2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2010 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 "magick/studio.h"
44 #include "magick/annotate.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/constitute.h"
51 #include "magick/composite-private.h"
52 #include "magick/draw.h"
53 #include "magick/exception.h"
54 #include "magick/exception-private.h"
55 #include "magick/gem.h"
56 #include "magick/image.h"
57 #include "magick/image-private.h"
58 #include "magick/list.h"
59 #include "magick/log.h"
60 #include "magick/magick.h"
61 #include "magick/memory_.h"
62 #include "magick/monitor.h"
63 #include "magick/monitor-private.h"
64 #include "magick/quantum-private.h"
65 #include "magick/pixel-private.h"
66 #include "magick/property.h"
67 #include "magick/resource_.h"
68 #include "magick/static.h"
69 #include "magick/string_.h"
70 #include "magick/module.h"
71 #include "magick/token.h"
72 #include "magick/utility.h"
73 #if defined(MAGICKCORE_XML_DELEGATE)
74 # if defined(__WINDOWS__)
75 # if defined(__MINGW32__)
78 # include <win32config.h>
81 # include <libxml/parser.h>
82 # include <libxml/xmlmemory.h>
83 # include <libxml/parserInternals.h>
84 # include <libxml/xmlerror.h>
87 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
88 #include "autotrace/autotrace.h"
91 #if defined(MAGICKCORE_RSVG_DELEGATE)
92 #include "librsvg/rsvg.h"
93 #if defined(MAGICKCORE_CAIRO_DELEGATE)
94 #include "librsvg/rsvg-cairo.h"
96 #include "librsvg/librsvg-features.h"
102 #define MVGPrintf (void) fprintf
105 Typedef declarations.
107 typedef struct _BoundingBox
116 typedef struct _ElementInfo
126 typedef struct _SVGInfo
180 #if defined(MAGICKCORE_XML_DELEGATE)
190 Forward declarations.
192 static MagickBooleanType
193 WriteSVGImage(const ImageInfo *,Image *);
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 % IsSVG()() returns MagickTrue if the image format type, identified by the
207 % magick string, is SVG.
209 % The format of the IsSVG method is:
211 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
213 % A description of each parameter follows:
215 % o magick: compare image format pattern against these bytes.
217 % o length: Specifies the length of the magick string.
220 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
224 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
229 #if defined(MAGICKCORE_XML_DELEGATE)
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 % R e a d S V G I m a g e %
239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
242 % allocates the memory necessary for the new Image structure and returns a
243 % pointer to the new image.
245 % The format of the ReadSVGImage method is:
247 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
249 % A description of each parameter follows:
251 % o image_info: the image info.
253 % o exception: return any errors or warnings in this structure.
257 static SVGInfo *AcquireSVGInfo(void)
262 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
263 if (svg_info == (SVGInfo *) NULL)
264 return((SVGInfo *) NULL);
265 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
266 svg_info->text=AcquireString("");
267 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
268 if (svg_info->scale == (double *) NULL)
269 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
270 GetAffineMatrix(&svg_info->affine);
271 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
275 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
277 if (svg_info->text != (char *) NULL)
278 svg_info->text=DestroyString(svg_info->text);
279 if (svg_info->scale != (double *) NULL)
280 svg_info->scale=(double *) (svg_info->scale);
281 if (svg_info->title != (char *) NULL)
282 svg_info->title=DestroyString(svg_info->title);
283 if (svg_info->comment != (char *) NULL)
284 svg_info->comment=DestroyString(svg_info->comment);
285 return((SVGInfo *) RelinquishMagickMemory(svg_info));
288 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
292 token[MaxTextExtent];
300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
301 assert(string != (const char *) NULL);
302 p=(const char *) string;
303 GetMagickToken(p,&p,token);
305 if (strchr(token,'%') != (char *) NULL)
313 if (svg_info->view_box.width == 0.0)
315 return(svg_info->view_box.width*value/100.0);
319 if (svg_info->view_box.height == 0.0)
321 return(svg_info->view_box.height*value/100.0);
323 alpha=value-svg_info->view_box.width;
324 beta=value-svg_info->view_box.height;
325 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
327 GetMagickToken(p,&p,token);
328 if (LocaleNCompare(token,"cm",2) == 0)
329 return(DefaultResolution*svg_info->scale[0]/2.54*value);
330 if (LocaleNCompare(token,"em",2) == 0)
331 return(svg_info->pointsize*value);
332 if (LocaleNCompare(token,"ex",2) == 0)
333 return(svg_info->pointsize*value/2.0);
334 if (LocaleNCompare(token,"in",2) == 0)
335 return(DefaultResolution*svg_info->scale[0]*value);
336 if (LocaleNCompare(token,"mm",2) == 0)
337 return(DefaultResolution*svg_info->scale[0]/25.4*value);
338 if (LocaleNCompare(token,"pc",2) == 0)
339 return(DefaultResolution*svg_info->scale[0]/6.0*value);
340 if (LocaleNCompare(token,"pt",2) == 0)
341 return(svg_info->scale[0]*value);
342 if (LocaleNCompare(token,"px",2) == 0)
347 static void StripStyleTokens(char *message)
356 assert(message != (char *) NULL);
357 if (*message == '\0')
359 length=strlen(message);
361 while (isspace((int) ((unsigned char) *p)) != 0)
364 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
366 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
368 StripString(message);
371 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
383 svg_info=(SVGInfo *) context;
385 if (style == (const char *) NULL)
386 return((char **) NULL);
387 text=AcquireString(style);
388 (void) SubstituteString(&text,":","\n");
389 (void) SubstituteString(&text,";","\n");
390 tokens=StringToList(text);
391 text=DestroyString(text);
392 for (i=0; tokens[i] != (char *) NULL; i++)
393 StripStyleTokens(tokens[i]);
398 static char **GetTransformTokens(void *context,const char *text,
414 svg_info=(SVGInfo *) context;
416 if (text == (const char *) NULL)
417 return((char **) NULL);
419 Determine the number of arguments.
421 for (p=text; *p != '\0'; p++)
426 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
427 if (tokens == (char **) NULL)
429 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
430 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
431 return((char **) NULL);
434 Convert string to an ASCII list.
438 for (q=p; *q != '\0'; q++)
440 if ((*q != '(') && (*q != ')') && (*q != '\0'))
442 tokens[i]=AcquireString(p);
443 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
444 StripString(tokens[i++]);
447 tokens[i]=AcquireString(p);
448 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
449 StripString(tokens[i++]);
450 tokens[i]=(char *) NULL;
454 #if defined(__cplusplus) || defined(c_plusplus)
458 static int SVGIsStandalone(void *context)
464 Is this document tagged standalone?
466 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
467 svg_info=(SVGInfo *) context;
468 return(svg_info->document->standalone == 1);
471 static int SVGHasInternalSubset(void *context)
477 Does this document has an internal subset?
479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
480 " SAX.SVGHasInternalSubset()");
481 svg_info=(SVGInfo *) context;
482 return(svg_info->document->intSubset != NULL);
485 static int SVGHasExternalSubset(void *context)
491 Does this document has an external subset?
493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
494 " SAX.SVGHasExternalSubset()");
495 svg_info=(SVGInfo *) context;
496 return(svg_info->document->extSubset != NULL);
499 static void SVGInternalSubset(void *context,const xmlChar *name,
500 const xmlChar *external_id,const xmlChar *system_id)
506 Does this document has an internal subset?
508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
509 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
510 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
511 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
512 svg_info=(SVGInfo *) context;
513 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
516 static xmlParserInputPtr SVGResolveEntity(void *context,
517 const xmlChar *public_id,const xmlChar *system_id)
526 Special entity resolver, better left to the parser, it has more
527 context than the application layer. The default behaviour is to
528 not resolve the entities, in that case the ENTITY_REF nodes are
529 built in the structure (and the parameter values).
531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
532 " SAX.resolveEntity(%s, %s)",
533 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
534 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
535 svg_info=(SVGInfo *) context;
536 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
537 public_id,svg_info->parser);
541 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
547 Get an entity by name.
549 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
551 svg_info=(SVGInfo *) context;
552 return(xmlGetDocEntity(svg_info->document,name));
555 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
561 Get a parameter entity by name.
563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
564 " SAX.getParameterEntity(%s)",name);
565 svg_info=(SVGInfo *) context;
566 return(xmlGetParameterEntity(svg_info->document,name));
569 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
570 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
576 An entity definition has been parsed.
578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
579 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
580 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
581 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
582 svg_info=(SVGInfo *) context;
583 if (svg_info->parser->inSubset == 1)
584 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
587 if (svg_info->parser->inSubset == 2)
588 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
592 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
593 const xmlChar *name,int type,int value,const xmlChar *default_value,
594 xmlEnumerationPtr tree)
607 An attribute definition has been parsed.
609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
610 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
612 svg_info=(SVGInfo *) context;
613 fullname=(xmlChar *) NULL;
614 prefix=(xmlChar *) NULL;
615 parser=svg_info->parser;
616 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
617 if (parser->inSubset == 1)
618 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
619 element,fullname,prefix,(xmlAttributeType) type,
620 (xmlAttributeDefault) value,default_value,tree);
622 if (parser->inSubset == 2)
623 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
624 element,fullname,prefix,(xmlAttributeType) type,
625 (xmlAttributeDefault) value,default_value,tree);
626 if (prefix != (xmlChar *) NULL)
628 if (fullname != (xmlChar *) NULL)
632 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
633 xmlElementContentPtr content)
642 An element definition has been parsed.
644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
645 " SAX.elementDecl(%s, %d, ...)",name,type);
646 svg_info=(SVGInfo *) context;
647 parser=svg_info->parser;
648 if (parser->inSubset == 1)
649 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
650 name,(xmlElementTypeVal) type,content);
652 if (parser->inSubset == 2)
653 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
654 name,(xmlElementTypeVal) type,content);
657 static void SVGNotationDeclaration(void *context,const xmlChar *name,
658 const xmlChar *public_id,const xmlChar *system_id)
667 What to do when a notation declaration has been parsed.
669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
670 " SAX.notationDecl(%s, %s, %s)",name,
671 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
672 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
673 svg_info=(SVGInfo *) context;
674 parser=svg_info->parser;
675 if (parser->inSubset == 1)
676 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
677 name,public_id,system_id);
679 if (parser->inSubset == 2)
680 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
681 name,public_id,system_id);
684 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
685 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
691 What to do when an unparsed entity declaration is parsed.
693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
694 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
695 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
696 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
697 svg_info=(SVGInfo *) context;
698 (void) xmlAddDocEntity(svg_info->document,name,
699 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
703 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
709 Receive the document locator at startup, actually xmlDefaultSAXLocator.
712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
713 " SAX.setDocumentLocator()");
714 svg_info=(SVGInfo *) context;
717 static void SVGStartDocument(void *context)
726 Called when the document start being processed.
728 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
729 svg_info=(SVGInfo *) context;
730 GetExceptionInfo(svg_info->exception);
731 parser=svg_info->parser;
732 svg_info->document=xmlNewDoc(parser->version);
733 if (svg_info->document == (xmlDocPtr) NULL)
735 if (parser->encoding == NULL)
736 svg_info->document->encoding=(const xmlChar *) NULL;
738 svg_info->document->encoding=xmlStrdup(parser->encoding);
739 svg_info->document->standalone=parser->standalone;
742 static void SVGEndDocument(void *context)
748 Called when the document end has been detected.
750 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
751 svg_info=(SVGInfo *) context;
752 if (svg_info->offset != (char *) NULL)
753 svg_info->offset=DestroyString(svg_info->offset);
754 if (svg_info->stop_color != (char *) NULL)
755 svg_info->stop_color=DestroyString(svg_info->stop_color);
756 if (svg_info->scale != (double *) NULL)
757 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
758 if (svg_info->text != (char *) NULL)
759 svg_info->text=DestroyString(svg_info->text);
760 if (svg_info->vertices != (char *) NULL)
761 svg_info->vertices=DestroyString(svg_info->vertices);
762 if (svg_info->url != (char *) NULL)
763 svg_info->url=DestroyString(svg_info->url);
764 #if defined(MAGICKCORE_XML_DELEGATE)
765 if (svg_info->document != (xmlDocPtr) NULL)
767 xmlFreeDoc(svg_info->document);
768 svg_info->document=(xmlDocPtr) NULL;
773 static void SVGStartElement(void *context,const xmlChar *name,
774 const xmlChar **attributes)
779 token[MaxTextExtent],
799 Called when an opening tag has been processed.
801 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
803 svg_info=(SVGInfo *) context;
805 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
806 svg_info->n+1UL,sizeof(*svg_info->scale));
807 if (svg_info->scale == (double *) NULL)
809 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
810 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
813 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
814 color=AcquireString("none");
815 units=AcquireString("userSpaceOnUse");
816 value=(const char *) NULL;
817 if (attributes != (const xmlChar **) NULL)
818 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
820 keyword=(const char *) attributes[i];
821 value=(const char *) attributes[i+1];
827 if (LocaleCompare(keyword,"cx") == 0)
829 svg_info->element.cx=
830 GetUserSpaceCoordinateValue(svg_info,1,value);
833 if (LocaleCompare(keyword,"cy") == 0)
835 svg_info->element.cy=
836 GetUserSpaceCoordinateValue(svg_info,-1,value);
844 if (LocaleCompare(keyword,"fx") == 0)
846 svg_info->element.major=
847 GetUserSpaceCoordinateValue(svg_info,1,value);
850 if (LocaleCompare(keyword,"fy") == 0)
852 svg_info->element.minor=
853 GetUserSpaceCoordinateValue(svg_info,-1,value);
861 if (LocaleCompare(keyword,"height") == 0)
863 svg_info->bounds.height=
864 GetUserSpaceCoordinateValue(svg_info,-1,value);
872 if (LocaleCompare(keyword,"id") == 0)
874 (void) CopyMagickString(id,value,MaxTextExtent);
882 if (LocaleCompare(keyword,"r") == 0)
884 svg_info->element.angle=
885 GetUserSpaceCoordinateValue(svg_info,0,value);
893 if (LocaleCompare(keyword,"width") == 0)
895 svg_info->bounds.width=
896 GetUserSpaceCoordinateValue(svg_info,1,value);
904 if (LocaleCompare(keyword,"x") == 0)
906 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
910 if (LocaleCompare(keyword,"x1") == 0)
912 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
916 if (LocaleCompare(keyword,"x2") == 0)
918 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
927 if (LocaleCompare(keyword,"y") == 0)
929 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
933 if (LocaleCompare(keyword,"y1") == 0)
935 svg_info->segment.y1=
936 GetUserSpaceCoordinateValue(svg_info,-1,value);
939 if (LocaleCompare(keyword,"y2") == 0)
941 svg_info->segment.y2=
942 GetUserSpaceCoordinateValue(svg_info,-1,value);
956 if (LocaleCompare((const char *) name,"circle") == 0)
958 MVGPrintf(svg_info->file,"push graphic-context\n");
961 if (LocaleCompare((const char *) name,"clipPath") == 0)
963 MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
971 if (LocaleCompare((const char *) name,"defs") == 0)
973 MVGPrintf(svg_info->file,"push defs\n");
981 if (LocaleCompare((const char *) name,"ellipse") == 0)
983 MVGPrintf(svg_info->file,"push graphic-context\n");
991 if (LocaleCompare((const char *) name,"g") == 0)
993 MVGPrintf(svg_info->file,"push graphic-context\n");
1001 if (LocaleCompare((const char *) name,"image") == 0)
1003 MVGPrintf(svg_info->file,"push graphic-context\n");
1011 if (LocaleCompare((const char *) name,"line") == 0)
1013 MVGPrintf(svg_info->file,"push graphic-context\n");
1016 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1018 MVGPrintf(svg_info->file,"push gradient '%s' linear %g,%g %g,%g\n",id,
1019 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1020 svg_info->segment.y2);
1028 if (LocaleCompare((const char *) name,"path") == 0)
1030 MVGPrintf(svg_info->file,"push graphic-context\n");
1033 if (LocaleCompare((const char *) name,"pattern") == 0)
1035 MVGPrintf(svg_info->file,"push pattern '%s' %g,%g %g,%g\n",id,
1036 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1037 svg_info->bounds.height);
1040 if (LocaleCompare((const char *) name,"polygon") == 0)
1042 MVGPrintf(svg_info->file,"push graphic-context\n");
1045 if (LocaleCompare((const char *) name,"polyline") == 0)
1047 MVGPrintf(svg_info->file,"push graphic-context\n");
1055 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1057 MVGPrintf(svg_info->file,"push gradient '%s' radial %g,%g %g,%g %g\n",
1058 id,svg_info->element.cx,svg_info->element.cy,
1059 svg_info->element.major,svg_info->element.minor,
1060 svg_info->element.angle);
1063 if (LocaleCompare((const char *) name,"rect") == 0)
1065 MVGPrintf(svg_info->file,"push graphic-context\n");
1073 if (LocaleCompare((const char *) name,"svg") == 0)
1075 MVGPrintf(svg_info->file,"push graphic-context\n");
1083 if (LocaleCompare((const char *) name,"text") == 0)
1085 MVGPrintf(svg_info->file,"push graphic-context\n");
1088 if (LocaleCompare((const char *) name,"tspan") == 0)
1090 if (*svg_info->text != '\0')
1101 text=EscapeString(svg_info->text,'\'');
1102 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x-
1103 svg_info->center.x,svg_info->bounds.y-svg_info->center.y,text);
1104 text=DestroyString(text);
1105 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1106 draw_info->pointsize=svg_info->pointsize;
1107 draw_info->text=AcquireString(svg_info->text);
1108 (void) ConcatenateString(&draw_info->text," ");
1109 GetTypeMetrics(svg_info->image,draw_info,&metrics);
1110 svg_info->bounds.x+=metrics.width;
1111 draw_info=DestroyDrawInfo(draw_info);
1112 *svg_info->text='\0';
1114 MVGPrintf(svg_info->file,"push graphic-context\n");
1122 if (attributes != (const xmlChar **) NULL)
1123 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1125 keyword=(const char *) attributes[i];
1126 value=(const char *) attributes[i+1];
1127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1128 " %s = %s",keyword,value);
1134 if (LocaleCompare(keyword,"angle") == 0)
1136 MVGPrintf(svg_info->file,"angle %g\n",
1137 GetUserSpaceCoordinateValue(svg_info,0,value));
1145 if (LocaleCompare(keyword,"clip-path") == 0)
1147 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1150 if (LocaleCompare(keyword,"clip-rule") == 0)
1152 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1155 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1157 (void) CloneString(&units,value);
1158 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1161 if (LocaleCompare(keyword,"color") == 0)
1163 (void) CloneString(&color,value);
1166 if (LocaleCompare(keyword,"cx") == 0)
1168 svg_info->element.cx=
1169 GetUserSpaceCoordinateValue(svg_info,1,value);
1172 if (LocaleCompare(keyword,"cy") == 0)
1174 svg_info->element.cy=
1175 GetUserSpaceCoordinateValue(svg_info,-1,value);
1183 if (LocaleCompare(keyword,"d") == 0)
1185 (void) CloneString(&svg_info->vertices,value);
1188 if (LocaleCompare(keyword,"dx") == 0)
1190 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1193 if (LocaleCompare(keyword,"dy") == 0)
1195 svg_info->bounds.y+=
1196 GetUserSpaceCoordinateValue(svg_info,-1,value);
1204 if (LocaleCompare(keyword,"fill") == 0)
1206 if (LocaleCompare(value,"currentColor") == 0)
1208 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1211 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1214 if (LocaleCompare(keyword,"fillcolor") == 0)
1216 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1219 if (LocaleCompare(keyword,"fill-rule") == 0)
1221 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1224 if (LocaleCompare(keyword,"fill-opacity") == 0)
1226 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1229 if (LocaleCompare(keyword,"font-family") == 0)
1231 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1234 if (LocaleCompare(keyword,"font-stretch") == 0)
1236 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1239 if (LocaleCompare(keyword,"font-style") == 0)
1241 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1244 if (LocaleCompare(keyword,"font-size") == 0)
1246 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1247 MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1250 if (LocaleCompare(keyword,"font-weight") == 0)
1252 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1260 if (LocaleCompare(keyword,"gradientTransform") == 0)
1267 GetAffineMatrix(&transform);
1268 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1269 tokens=GetTransformTokens(context,value,&number_tokens);
1270 for (j=0; j < (number_tokens-1); j+=2)
1272 keyword=(char *) tokens[j];
1273 if (keyword == (char *) NULL)
1275 value=(char *) tokens[j+1];
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277 " %s: %s",keyword,value);
1279 GetAffineMatrix(&affine);
1285 if (LocaleCompare(keyword,"matrix") == 0)
1287 p=(const char *) value;
1288 GetMagickToken(p,&p,token);
1289 affine.sx=atof(value);
1290 GetMagickToken(p,&p,token);
1292 GetMagickToken(p,&p,token);
1293 affine.rx=atof(token);
1294 GetMagickToken(p,&p,token);
1296 GetMagickToken(p,&p,token);
1297 affine.ry=atof(token);
1298 GetMagickToken(p,&p,token);
1300 GetMagickToken(p,&p,token);
1301 affine.sy=atof(token);
1302 GetMagickToken(p,&p,token);
1304 GetMagickToken(p,&p,token);
1305 affine.tx=atof(token);
1306 GetMagickToken(p,&p,token);
1308 GetMagickToken(p,&p,token);
1309 affine.ty=atof(token);
1317 if (LocaleCompare(keyword,"rotate") == 0)
1322 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1323 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1324 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1325 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1326 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1334 if (LocaleCompare(keyword,"scale") == 0)
1336 for (p=(const char *) value; *p != '\0'; p++)
1337 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1340 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1341 affine.sy=affine.sx;
1344 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1345 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1348 if (LocaleCompare(keyword,"skewX") == 0)
1350 affine.sx=svg_info->affine.sx;
1351 affine.ry=tan(DegreesToRadians(fmod(
1352 GetUserSpaceCoordinateValue(svg_info,1,value),
1354 affine.sy=svg_info->affine.sy;
1357 if (LocaleCompare(keyword,"skewY") == 0)
1359 affine.sx=svg_info->affine.sx;
1360 affine.rx=tan(DegreesToRadians(fmod(
1361 GetUserSpaceCoordinateValue(svg_info,-1,value),
1363 affine.sy=svg_info->affine.sy;
1371 if (LocaleCompare(keyword,"translate") == 0)
1373 for (p=(const char *) value; *p != '\0'; p++)
1374 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1377 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1378 affine.ty=affine.tx;
1381 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1389 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1390 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1391 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1392 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1393 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1395 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1398 MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1399 transform.sx,transform.rx,transform.ry,transform.sy,
1400 transform.tx,transform.ty);
1401 for (j=0; tokens[j] != (char *) NULL; j++)
1402 tokens[j]=DestroyString(tokens[j]);
1403 tokens=(char **) RelinquishMagickMemory(tokens);
1406 if (LocaleCompare(keyword,"gradientUnits") == 0)
1408 (void) CloneString(&units,value);
1409 MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1417 if (LocaleCompare(keyword,"height") == 0)
1419 svg_info->bounds.height=
1420 GetUserSpaceCoordinateValue(svg_info,-1,value);
1423 if (LocaleCompare(keyword,"href") == 0)
1425 (void) CloneString(&svg_info->url,value);
1433 if (LocaleCompare(keyword,"major") == 0)
1435 svg_info->element.major=
1436 GetUserSpaceCoordinateValue(svg_info,1,value);
1439 if (LocaleCompare(keyword,"minor") == 0)
1441 svg_info->element.minor=
1442 GetUserSpaceCoordinateValue(svg_info,-1,value);
1450 if (LocaleCompare(keyword,"offset") == 0)
1452 (void) CloneString(&svg_info->offset,value);
1455 if (LocaleCompare(keyword,"opacity") == 0)
1457 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1465 if (LocaleCompare(keyword,"path") == 0)
1467 (void) CloneString(&svg_info->url,value);
1470 if (LocaleCompare(keyword,"points") == 0)
1472 (void) CloneString(&svg_info->vertices,value);
1480 if (LocaleCompare(keyword,"r") == 0)
1482 svg_info->element.major=
1483 GetUserSpaceCoordinateValue(svg_info,1,value);
1484 svg_info->element.minor=
1485 GetUserSpaceCoordinateValue(svg_info,-1,value);
1488 if (LocaleCompare(keyword,"rotate") == 0)
1493 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1494 MVGPrintf(svg_info->file,"translate %g,%g\n",svg_info->bounds.x,
1495 svg_info->bounds.y);
1496 svg_info->bounds.x=0;
1497 svg_info->bounds.y=0;
1498 MVGPrintf(svg_info->file,"rotate %g\n",angle);
1501 if (LocaleCompare(keyword,"rx") == 0)
1503 if (LocaleCompare((const char *) name,"ellipse") == 0)
1504 svg_info->element.major=
1505 GetUserSpaceCoordinateValue(svg_info,1,value);
1508 GetUserSpaceCoordinateValue(svg_info,1,value);
1511 if (LocaleCompare(keyword,"ry") == 0)
1513 if (LocaleCompare((const char *) name,"ellipse") == 0)
1514 svg_info->element.minor=
1515 GetUserSpaceCoordinateValue(svg_info,-1,value);
1518 GetUserSpaceCoordinateValue(svg_info,-1,value);
1526 if (LocaleCompare(keyword,"stop-color") == 0)
1528 (void) CloneString(&svg_info->stop_color,value);
1531 if (LocaleCompare(keyword,"stroke") == 0)
1533 if (LocaleCompare(value,"currentColor") == 0)
1535 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1538 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1541 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1543 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1544 LocaleCompare(value,"true") == 0);
1547 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1549 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1552 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1554 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1557 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1559 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1562 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1564 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1567 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1569 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1572 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1574 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1577 if (LocaleCompare(keyword,"stroke-width") == 0)
1579 MVGPrintf(svg_info->file,"stroke-width %g\n",
1580 GetUserSpaceCoordinateValue(svg_info,1,value));
1583 if (LocaleCompare(keyword,"style") == 0)
1585 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1586 tokens=GetStyleTokens(context,value,&number_tokens);
1587 for (j=0; j < (number_tokens-1); j+=2)
1589 keyword=(char *) tokens[j];
1590 value=(char *) tokens[j+1];
1591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1592 " %s: %s",keyword,value);
1598 if (LocaleCompare(keyword,"clip-path") == 0)
1600 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1603 if (LocaleCompare(keyword,"clip-rule") == 0)
1605 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1608 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1610 (void) CloneString(&units,value);
1611 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1614 if (LocaleCompare(keyword,"color") == 0)
1616 (void) CloneString(&color,value);
1624 if (LocaleCompare(keyword,"fill") == 0)
1626 if (LocaleCompare(value,"currentColor") == 0)
1628 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1631 if (LocaleCompare(value,"#00000000") == 0)
1632 MVGPrintf(svg_info->file,"fill '#000000'\n");
1634 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1637 if (LocaleCompare(keyword,"fillcolor") == 0)
1639 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1642 if (LocaleCompare(keyword,"fill-rule") == 0)
1644 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1647 if (LocaleCompare(keyword,"fill-opacity") == 0)
1649 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1652 if (LocaleCompare(keyword,"font-family") == 0)
1654 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1657 if (LocaleCompare(keyword,"font-stretch") == 0)
1659 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1662 if (LocaleCompare(keyword,"font-style") == 0)
1664 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1667 if (LocaleCompare(keyword,"font-size") == 0)
1669 svg_info->pointsize=GetUserSpaceCoordinateValue(
1671 MVGPrintf(svg_info->file,"font-size %g\n",
1672 svg_info->pointsize);
1675 if (LocaleCompare(keyword,"font-weight") == 0)
1677 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1685 if (LocaleCompare(keyword,"offset") == 0)
1687 MVGPrintf(svg_info->file,"offset %g\n",
1688 GetUserSpaceCoordinateValue(svg_info,1,value));
1691 if (LocaleCompare(keyword,"opacity") == 0)
1693 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1701 if (LocaleCompare(keyword,"stop-color") == 0)
1703 (void) CloneString(&svg_info->stop_color,value);
1706 if (LocaleCompare(keyword,"stroke") == 0)
1708 if (LocaleCompare(value,"currentColor") == 0)
1710 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1713 if (LocaleCompare(value,"#00000000") == 0)
1714 MVGPrintf(svg_info->file,"fill '#000000'\n");
1716 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1719 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1721 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1722 LocaleCompare(value,"true") == 0);
1725 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1727 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1730 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1732 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1736 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1738 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1741 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1743 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1747 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1749 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1753 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1755 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1758 if (LocaleCompare(keyword,"stroke-width") == 0)
1760 MVGPrintf(svg_info->file,"stroke-width %g\n",
1761 GetUserSpaceCoordinateValue(svg_info,1,value));
1769 if (LocaleCompare(keyword,"text-align") == 0)
1771 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1774 if (LocaleCompare(keyword,"text-anchor") == 0)
1776 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1779 if (LocaleCompare(keyword,"text-decoration") == 0)
1781 if (LocaleCompare(value,"underline") == 0)
1782 MVGPrintf(svg_info->file,"decorate underline\n");
1783 if (LocaleCompare(value,"line-through") == 0)
1784 MVGPrintf(svg_info->file,"decorate line-through\n");
1785 if (LocaleCompare(value,"overline") == 0)
1786 MVGPrintf(svg_info->file,"decorate overline\n");
1789 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1791 MVGPrintf(svg_info->file,"text-antialias %d\n",
1792 LocaleCompare(value,"true") == 0);
1801 for (j=0; tokens[j] != (char *) NULL; j++)
1802 tokens[j]=DestroyString(tokens[j]);
1803 tokens=(char **) RelinquishMagickMemory(tokens);
1811 if (LocaleCompare(keyword,"text-align") == 0)
1813 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1816 if (LocaleCompare(keyword,"text-anchor") == 0)
1818 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1821 if (LocaleCompare(keyword,"text-decoration") == 0)
1823 if (LocaleCompare(value,"underline") == 0)
1824 MVGPrintf(svg_info->file,"decorate underline\n");
1825 if (LocaleCompare(value,"line-through") == 0)
1826 MVGPrintf(svg_info->file,"decorate line-through\n");
1827 if (LocaleCompare(value,"overline") == 0)
1828 MVGPrintf(svg_info->file,"decorate overline\n");
1831 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1833 MVGPrintf(svg_info->file,"text-antialias %d\n",
1834 LocaleCompare(value,"true") == 0);
1837 if (LocaleCompare(keyword,"transform") == 0)
1844 GetAffineMatrix(&transform);
1845 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1846 tokens=GetTransformTokens(context,value,&number_tokens);
1847 for (j=0; j < (number_tokens-1); j+=2)
1849 keyword=(char *) tokens[j];
1850 value=(char *) tokens[j+1];
1851 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1852 " %s: %s",keyword,value);
1854 GetAffineMatrix(&affine);
1860 if (LocaleCompare(keyword,"matrix") == 0)
1862 p=(const char *) value;
1863 GetMagickToken(p,&p,token);
1864 affine.sx=atof(value);
1865 GetMagickToken(p,&p,token);
1867 GetMagickToken(p,&p,token);
1868 affine.rx=atof(token);
1869 GetMagickToken(p,&p,token);
1871 GetMagickToken(p,&p,token);
1872 affine.ry=atof(token);
1873 GetMagickToken(p,&p,token);
1875 GetMagickToken(p,&p,token);
1876 affine.sy=atof(token);
1877 GetMagickToken(p,&p,token);
1879 GetMagickToken(p,&p,token);
1880 affine.tx=atof(token);
1881 GetMagickToken(p,&p,token);
1883 GetMagickToken(p,&p,token);
1884 affine.ty=atof(token);
1892 if (LocaleCompare(keyword,"rotate") == 0)
1899 p=(const char *) value;
1900 GetMagickToken(p,&p,token);
1902 GetMagickToken(p,&p,token);
1904 GetMagickToken(p,&p,token);
1906 GetMagickToken(p,&p,token);
1908 GetMagickToken(p,&p,token);
1910 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1911 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1912 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1913 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1916 svg_info->center.x=x;
1917 svg_info->center.y=y;
1925 if (LocaleCompare(keyword,"scale") == 0)
1927 for (p=(const char *) value; *p != '\0'; p++)
1928 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1931 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1932 affine.sy=affine.sx;
1934 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1936 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1939 if (LocaleCompare(keyword,"skewX") == 0)
1941 affine.sx=svg_info->affine.sx;
1942 affine.ry=tan(DegreesToRadians(fmod(
1943 GetUserSpaceCoordinateValue(svg_info,1,value),
1945 affine.sy=svg_info->affine.sy;
1948 if (LocaleCompare(keyword,"skewY") == 0)
1950 affine.sx=svg_info->affine.sx;
1951 affine.rx=tan(DegreesToRadians(fmod(
1952 GetUserSpaceCoordinateValue(svg_info,-1,value),
1954 affine.sy=svg_info->affine.sy;
1962 if (LocaleCompare(keyword,"translate") == 0)
1964 for (p=(const char *) value; *p != '\0'; p++)
1965 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1968 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1969 affine.ty=affine.tx;
1971 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
1980 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1981 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1982 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1983 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1984 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1986 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1989 MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1990 transform.sx,transform.rx,transform.ry,transform.sy,
1991 transform.tx,transform.ty);
1992 for (j=0; tokens[j] != (char *) NULL; j++)
1993 tokens[j]=DestroyString(tokens[j]);
1994 tokens=(char **) RelinquishMagickMemory(tokens);
2002 if (LocaleCompare(keyword,"verts") == 0)
2004 (void) CloneString(&svg_info->vertices,value);
2007 if (LocaleCompare(keyword,"viewBox") == 0)
2009 p=(const char *) value;
2010 GetMagickToken(p,&p,token);
2011 svg_info->view_box.x=atof(token);
2012 GetMagickToken(p,&p,token);
2014 GetMagickToken(p,&p,token);
2015 svg_info->view_box.y=atof(token);
2016 GetMagickToken(p,&p,token);
2018 GetMagickToken(p,&p,token);
2019 svg_info->view_box.width=atof(token);
2020 if (svg_info->bounds.width == 0)
2021 svg_info->bounds.width=svg_info->view_box.width;
2022 GetMagickToken(p,&p,token);
2024 GetMagickToken(p,&p,token);
2025 svg_info->view_box.height=atof(token);
2026 if (svg_info->bounds.height == 0)
2027 svg_info->bounds.height=svg_info->view_box.height;
2035 if (LocaleCompare(keyword,"width") == 0)
2037 svg_info->bounds.width=
2038 GetUserSpaceCoordinateValue(svg_info,1,value);
2046 if (LocaleCompare(keyword,"x") == 0)
2048 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2051 if (LocaleCompare(keyword,"xlink:href") == 0)
2053 (void) CloneString(&svg_info->url,value);
2056 if (LocaleCompare(keyword,"x1") == 0)
2058 svg_info->segment.x1=
2059 GetUserSpaceCoordinateValue(svg_info,1,value);
2062 if (LocaleCompare(keyword,"x2") == 0)
2064 svg_info->segment.x2=
2065 GetUserSpaceCoordinateValue(svg_info,1,value);
2073 if (LocaleCompare(keyword,"y") == 0)
2075 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2078 if (LocaleCompare(keyword,"y1") == 0)
2080 svg_info->segment.y1=
2081 GetUserSpaceCoordinateValue(svg_info,-1,value);
2084 if (LocaleCompare(keyword,"y2") == 0)
2086 svg_info->segment.y2=
2087 GetUserSpaceCoordinateValue(svg_info,-1,value);
2096 if (LocaleCompare((const char *) name,"svg") == 0)
2098 if (svg_info->document->encoding != (const xmlChar *) NULL)
2099 MVGPrintf(svg_info->file,"encoding \"%s\"\n",
2100 (const char *) svg_info->document->encoding);
2101 if (attributes != (const xmlChar **) NULL)
2107 if ((svg_info->view_box.width == 0.0) ||
2108 (svg_info->view_box.height == 0.0))
2109 svg_info->view_box=svg_info->bounds;
2110 svg_info->width=(unsigned long) (svg_info->bounds.width+0.5);
2111 svg_info->height=(unsigned long) (svg_info->bounds.height+0.5);
2112 MVGPrintf(svg_info->file,"viewbox 0 0 %lu %lu\n",svg_info->width,
2114 sx=(double) svg_info->width/svg_info->view_box.width;
2115 sy=(double) svg_info->height/svg_info->view_box.height;
2116 MVGPrintf(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",sx,sy);
2119 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2120 units=DestroyString(units);
2121 if (color != (char *) NULL)
2122 color=DestroyString(color);
2125 static void SVGEndElement(void *context,const xmlChar *name)
2131 Called when the end of an element has been detected.
2133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2134 " SAX.endElement(%s)",name);
2135 svg_info=(SVGInfo *) context;
2141 if (LocaleCompare((const char *) name,"circle") == 0)
2143 MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",svg_info->element.cx,
2144 svg_info->element.cy,svg_info->element.cx,svg_info->element.cy+
2145 svg_info->element.minor);
2146 MVGPrintf(svg_info->file,"pop graphic-context\n");
2149 if (LocaleCompare((const char *) name,"clipPath") == 0)
2151 MVGPrintf(svg_info->file,"pop clip-path\n");
2159 if (LocaleCompare((const char *) name,"defs") == 0)
2161 MVGPrintf(svg_info->file,"pop defs\n");
2164 if (LocaleCompare((const char *) name,"desc") == 0)
2169 if (*svg_info->text == '\0')
2171 (void) fputc('#',svg_info->file);
2172 for (p=svg_info->text; *p != '\0'; p++)
2174 (void) fputc(*p,svg_info->file);
2176 (void) fputc('#',svg_info->file);
2178 (void) fputc('\n',svg_info->file);
2179 *svg_info->text='\0';
2187 if (LocaleCompare((const char *) name,"ellipse") == 0)
2192 angle=svg_info->element.angle;
2193 MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2194 svg_info->element.cx,svg_info->element.cy,
2195 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2196 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2197 MVGPrintf(svg_info->file,"pop graphic-context\n");
2205 if (LocaleCompare((const char *) name,"g") == 0)
2207 MVGPrintf(svg_info->file,"pop graphic-context\n");
2215 if (LocaleCompare((const char *) name,"image") == 0)
2217 MVGPrintf(svg_info->file,"image Over %g,%g %g,%g '%s'\n",
2218 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2219 svg_info->bounds.height,svg_info->url);
2220 MVGPrintf(svg_info->file,"pop graphic-context\n");
2228 if (LocaleCompare((const char *) name,"line") == 0)
2230 MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",svg_info->segment.x1,
2231 svg_info->segment.y1,svg_info->segment.x2,svg_info->segment.y2);
2232 MVGPrintf(svg_info->file,"pop graphic-context\n");
2235 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2237 MVGPrintf(svg_info->file,"pop gradient\n");
2245 if (LocaleCompare((const char *) name,"pattern") == 0)
2247 MVGPrintf(svg_info->file,"pop pattern\n");
2250 if (LocaleCompare((const char *) name,"path") == 0)
2252 MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2253 MVGPrintf(svg_info->file,"pop graphic-context\n");
2256 if (LocaleCompare((const char *) name,"polygon") == 0)
2258 MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2259 MVGPrintf(svg_info->file,"pop graphic-context\n");
2262 if (LocaleCompare((const char *) name,"polyline") == 0)
2264 MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2265 MVGPrintf(svg_info->file,"pop graphic-context\n");
2273 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2275 MVGPrintf(svg_info->file,"pop gradient\n");
2278 if (LocaleCompare((const char *) name,"rect") == 0)
2280 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2282 MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2283 svg_info->bounds.x,svg_info->bounds.y,
2284 svg_info->bounds.x+svg_info->bounds.width,
2285 svg_info->bounds.y+svg_info->bounds.height);
2286 MVGPrintf(svg_info->file,"pop graphic-context\n");
2289 if (svg_info->radius.x == 0.0)
2290 svg_info->radius.x=svg_info->radius.y;
2291 if (svg_info->radius.y == 0.0)
2292 svg_info->radius.y=svg_info->radius.x;
2293 MVGPrintf(svg_info->file,"roundRectangle %g,%g %g,%g %g,%g\n",
2294 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2295 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2296 svg_info->radius.x,svg_info->radius.y);
2297 svg_info->radius.x=0.0;
2298 svg_info->radius.y=0.0;
2299 MVGPrintf(svg_info->file,"pop graphic-context\n");
2307 if (LocaleCompare((const char *) name,"stop") == 0)
2309 MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2313 if (LocaleCompare((const char *) name,"svg") == 0)
2315 MVGPrintf(svg_info->file,"pop graphic-context\n");
2323 if (LocaleCompare((const char *) name,"text") == 0)
2325 if (*svg_info->text != '\0')
2330 text=EscapeString(svg_info->text,'\'');
2332 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x-
2333 svg_info->center.x,svg_info->bounds.y-svg_info->center.y,text);
2334 text=DestroyString(text);
2335 *svg_info->text='\0';
2337 MVGPrintf(svg_info->file,"pop graphic-context\n");
2340 if (LocaleCompare((const char *) name,"tspan") == 0)
2342 if (*svg_info->text != '\0')
2353 text=EscapeString(svg_info->text,'\'');
2355 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x,
2356 svg_info->bounds.y,text);
2357 text=DestroyString(text);
2358 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2359 draw_info->pointsize=svg_info->pointsize;
2360 draw_info->text=AcquireString(svg_info->text);
2361 (void) ConcatenateString(&draw_info->text," ");
2362 GetTypeMetrics(svg_info->image,draw_info,&metrics);
2363 svg_info->bounds.x+=metrics.width;
2364 draw_info=DestroyDrawInfo(draw_info);
2365 *svg_info->text='\0';
2367 MVGPrintf(svg_info->file,"pop graphic-context\n");
2370 if (LocaleCompare((const char *) name,"title") == 0)
2372 if (*svg_info->text == '\0')
2374 (void) CloneString(&svg_info->title,svg_info->text);
2375 *svg_info->text='\0';
2383 *svg_info->text='\0';
2384 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2385 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2389 static void SVGCharacters(void *context,const xmlChar *c,int length)
2401 Receiving some characters from the parser.
2403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2404 " SAX.characters(%s,%lu)",c,(unsigned long) length);
2405 svg_info=(SVGInfo *) context;
2406 if (svg_info->text != (char *) NULL)
2407 svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
2408 strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
2411 svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2412 sizeof(*svg_info->text));
2413 if (svg_info->text != (char *) NULL)
2414 *svg_info->text='\0';
2416 if (svg_info->text == (char *) NULL)
2418 p=svg_info->text+strlen(svg_info->text);
2419 for (i=0; i < (long) length; i++)
2424 static void SVGReference(void *context,const xmlChar *name)
2433 Called when an entity reference is detected.
2435 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2437 svg_info=(SVGInfo *) context;
2438 parser=svg_info->parser;
2439 if (parser == (xmlParserCtxtPtr) NULL)
2441 if (parser->node == (xmlNodePtr) NULL)
2444 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2446 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2449 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2455 Receiving some ignorable whitespaces from the parser.
2457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2458 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2459 svg_info=(SVGInfo *) context;
2462 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2463 const xmlChar *data)
2469 A processing instruction has been parsed.
2471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2472 " SAX.processingInstruction(%s, %s)",target,data);
2473 svg_info=(SVGInfo *) context;
2476 static void SVGComment(void *context,const xmlChar *value)
2482 A comment has been parsed.
2484 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2486 svg_info=(SVGInfo *) context;
2487 if (svg_info->comment != (char *) NULL)
2488 (void) ConcatenateString(&svg_info->comment,"\n");
2489 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2492 static void SVGWarning(void *context,const char *format,...)
2496 reason[MaxTextExtent];
2505 Display and format a warning messages, gives file, line, position and
2508 va_start(operands,format);
2509 svg_info=(SVGInfo *) context;
2510 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2512 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2513 (void) vsprintf(reason,format,operands);
2515 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2517 message=GetExceptionMessage(errno);
2518 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2519 DelegateWarning,reason,"`%s`",message);
2520 message=DestroyString(message);
2524 static void SVGError(void *context,const char *format,...)
2528 reason[MaxTextExtent];
2537 Display and format a error formats, gives file, line, position and
2540 va_start(operands,format);
2541 svg_info=(SVGInfo *) context;
2542 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2543 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2544 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2545 (void) vsprintf(reason,format,operands);
2547 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2549 message=GetExceptionMessage(errno);
2550 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2551 reason,"`%s`",message);
2552 message=DestroyString(message);
2556 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2568 Called when a pcdata block has been parsed.
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2572 svg_info=(SVGInfo *) context;
2573 parser=svg_info->parser;
2574 child=xmlGetLastChild(parser->node);
2575 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2577 xmlTextConcat(child,value,length);
2580 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2583 static void SVGExternalSubset(void *context,const xmlChar *name,
2584 const xmlChar *external_id,const xmlChar *system_id)
2599 Does this document has an external subset?
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2602 " SAX.externalSubset(%s, %s, %s)",name,
2603 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2604 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2605 svg_info=(SVGInfo *) context;
2606 parser=svg_info->parser;
2607 if (((external_id == NULL) && (system_id == NULL)) ||
2608 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2609 (svg_info->document == 0)))
2611 input=SVGResolveEntity(context,external_id,system_id);
2614 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2615 parser_context=(*parser);
2616 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2617 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2619 parser->errNo=XML_ERR_NO_MEMORY;
2620 parser->input=parser_context.input;
2621 parser->inputNr=parser_context.inputNr;
2622 parser->inputMax=parser_context.inputMax;
2623 parser->inputTab=parser_context.inputTab;
2629 xmlPushInput(parser,input);
2630 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2631 if (input->filename == (char *) NULL)
2632 input->filename=(char *) xmlStrdup(system_id);
2635 input->base=parser->input->cur;
2636 input->cur=parser->input->cur;
2638 xmlParseExternalSubset(parser,external_id,system_id);
2639 while (parser->inputNr > 1)
2640 (void) xmlPopInput(parser);
2641 xmlFreeInputStream(parser->input);
2642 xmlFree(parser->inputTab);
2643 parser->input=parser_context.input;
2644 parser->inputNr=parser_context.inputNr;
2645 parser->inputMax=parser_context.inputMax;
2646 parser->inputTab=parser_context.inputTab;
2649 #if defined(MAGICKCORE_RSVG_DELEGATE)
2650 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2651 static void SVGSetImageSize(int *width,int *height,gpointer context)
2656 image=(Image *) context;
2657 *width=(int) (*width*image->x_resolution/72.0);
2658 *height=(int) (*height*image->y_resolution/72.0);
2663 #if defined(__cplusplus) || defined(c_plusplus)
2667 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2670 filename[MaxTextExtent];
2689 message[MaxTextExtent];
2700 assert(image_info != (const ImageInfo *) NULL);
2701 assert(image_info->signature == MagickSignature);
2702 assert(exception != (ExceptionInfo *) NULL);
2703 if (image_info->debug != MagickFalse)
2704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2705 image_info->filename);
2706 assert(exception->signature == MagickSignature);
2707 image=AcquireImage(image_info);
2708 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2709 if (status == MagickFalse)
2711 image=DestroyImageList(image);
2712 return((Image *) NULL);
2714 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2716 #if defined(MAGICKCORE_RSVG_DELEGATE)
2717 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2724 register unsigned char
2737 register const guchar
2754 register PixelPacket
2760 svg_handle=rsvg_handle_new();
2761 if (svg_handle == (RsvgHandle *) NULL)
2762 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2763 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2764 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2765 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2767 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2768 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2769 image->y_resolution);
2770 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2772 error=(GError *) NULL;
2773 (void) rsvg_handle_write(svg_handle,message,n,&error);
2774 if (error != (GError *) NULL)
2775 g_error_free(error);
2777 error=(GError *) NULL;
2778 rsvg_handle_close(svg_handle,&error);
2779 if (error != (GError *) NULL)
2780 g_error_free(error);
2781 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2782 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2783 image->columns=dimension_info.width;
2784 image->rows=dimension_info.height;
2785 pixels=(unsigned char *) NULL;
2787 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2788 rsvg_handle_free(svg_handle);
2789 image->columns=gdk_pixbuf_get_width(pixel_info);
2790 image->rows=gdk_pixbuf_get_height(pixel_info);
2792 image->matte=MagickTrue;
2793 SetImageProperty(image,"svg:base-uri",
2794 rsvg_handle_get_base_uri(svg_handle));
2795 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2796 SetImageProperty(image,"svg:description",
2797 rsvg_handle_get_desc(svg_handle));
2798 if ((image->columns == 0) || (image->rows == 0))
2800 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2801 g_object_unref(G_OBJECT(pixel_info));
2803 g_object_unref(svg_handle);
2804 ThrowReaderException(MissingDelegateError,
2805 "NoDecodeDelegateForThisImageFormat");
2807 if (image_info->ping == MagickFalse)
2809 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2810 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2811 image->rows*sizeof(*pixels));
2812 if (pixels == (unsigned char *) NULL)
2814 g_object_unref(svg_handle);
2815 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2818 (void) SetImageBackgroundColor(image);
2819 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2820 cairo_surface=cairo_image_surface_create_for_data(pixels,
2821 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2822 if (cairo_surface == (cairo_surface_t *) NULL)
2824 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2825 g_object_unref(svg_handle);
2826 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2828 cairo_info=cairo_create(cairo_surface);
2829 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2830 cairo_paint(cairo_info);
2831 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2832 rsvg_handle_render_cairo(svg_handle,cairo_info);
2833 cairo_destroy(cairo_info);
2834 cairo_surface_destroy(cairo_surface);
2835 g_object_unref(svg_handle);
2838 p=gdk_pixbuf_get_pixels(pixel_info);
2840 for (y=0; y < (long) image->rows; y++)
2842 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2843 if (q == (PixelPacket *) NULL)
2845 for (x=0; x < (long) image->columns; x++)
2847 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2848 fill_color.blue=ScaleCharToQuantum(*p++);
2849 fill_color.green=ScaleCharToQuantum(*p++);
2850 fill_color.red=ScaleCharToQuantum(*p++);
2852 fill_color.red=ScaleCharToQuantum(*p++);
2853 fill_color.green=ScaleCharToQuantum(*p++);
2854 fill_color.blue=ScaleCharToQuantum(*p++);
2856 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2857 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2862 gamma=1.0-QuantumScale*fill_color.opacity;
2863 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2864 fill_color.blue*=gamma;
2865 fill_color.green*=gamma;
2866 fill_color.red*=gamma;
2869 MagickCompositeOver(&fill_color,fill_color.opacity,q,
2870 (MagickRealType) q->opacity,q);
2873 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2875 if (image->previous == (Image *) NULL)
2877 status=SetImageProgress(image,LoadImageTag,y,image->rows);
2878 if (status == MagickFalse)
2883 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2884 if (pixels != (unsigned char *) NULL)
2885 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2887 g_object_unref(G_OBJECT(pixel_info));
2889 (void) CloseBlob(image);
2890 return(GetFirstImageInList(image));
2897 unique_file=AcquireUniqueFileResource(filename);
2898 if (unique_file != -1)
2899 file=fdopen(unique_file,"w");
2900 if ((unique_file == -1) || (file == (FILE *) NULL))
2902 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2903 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2905 image=DestroyImageList(image);
2906 return((Image *) NULL);
2911 svg_info=AcquireSVGInfo();
2912 if (svg_info == (SVGInfo *) NULL)
2913 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2914 svg_info->file=file;
2915 svg_info->exception=exception;
2916 svg_info->image=image;
2917 svg_info->image_info=image_info;
2918 svg_info->bounds.width=image->columns;
2919 svg_info->bounds.height=image->rows;
2920 if (image_info->size != (char *) NULL)
2921 (void) CloneString(&svg_info->size,image_info->size);
2922 if (image->debug != MagickFalse)
2923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2925 (void) xmlSubstituteEntitiesDefault(1);
2926 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
2927 sax_modules.internalSubset=SVGInternalSubset;
2928 sax_modules.isStandalone=SVGIsStandalone;
2929 sax_modules.hasInternalSubset=SVGHasInternalSubset;
2930 sax_modules.hasExternalSubset=SVGHasExternalSubset;
2931 sax_modules.resolveEntity=SVGResolveEntity;
2932 sax_modules.getEntity=SVGGetEntity;
2933 sax_modules.entityDecl=SVGEntityDeclaration;
2934 sax_modules.notationDecl=SVGNotationDeclaration;
2935 sax_modules.attributeDecl=SVGAttributeDeclaration;
2936 sax_modules.elementDecl=SVGElementDeclaration;
2937 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
2938 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
2939 sax_modules.startDocument=SVGStartDocument;
2940 sax_modules.endDocument=SVGEndDocument;
2941 sax_modules.startElement=SVGStartElement;
2942 sax_modules.endElement=SVGEndElement;
2943 sax_modules.reference=SVGReference;
2944 sax_modules.characters=SVGCharacters;
2945 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
2946 sax_modules.processingInstruction=SVGProcessingInstructions;
2947 sax_modules.comment=SVGComment;
2948 sax_modules.warning=SVGWarning;
2949 sax_modules.error=SVGError;
2950 sax_modules.fatalError=SVGError;
2951 sax_modules.getParameterEntity=SVGGetParameterEntity;
2952 sax_modules.cdataBlock=SVGCDataBlock;
2953 sax_modules.externalSubset=SVGExternalSubset;
2954 sax_handler=(&sax_modules);
2955 n=ReadBlob(image,MaxTextExtent,message);
2958 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2959 message,n,image->filename);
2960 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2962 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2967 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2968 xmlFreeParserCtxt(svg_info->parser);
2969 if (image->debug != MagickFalse)
2970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2972 (void) fclose(file);
2973 (void) CloseBlob(image);
2974 image->columns=svg_info->width;
2975 image->rows=svg_info->height;
2976 if (exception->severity >= ErrorException)
2978 image=DestroyImage(image);
2979 return((Image *) NULL);
2981 if (image_info->ping == MagickFalse)
2989 image=DestroyImage(image);
2990 image=(Image *) NULL;
2991 read_info=CloneImageInfo(image_info);
2992 SetImageInfoBlob(read_info,(void *) NULL,0);
2993 if (read_info->density != (char *) NULL)
2994 read_info->density=DestroyString(read_info->density);
2995 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
2997 image=ReadImage(read_info,exception);
2998 read_info=DestroyImageInfo(read_info);
2999 if (image != (Image *) NULL)
3000 (void) CopyMagickString(image->filename,image_info->filename,
3004 Relinquish resources.
3006 if (image != (Image *) NULL)
3008 if (svg_info->title != (char *) NULL)
3009 (void) SetImageProperty(image,"svg:title",svg_info->title);
3010 if (svg_info->comment != (char *) NULL)
3011 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3013 svg_info=DestroySVGInfo(svg_info);
3014 (void) RelinquishUniqueFileResource(filename);
3015 return(GetFirstImageInList(image));
3020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3024 % R e g i s t e r S V G I m a g e %
3028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3030 % RegisterSVGImage() adds attributes for the SVG image format to
3031 % the list of supported formats. The attributes include the image format
3032 % tag, a method to read and/or write the format, whether the format
3033 % supports the saving of more than one frame to the same file or blob,
3034 % whether the format supports native in-memory I/O, and a brief
3035 % description of the format.
3037 % The format of the RegisterSVGImage method is:
3039 % unsigned long RegisterSVGImage(void)
3042 ModuleExport unsigned long RegisterSVGImage(void)
3045 version[MaxTextExtent];
3051 #if defined(LIBXML_DOTTED_VERSION)
3052 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3054 #if defined(MAGICKCORE_RSVG_DELEGATE)
3056 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3057 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3059 entry=SetMagickInfo("SVG");
3060 #if defined(MAGICKCORE_XML_DELEGATE)
3061 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3063 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3064 entry->blob_support=MagickFalse;
3065 entry->seekable_stream=MagickFalse;
3066 entry->description=ConstantString("Scalable Vector Graphics");
3067 if (*version != '\0')
3068 entry->version=ConstantString(version);
3069 entry->magick=(IsImageFormatHandler *) IsSVG;
3070 entry->module=ConstantString("SVG");
3071 (void) RegisterMagickInfo(entry);
3072 entry=SetMagickInfo("SVGZ");
3073 #if defined(MAGICKCORE_XML_DELEGATE)
3074 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3076 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3077 entry->blob_support=MagickFalse;
3078 entry->seekable_stream=MagickFalse;
3079 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3080 if (*version != '\0')
3081 entry->version=ConstantString(version);
3082 entry->magick=(IsImageFormatHandler *) IsSVG;
3083 entry->module=ConstantString("SVG");
3084 (void) RegisterMagickInfo(entry);
3085 entry=SetMagickInfo("MSVG");
3086 #if defined(MAGICKCORE_XML_DELEGATE)
3087 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3089 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3090 entry->blob_support=MagickFalse;
3091 entry->seekable_stream=MagickFalse;
3092 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3093 entry->magick=(IsImageFormatHandler *) IsSVG;
3094 entry->module=ConstantString("SVG");
3095 (void) RegisterMagickInfo(entry);
3096 return(MagickImageCoderSignature);
3100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3104 % U n r e g i s t e r S V G I m a g e %
3108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3110 % UnregisterSVGImage() removes format registrations made by the
3111 % SVG module from the list of supported formats.
3113 % The format of the UnregisterSVGImage method is:
3115 % UnregisterSVGImage(void)
3118 ModuleExport void UnregisterSVGImage(void)
3120 (void) UnregisterMagickInfo("SVGZ");
3121 (void) UnregisterMagickInfo("SVG");
3122 (void) UnregisterMagickInfo("MSVG");
3123 #if defined(MAGICKCORE_RSVG_DELEGATE)
3129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3133 % W r i t e S V G I m a g e %
3137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3139 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3142 % The format of the WriteSVGImage method is:
3144 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3146 % A description of each parameter follows.
3148 % o image_info: the image info.
3150 % o image: The image.
3154 static void AffineToTransform(Image *image,AffineMatrix *affine)
3157 transform[MaxTextExtent];
3159 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3161 if ((fabs(affine->rx) < MagickEpsilon) &&
3162 (fabs(affine->ry) < MagickEpsilon))
3164 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3165 (fabs(affine->sy-1.0) < MagickEpsilon))
3167 (void) WriteBlobString(image,"\">\n");
3170 (void) FormatMagickString(transform,MaxTextExtent,
3171 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3172 (void) WriteBlobString(image,transform);
3177 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3178 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3179 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3185 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3186 (void) FormatMagickString(transform,MaxTextExtent,
3187 "\" transform=\"rotate(%g)\">\n",theta);
3188 (void) WriteBlobString(image,transform);
3195 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3196 (fabs(affine->rx) < MagickEpsilon) &&
3197 (fabs(affine->ry) < MagickEpsilon) &&
3198 (fabs(affine->sy-1.0) < MagickEpsilon))
3200 (void) FormatMagickString(transform,MaxTextExtent,
3201 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3202 (void) WriteBlobString(image,transform);
3206 (void) FormatMagickString(transform,MaxTextExtent,
3207 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",affine->sx,affine->rx,
3208 affine->ry,affine->sy,affine->tx,affine->ty);
3209 (void) WriteBlobString(image,transform);
3212 static MagickBooleanType IsPoint(const char *point)
3220 value=strtol(point,&p,10);
3221 return(p != point ? MagickTrue : MagickFalse);
3224 static MagickBooleanType TraceSVGImage(Image *image)
3229 register const PixelPacket
3235 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3240 at_fitting_opts_type
3259 Trace image and write as SVG.
3261 fitting_options=at_fitting_opts_new();
3262 output_options=at_output_opts_new();
3263 type=GetImageType(image,&image->exception);
3265 if ((type == BilevelType) || (type == GrayscaleType))
3267 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3269 for (y=0; y < (long) image->rows; y++)
3271 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3272 if (p == (const PixelPacket *) NULL)
3274 for (x=0; x < (long) image->columns; x++)
3276 trace->bitmap[i++]=p->red;
3277 if (number_planes == 3)
3279 trace->bitmap[i++]=p->green;
3280 trace->bitmap[i++]=p->blue;
3285 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3287 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3288 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3293 at_splines_free(splines);
3294 at_bitmap_free(trace);
3295 at_output_opts_free(output_options);
3296 at_fitting_opts_free(fitting_options);
3301 message[MaxTextExtent],
3302 tuple[MaxTextExtent];
3307 register const IndexPacket
3310 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3311 (void) WriteBlobString(image,
3312 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3313 (void) WriteBlobString(image,
3314 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3315 (void) FormatMagickString(message,MaxTextExtent,
3316 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3317 (void) WriteBlobString(image,message);
3318 GetMagickPixelPacket(image,&pixel);
3319 for (y=0; y < (long) image->rows; y++)
3321 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3322 if (p == (const PixelPacket *) NULL)
3324 indexes=GetVirtualIndexQueue(image);
3325 for (x=0; x < (long) image->columns; x++)
3327 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3328 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3330 (void) FormatMagickString(message,MaxTextExtent,
3331 " <circle cx=\"%ld\" cy=\"%ld\" r=\"1\" fill=\"%s\"/>\n",x,y,tuple);
3332 (void) WriteBlobString(image,message);
3336 (void) WriteBlobString(image,"</svg>\n");
3342 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3344 #define BezierQuantum 200
3350 keyword[MaxTextExtent],
3351 message[MaxTextExtent],
3352 name[MaxTextExtent],
3354 type[MaxTextExtent];
3396 Open output image file.
3398 assert(image_info != (const ImageInfo *) NULL);
3399 assert(image_info->signature == MagickSignature);
3400 assert(image != (Image *) NULL);
3401 assert(image->signature == MagickSignature);
3402 if (image->debug != MagickFalse)
3403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3404 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3405 if (status == MagickFalse)
3407 value=GetImageArtifact(image,"SVG");
3408 if (value != (char *) NULL)
3410 (void) WriteBlobString(image,value);
3411 (void) CloseBlob(image);
3414 value=GetImageArtifact(image,"MVG");
3415 if (value == (char *) NULL)
3416 return(TraceSVGImage(image));
3420 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3421 (void) WriteBlobString(image,
3422 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3423 (void) WriteBlobString(image,
3424 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3425 (void) FormatMagickString(message,MaxTextExtent,
3426 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3427 (void) WriteBlobString(image,message);
3429 Allocate primitive info memory.
3432 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3433 sizeof(*primitive_info));
3434 if (primitive_info == (PrimitiveInfo *) NULL)
3435 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3436 GetAffineMatrix(&affine);
3437 token=AcquireString(value);
3441 for (q=(const char *) value; *q != '\0'; )
3444 Interpret graphic primitive.
3446 GetMagickToken(q,&q,keyword);
3447 if (*keyword == '\0')
3449 if (*keyword == '#')
3454 if (active != MagickFalse)
3456 AffineToTransform(image,&affine);
3459 (void) WriteBlobString(image,"<desc>");
3460 (void) WriteBlobString(image,keyword+1);
3461 for ( ; (*q != '\n') && (*q != '\0'); q++)
3464 case '<': (void) WriteBlobString(image,"<"); break;
3465 case '>': (void) WriteBlobString(image,">"); break;
3466 case '&': (void) WriteBlobString(image,"&"); break;
3467 default: (void) WriteBlobByte(image,*q); break;
3469 (void) WriteBlobString(image,"</desc>\n");
3472 primitive_type=UndefinedPrimitive;
3480 if (LocaleCompare("affine",keyword) == 0)
3482 GetMagickToken(q,&q,token);
3483 affine.sx=atof(token);
3484 GetMagickToken(q,&q,token);
3486 GetMagickToken(q,&q,token);
3487 affine.rx=atof(token);
3488 GetMagickToken(q,&q,token);
3490 GetMagickToken(q,&q,token);
3491 affine.ry=atof(token);
3492 GetMagickToken(q,&q,token);
3494 GetMagickToken(q,&q,token);
3495 affine.sy=atof(token);
3496 GetMagickToken(q,&q,token);
3498 GetMagickToken(q,&q,token);
3499 affine.tx=atof(token);
3500 GetMagickToken(q,&q,token);
3502 GetMagickToken(q,&q,token);
3503 affine.ty=atof(token);
3506 if (LocaleCompare("angle",keyword) == 0)
3508 GetMagickToken(q,&q,token);
3509 affine.rx=atof(token);
3510 affine.ry=atof(token);
3513 if (LocaleCompare("arc",keyword) == 0)
3515 primitive_type=ArcPrimitive;
3524 if (LocaleCompare("bezier",keyword) == 0)
3526 primitive_type=BezierPrimitive;
3535 if (LocaleCompare("clip-path",keyword) == 0)
3537 GetMagickToken(q,&q,token);
3538 (void) FormatMagickString(message,MaxTextExtent,
3539 "clip-path:url(#%s);",token);
3540 (void) WriteBlobString(image,message);
3543 if (LocaleCompare("clip-rule",keyword) == 0)
3545 GetMagickToken(q,&q,token);
3546 (void) FormatMagickString(message,MaxTextExtent,
3547 "clip-rule:%s;",token);
3548 (void) WriteBlobString(image,message);
3551 if (LocaleCompare("clip-units",keyword) == 0)
3553 GetMagickToken(q,&q,token);
3554 (void) FormatMagickString(message,MaxTextExtent,
3555 "clipPathUnits=%s;",token);
3556 (void) WriteBlobString(image,message);
3559 if (LocaleCompare("circle",keyword) == 0)
3561 primitive_type=CirclePrimitive;
3564 if (LocaleCompare("color",keyword) == 0)
3566 primitive_type=ColorPrimitive;
3575 if (LocaleCompare("decorate",keyword) == 0)
3577 GetMagickToken(q,&q,token);
3578 (void) FormatMagickString(message,MaxTextExtent,
3579 "text-decoration:%s;",token);
3580 (void) WriteBlobString(image,message);
3589 if (LocaleCompare("ellipse",keyword) == 0)
3591 primitive_type=EllipsePrimitive;
3600 if (LocaleCompare("fill",keyword) == 0)
3602 GetMagickToken(q,&q,token);
3603 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3605 (void) WriteBlobString(image,message);
3608 if (LocaleCompare("fill-rule",keyword) == 0)
3610 GetMagickToken(q,&q,token);
3611 (void) FormatMagickString(message,MaxTextExtent,
3612 "fill-rule:%s;",token);
3613 (void) WriteBlobString(image,message);
3616 if (LocaleCompare("fill-opacity",keyword) == 0)
3618 GetMagickToken(q,&q,token);
3619 (void) FormatMagickString(message,MaxTextExtent,
3620 "fill-opacity:%s;",token);
3621 (void) WriteBlobString(image,message);
3624 if (LocaleCompare("font-family",keyword) == 0)
3626 GetMagickToken(q,&q,token);
3627 (void) FormatMagickString(message,MaxTextExtent,
3628 "font-family:%s;",token);
3629 (void) WriteBlobString(image,message);
3632 if (LocaleCompare("font-stretch",keyword) == 0)
3634 GetMagickToken(q,&q,token);
3635 (void) FormatMagickString(message,MaxTextExtent,
3636 "font-stretch:%s;",token);
3637 (void) WriteBlobString(image,message);
3640 if (LocaleCompare("font-style",keyword) == 0)
3642 GetMagickToken(q,&q,token);
3643 (void) FormatMagickString(message,MaxTextExtent,
3644 "font-style:%s;",token);
3645 (void) WriteBlobString(image,message);
3648 if (LocaleCompare("font-size",keyword) == 0)
3650 GetMagickToken(q,&q,token);
3651 (void) FormatMagickString(message,MaxTextExtent,
3652 "font-size:%s;",token);
3653 (void) WriteBlobString(image,message);
3656 if (LocaleCompare("font-weight",keyword) == 0)
3658 GetMagickToken(q,&q,token);
3659 (void) FormatMagickString(message,MaxTextExtent,
3660 "font-weight:%s;",token);
3661 (void) WriteBlobString(image,message);
3670 if (LocaleCompare("gradient-units",keyword) == 0)
3672 GetMagickToken(q,&q,token);
3675 if (LocaleCompare("text-align",keyword) == 0)
3677 GetMagickToken(q,&q,token);
3678 (void) FormatMagickString(message,MaxTextExtent,
3679 "text-align %s ",token);
3680 (void) WriteBlobString(image,message);
3683 if (LocaleCompare("text-anchor",keyword) == 0)
3685 GetMagickToken(q,&q,token);
3686 (void) FormatMagickString(message,MaxTextExtent,
3687 "text-anchor %s ",token);
3688 (void) WriteBlobString(image,message);
3697 if (LocaleCompare("image",keyword) == 0)
3699 GetMagickToken(q,&q,token);
3700 primitive_type=ImagePrimitive;
3709 if (LocaleCompare("line",keyword) == 0)
3711 primitive_type=LinePrimitive;
3720 if (LocaleCompare("matte",keyword) == 0)
3722 primitive_type=MattePrimitive;
3731 if (LocaleCompare("opacity",keyword) == 0)
3733 GetMagickToken(q,&q,token);
3734 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3736 (void) WriteBlobString(image,message);
3745 if (LocaleCompare("path",keyword) == 0)
3747 primitive_type=PathPrimitive;
3750 if (LocaleCompare("point",keyword) == 0)
3752 primitive_type=PointPrimitive;
3755 if (LocaleCompare("polyline",keyword) == 0)
3757 primitive_type=PolylinePrimitive;
3760 if (LocaleCompare("polygon",keyword) == 0)
3762 primitive_type=PolygonPrimitive;
3765 if (LocaleCompare("pop",keyword) == 0)
3767 GetMagickToken(q,&q,token);
3768 if (LocaleCompare("clip-path",token) == 0)
3770 (void) WriteBlobString(image,"</clipPath>\n");
3773 if (LocaleCompare("defs",token) == 0)
3775 (void) WriteBlobString(image,"</defs>\n");
3778 if (LocaleCompare("gradient",token) == 0)
3780 (void) FormatMagickString(message,MaxTextExtent,
3781 "</%sGradient>\n",type);
3782 (void) WriteBlobString(image,message);
3785 if (LocaleCompare("graphic-context",token) == 0)
3789 ThrowWriterException(DrawError,
3790 "UnbalancedGraphicContextPushPop");
3791 (void) WriteBlobString(image,"</g>\n");
3793 if (LocaleCompare("pattern",token) == 0)
3795 (void) WriteBlobString(image,"</pattern>\n");
3798 if (LocaleCompare("defs",token) == 0)
3799 (void) WriteBlobString(image,"</g>\n");
3802 if (LocaleCompare("push",keyword) == 0)
3804 GetMagickToken(q,&q,token);
3805 if (LocaleCompare("clip-path",token) == 0)
3807 GetMagickToken(q,&q,token);
3808 (void) FormatMagickString(message,MaxTextExtent,
3809 "<clipPath id=\"%s\">\n",token);
3810 (void) WriteBlobString(image,message);
3813 if (LocaleCompare("defs",token) == 0)
3815 (void) WriteBlobString(image,"<defs>\n");
3818 if (LocaleCompare("gradient",token) == 0)
3820 GetMagickToken(q,&q,token);
3821 (void) CopyMagickString(name,token,MaxTextExtent);
3822 GetMagickToken(q,&q,token);
3823 (void) CopyMagickString(type,token,MaxTextExtent);
3824 GetMagickToken(q,&q,token);
3825 svg_info.segment.x1=atof(token);
3826 svg_info.element.cx=atof(token);
3827 GetMagickToken(q,&q,token);
3829 GetMagickToken(q,&q,token);
3830 svg_info.segment.y1=atof(token);
3831 svg_info.element.cy=atof(token);
3832 GetMagickToken(q,&q,token);
3834 GetMagickToken(q,&q,token);
3835 svg_info.segment.x2=atof(token);
3836 svg_info.element.major=atof(token);
3837 GetMagickToken(q,&q,token);
3839 GetMagickToken(q,&q,token);
3840 svg_info.segment.y2=atof(token);
3841 svg_info.element.minor=atof(token);
3842 (void) FormatMagickString(message,MaxTextExtent,
3843 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3844 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3845 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3846 if (LocaleCompare(type,"radial") == 0)
3848 GetMagickToken(q,&q,token);
3850 GetMagickToken(q,&q,token);
3851 svg_info.element.angle=atof(token);
3852 (void) FormatMagickString(message,MaxTextExtent,
3853 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3854 "fx=\"%g\" fy=\"%g\">\n",type,name,svg_info.element.cx,
3855 svg_info.element.cy,svg_info.element.angle,
3856 svg_info.element.major,svg_info.element.minor);
3858 (void) WriteBlobString(image,message);
3861 if (LocaleCompare("graphic-context",token) == 0)
3866 AffineToTransform(image,&affine);
3869 (void) WriteBlobString(image,"<g style=\"");
3872 if (LocaleCompare("pattern",token) == 0)
3874 GetMagickToken(q,&q,token);
3875 (void) CopyMagickString(name,token,MaxTextExtent);
3876 GetMagickToken(q,&q,token);
3877 svg_info.bounds.x=atof(token);
3878 GetMagickToken(q,&q,token);
3880 GetMagickToken(q,&q,token);
3881 svg_info.bounds.y=atof(token);
3882 GetMagickToken(q,&q,token);
3884 GetMagickToken(q,&q,token);
3885 svg_info.bounds.width=atof(token);
3886 GetMagickToken(q,&q,token);
3888 GetMagickToken(q,&q,token);
3889 svg_info.bounds.height=atof(token);
3890 (void) FormatMagickString(message,MaxTextExtent,
3891 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3892 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
3893 svg_info.bounds.width,svg_info.bounds.height);
3894 (void) WriteBlobString(image,message);
3905 if (LocaleCompare("rectangle",keyword) == 0)
3907 primitive_type=RectanglePrimitive;
3910 if (LocaleCompare("roundRectangle",keyword) == 0)
3912 primitive_type=RoundRectanglePrimitive;
3915 if (LocaleCompare("rotate",keyword) == 0)
3917 GetMagickToken(q,&q,token);
3918 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3920 (void) WriteBlobString(image,message);
3929 if (LocaleCompare("scale",keyword) == 0)
3931 GetMagickToken(q,&q,token);
3932 affine.sx=atof(token);
3933 GetMagickToken(q,&q,token);
3935 GetMagickToken(q,&q,token);
3936 affine.sy=atof(token);
3939 if (LocaleCompare("skewX",keyword) == 0)
3941 GetMagickToken(q,&q,token);
3942 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3944 (void) WriteBlobString(image,message);
3947 if (LocaleCompare("skewY",keyword) == 0)
3949 GetMagickToken(q,&q,token);
3950 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3952 (void) WriteBlobString(image,message);
3955 if (LocaleCompare("stop-color",keyword) == 0)
3958 color[MaxTextExtent];
3960 GetMagickToken(q,&q,token);
3961 (void) CopyMagickString(color,token,MaxTextExtent);
3962 GetMagickToken(q,&q,token);
3963 (void) FormatMagickString(message,MaxTextExtent,
3964 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3965 (void) WriteBlobString(image,message);
3968 if (LocaleCompare("stroke",keyword) == 0)
3970 GetMagickToken(q,&q,token);
3971 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
3973 (void) WriteBlobString(image,message);
3976 if (LocaleCompare("stroke-antialias",keyword) == 0)
3978 GetMagickToken(q,&q,token);
3979 (void) FormatMagickString(message,MaxTextExtent,
3980 "stroke-antialias:%s;",token);
3981 (void) WriteBlobString(image,message);
3984 if (LocaleCompare("stroke-dasharray",keyword) == 0)
3992 GetMagickToken(p,&p,token);
3993 for (k=0; IsPoint(token); k++)
3994 GetMagickToken(p,&p,token);
3995 (void) WriteBlobString(image,"stroke-dasharray:");
3996 for (j=0; j < k; j++)
3998 GetMagickToken(q,&q,token);
3999 (void) FormatMagickString(message,MaxTextExtent,"%s ",
4001 (void) WriteBlobString(image,message);
4003 (void) WriteBlobString(image,";");
4006 GetMagickToken(q,&q,token);
4007 (void) FormatMagickString(message,MaxTextExtent,
4008 "stroke-dasharray:%s;",token);
4009 (void) WriteBlobString(image,message);
4012 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4014 GetMagickToken(q,&q,token);
4015 (void) FormatMagickString(message,MaxTextExtent,
4016 "stroke-dashoffset:%s;",token);
4017 (void) WriteBlobString(image,message);
4020 if (LocaleCompare("stroke-linecap",keyword) == 0)
4022 GetMagickToken(q,&q,token);
4023 (void) FormatMagickString(message,MaxTextExtent,
4024 "stroke-linecap:%s;",token);
4025 (void) WriteBlobString(image,message);
4028 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4030 GetMagickToken(q,&q,token);
4031 (void) FormatMagickString(message,MaxTextExtent,
4032 "stroke-linejoin:%s;",token);
4033 (void) WriteBlobString(image,message);
4036 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4038 GetMagickToken(q,&q,token);
4039 (void) FormatMagickString(message,MaxTextExtent,
4040 "stroke-miterlimit:%s;",token);
4041 (void) WriteBlobString(image,message);
4044 if (LocaleCompare("stroke-opacity",keyword) == 0)
4046 GetMagickToken(q,&q,token);
4047 (void) FormatMagickString(message,MaxTextExtent,
4048 "stroke-opacity:%s;",token);
4049 (void) WriteBlobString(image,message);
4052 if (LocaleCompare("stroke-width",keyword) == 0)
4054 GetMagickToken(q,&q,token);
4055 (void) FormatMagickString(message,MaxTextExtent,
4056 "stroke-width:%s;",token);
4057 (void) WriteBlobString(image,message);
4066 if (LocaleCompare("text",keyword) == 0)
4068 primitive_type=TextPrimitive;
4071 if (LocaleCompare("text-antialias",keyword) == 0)
4073 GetMagickToken(q,&q,token);
4074 (void) FormatMagickString(message,MaxTextExtent,
4075 "text-antialias:%s;",token);
4076 (void) WriteBlobString(image,message);
4079 if (LocaleCompare("tspan",keyword) == 0)
4081 primitive_type=TextPrimitive;
4084 if (LocaleCompare("translate",keyword) == 0)
4086 GetMagickToken(q,&q,token);
4087 affine.tx=atof(token);
4088 GetMagickToken(q,&q,token);
4090 GetMagickToken(q,&q,token);
4091 affine.ty=atof(token);
4100 if (LocaleCompare("viewbox",keyword) == 0)
4102 GetMagickToken(q,&q,token);
4104 GetMagickToken(q,&q,token);
4105 GetMagickToken(q,&q,token);
4107 GetMagickToken(q,&q,token);
4108 GetMagickToken(q,&q,token);
4110 GetMagickToken(q,&q,token);
4111 GetMagickToken(q,&q,token);
4123 if (status == MagickFalse)
4125 if (primitive_type == UndefinedPrimitive)
4128 Parse the primitive attributes.
4132 for (x=0; *q != '\0'; x++)
4137 if (IsPoint(q) == MagickFalse)
4139 GetMagickToken(q,&q,token);
4140 point.x=atof(token);
4141 GetMagickToken(q,&q,token);
4143 GetMagickToken(q,&q,token);
4144 point.y=atof(token);
4145 GetMagickToken(q,(const char **) NULL,token);
4147 GetMagickToken(q,&q,token);
4148 primitive_info[i].primitive=primitive_type;
4149 primitive_info[i].point=point;
4150 primitive_info[i].coordinates=0;
4151 primitive_info[i].method=FloodfillMethod;
4153 if (i < (long) (number_points-6*BezierQuantum-360))
4155 number_points+=6*BezierQuantum+360;
4156 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4157 number_points,sizeof(*primitive_info));
4158 if (primitive_info == (PrimitiveInfo *) NULL)
4160 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4161 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4165 primitive_info[j].primitive=primitive_type;
4166 primitive_info[j].coordinates=x;
4167 primitive_info[j].method=FloodfillMethod;
4168 primitive_info[j].text=(char *) NULL;
4171 AffineToTransform(image,&affine);
4175 switch (primitive_type)
4177 case PointPrimitive:
4180 if (primitive_info[j].coordinates != 1)
4189 if (primitive_info[j].coordinates != 2)
4194 (void) FormatMagickString(message,MaxTextExtent,
4195 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4196 primitive_info[j].point.x,primitive_info[j].point.y,
4197 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4198 (void) WriteBlobString(image,message);
4201 case RectanglePrimitive:
4203 if (primitive_info[j].coordinates != 2)
4208 (void) FormatMagickString(message,MaxTextExtent,
4209 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4210 primitive_info[j].point.x,primitive_info[j].point.y,
4211 primitive_info[j+1].point.x-primitive_info[j].point.x,
4212 primitive_info[j+1].point.y-primitive_info[j].point.y);
4213 (void) WriteBlobString(image,message);
4216 case RoundRectanglePrimitive:
4218 if (primitive_info[j].coordinates != 3)
4223 (void) FormatMagickString(message,MaxTextExtent,
4224 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4225 "ry=\"%g\"/>\n",primitive_info[j].point.x,primitive_info[j].point.y,
4226 primitive_info[j+1].point.x-primitive_info[j].point.x,
4227 primitive_info[j+1].point.y-primitive_info[j].point.y,
4228 primitive_info[j+2].point.x,primitive_info[j+2].point.y);
4229 (void) WriteBlobString(image,message);
4234 if (primitive_info[j].coordinates != 3)
4241 case EllipsePrimitive:
4243 if (primitive_info[j].coordinates != 3)
4248 (void) FormatMagickString(message,MaxTextExtent,
4249 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4250 primitive_info[j].point.x,primitive_info[j].point.y,
4251 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4252 (void) WriteBlobString(image,message);
4255 case CirclePrimitive:
4261 if (primitive_info[j].coordinates != 2)
4266 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4267 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4268 (void) FormatMagickString(message,MaxTextExtent,
4269 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4270 primitive_info[j].point.x,primitive_info[j].point.y,
4272 (void) WriteBlobString(image,message);
4275 case PolylinePrimitive:
4277 if (primitive_info[j].coordinates < 2)
4282 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4283 (void) WriteBlobString(image,message);
4284 length=strlen(message);
4287 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4288 primitive_info[j].point.x,primitive_info[j].point.y);
4289 length+=strlen(message);
4292 (void) WriteBlobString(image,"\n ");
4293 length=strlen(message)+5;
4295 (void) WriteBlobString(image,message);
4297 (void) WriteBlobString(image,"\"/>\n");
4300 case PolygonPrimitive:
4302 if (primitive_info[j].coordinates < 3)
4307 primitive_info[i]=primitive_info[j];
4308 primitive_info[i].coordinates=0;
4309 primitive_info[j].coordinates++;
4311 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4312 (void) WriteBlobString(image,message);
4313 length=strlen(message);
4316 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4317 primitive_info[j].point.x,primitive_info[j].point.y);
4318 length+=strlen(message);
4321 (void) WriteBlobString(image,"\n ");
4322 length=strlen(message)+5;
4324 (void) WriteBlobString(image,message);
4326 (void) WriteBlobString(image,"\"/>\n");
4329 case BezierPrimitive:
4331 if (primitive_info[j].coordinates < 3)
4343 GetMagickToken(q,&q,token);
4344 number_attributes=1;
4345 for (p=token; *p != '\0'; p++)
4346 if (isalpha((int) *p))
4347 number_attributes++;
4348 if (i > (long) (number_points-6*BezierQuantum*number_attributes-1))
4350 number_points+=6*BezierQuantum*number_attributes;
4351 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4352 number_points,sizeof(*primitive_info));
4353 if (primitive_info == (PrimitiveInfo *) NULL)
4355 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4356 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4361 (void) WriteBlobString(image," <path d=\"");
4362 (void) WriteBlobString(image,token);
4363 (void) WriteBlobString(image,"\"/>\n");
4366 case ColorPrimitive:
4367 case MattePrimitive:
4369 if (primitive_info[j].coordinates != 1)
4374 GetMagickToken(q,&q,token);
4375 if (LocaleCompare("point",token) == 0)
4376 primitive_info[j].method=PointMethod;
4377 if (LocaleCompare("replace",token) == 0)
4378 primitive_info[j].method=ReplaceMethod;
4379 if (LocaleCompare("floodfill",token) == 0)
4380 primitive_info[j].method=FloodfillMethod;
4381 if (LocaleCompare("filltoborder",token) == 0)
4382 primitive_info[j].method=FillToBorderMethod;
4383 if (LocaleCompare("reset",token) == 0)
4384 primitive_info[j].method=ResetMethod;
4392 if (primitive_info[j].coordinates != 1)
4397 GetMagickToken(q,&q,token);
4398 (void) FormatMagickString(message,MaxTextExtent,
4399 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4400 primitive_info[j].point.y);
4401 (void) WriteBlobString(image,message);
4402 for (p=token; *p != '\0'; p++)
4405 case '<': (void) WriteBlobString(image,"<"); break;
4406 case '>': (void) WriteBlobString(image,">"); break;
4407 case '&': (void) WriteBlobString(image,"&"); break;
4408 default: (void) WriteBlobByte(image,*p); break;
4410 (void) WriteBlobString(image,"</text>\n");
4413 case ImagePrimitive:
4415 if (primitive_info[j].coordinates != 2)
4420 GetMagickToken(q,&q,token);
4421 (void) FormatMagickString(message,MaxTextExtent,
4422 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4423 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4424 primitive_info[j].point.y,primitive_info[j+1].point.x,
4425 primitive_info[j+1].point.y,token);
4426 (void) WriteBlobString(image,message);
4430 if (primitive_info == (PrimitiveInfo *) NULL)
4432 primitive_info[i].primitive=UndefinedPrimitive;
4433 if (status == MagickFalse)
4436 (void) WriteBlobString(image,"</svg>\n");
4438 Relinquish resources.
4440 token=DestroyString(token);
4441 if (primitive_info != (PrimitiveInfo *) NULL)
4442 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4443 (void) CloseBlob(image);