2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2009 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)
2674 SVGHasInternalSubset,
2675 SVGHasExternalSubset,
2678 SVGEntityDeclaration,
2679 SVGNotationDeclaration,
2680 SVGAttributeDeclaration,
2681 SVGElementDeclaration,
2682 SVGUnparsedEntityDeclaration,
2683 SVGSetDocumentLocator,
2690 SVGIgnorableWhitespace,
2691 SVGProcessingInstructions,
2696 SVGGetParameterEntity,
2702 filename[MaxTextExtent];
2721 message[MaxTextExtent];
2729 assert(image_info != (const ImageInfo *) NULL);
2730 assert(image_info->signature == MagickSignature);
2731 assert(exception != (ExceptionInfo *) NULL);
2732 if (image_info->debug != MagickFalse)
2733 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2734 image_info->filename);
2735 assert(exception->signature == MagickSignature);
2736 image=AcquireImage(image_info);
2737 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2738 if (status == MagickFalse)
2740 image=DestroyImageList(image);
2741 return((Image *) NULL);
2743 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2745 #if defined(MAGICKCORE_RSVG_DELEGATE)
2746 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2753 register unsigned char
2766 register const guchar
2783 register PixelPacket
2789 svg_handle=rsvg_handle_new();
2790 if (svg_handle == (RsvgHandle *) NULL)
2791 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2792 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2793 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2794 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2796 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2797 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2798 image->y_resolution);
2799 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2801 error=(GError *) NULL;
2802 (void) rsvg_handle_write(svg_handle,message,n,&error);
2803 if (error != (GError *) NULL)
2804 g_error_free(error);
2806 error=(GError *) NULL;
2807 rsvg_handle_close(svg_handle,&error);
2808 if (error != (GError *) NULL)
2809 g_error_free(error);
2810 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2811 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2812 image->columns=dimension_info.width*image->x_resolution/72.0;
2813 image->rows=dimension_info.height*image->y_resolution/72.0;
2814 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2815 image->rows*sizeof(*pixels));
2817 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2818 rsvg_handle_free(svg_handle);
2819 image->columns=gdk_pixbuf_get_width(pixel_info);
2820 image->rows=gdk_pixbuf_get_height(pixel_info);
2822 if ((image->columns == 0) || (image->rows == 0))
2824 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2825 g_object_unref(G_OBJECT(pixel_info));
2827 g_object_unref(svg_handle);
2828 ThrowReaderException(MissingDelegateError,
2829 "NoDecodeDelegateForThisImageFormat");
2831 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2832 if (pixels == (unsigned char *) NULL)
2834 g_object_unref(svg_handle);
2835 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2838 image->matte=MagickTrue;
2839 (void) SetImageBackgroundColor(image);
2840 SetImageProperty(image,"svg:base-uri",
2841 rsvg_handle_get_base_uri(svg_handle));
2842 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2843 SetImageProperty(image,"svg:description",
2844 rsvg_handle_get_desc(svg_handle));
2845 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2846 cairo_surface=cairo_image_surface_create_for_data(pixels,
2847 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2848 if (cairo_surface == (cairo_surface_t *) NULL)
2850 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2851 g_object_unref(svg_handle);
2852 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2854 cairo_info=cairo_create(cairo_surface);
2855 cairo_scale(cairo_info,image->x_resolution/72.0,image->y_resolution/72.0);
2856 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2857 cairo_paint(cairo_info);
2858 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2859 rsvg_handle_render_cairo(svg_handle,cairo_info);
2860 cairo_destroy(cairo_info);
2861 cairo_surface_destroy(cairo_surface);
2862 g_object_unref(svg_handle);
2865 p=gdk_pixbuf_get_pixels(pixel_info);
2867 for (y=0; y < (long) image->rows; y++)
2869 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2870 if (q == (PixelPacket *) NULL)
2872 for (x=0; x < (long) image->columns; x++)
2874 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2875 fill_color.blue=ScaleCharToQuantum(*p++);
2876 fill_color.green=ScaleCharToQuantum(*p++);
2877 fill_color.red=ScaleCharToQuantum(*p++);
2879 fill_color.red=ScaleCharToQuantum(*p++);
2880 fill_color.green=ScaleCharToQuantum(*p++);
2881 fill_color.blue=ScaleCharToQuantum(*p++);
2883 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2884 MagickCompositeOver(&fill_color,fill_color.opacity,q,(MagickRealType)
2888 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2890 if (image->previous == (Image *) NULL)
2892 status=SetImageProgress(image,LoadImageTag,y,image->rows);
2893 if (status == MagickFalse)
2897 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2898 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2900 g_object_unref(G_OBJECT(pixel_info));
2902 (void) CloseBlob(image);
2903 return(GetFirstImageInList(image));
2910 unique_file=AcquireUniqueFileResource(filename);
2911 if (unique_file != -1)
2912 file=fdopen(unique_file,"w");
2913 if ((unique_file == -1) || (file == (FILE *) NULL))
2915 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2916 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2918 image=DestroyImageList(image);
2919 return((Image *) NULL);
2924 svg_info=AcquireSVGInfo();
2925 if (svg_info == (SVGInfo *) NULL)
2926 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2927 svg_info->file=file;
2928 svg_info->exception=exception;
2929 svg_info->image=image;
2930 svg_info->image_info=image_info;
2931 svg_info->bounds.width=image->columns;
2932 svg_info->bounds.height=image->rows;
2933 if (image_info->size != (char *) NULL)
2934 (void) CloneString(&svg_info->size,image_info->size);
2935 if (image->debug != MagickFalse)
2936 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2938 (void) xmlSubstituteEntitiesDefault(1);
2939 sax_handler=(&SAXModules);
2940 n=ReadBlob(image,MaxTextExtent,message);
2943 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2944 message,n,image->filename);
2945 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2947 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2952 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2953 xmlFreeParserCtxt(svg_info->parser);
2954 if (image->debug != MagickFalse)
2955 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2957 (void) fclose(file);
2958 (void) CloseBlob(image);
2959 image->columns=svg_info->width;
2960 image->rows=svg_info->height;
2961 if (exception->severity >= ErrorException)
2963 image=DestroyImage(image);
2964 return((Image *) NULL);
2966 if (image_info->ping == MagickFalse)
2974 image=DestroyImage(image);
2975 image=(Image *) NULL;
2976 read_info=CloneImageInfo(image_info);
2977 SetImageInfoBlob(read_info,(void *) NULL,0);
2978 if (read_info->density != (char *) NULL)
2979 read_info->density=DestroyString(read_info->density);
2980 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
2982 image=ReadImage(read_info,exception);
2983 read_info=DestroyImageInfo(read_info);
2984 if (image != (Image *) NULL)
2985 (void) CopyMagickString(image->filename,image_info->filename,
2989 Relinquish resources.
2991 if (image != (Image *) NULL)
2993 if (svg_info->title != (char *) NULL)
2994 (void) SetImageProperty(image,"svg:title",svg_info->title);
2995 if (svg_info->comment != (char *) NULL)
2996 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
2998 svg_info=DestroySVGInfo(svg_info);
2999 (void) RelinquishUniqueFileResource(filename);
3000 return(GetFirstImageInList(image));
3005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009 % R e g i s t e r S V G I m a g e %
3013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3015 % RegisterSVGImage() adds attributes for the SVG image format to
3016 % the list of supported formats. The attributes include the image format
3017 % tag, a method to read and/or write the format, whether the format
3018 % supports the saving of more than one frame to the same file or blob,
3019 % whether the format supports native in-memory I/O, and a brief
3020 % description of the format.
3022 % The format of the RegisterSVGImage method is:
3024 % unsigned long RegisterSVGImage(void)
3027 ModuleExport unsigned long RegisterSVGImage(void)
3030 version[MaxTextExtent];
3036 #if defined(LIBXML_DOTTED_VERSION)
3037 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3039 #if defined(MAGICKCORE_RSVG_DELEGATE)
3041 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3042 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3044 entry=SetMagickInfo("SVG");
3045 #if defined(MAGICKCORE_XML_DELEGATE)
3046 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3048 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3049 entry->blob_support=MagickFalse;
3050 entry->seekable_stream=MagickFalse;
3051 entry->description=ConstantString("Scalable Vector Graphics");
3052 if (*version != '\0')
3053 entry->version=ConstantString(version);
3054 entry->magick=(IsImageFormatHandler *) IsSVG;
3055 entry->module=ConstantString("SVG");
3056 (void) RegisterMagickInfo(entry);
3057 entry=SetMagickInfo("SVGZ");
3058 #if defined(MAGICKCORE_XML_DELEGATE)
3059 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3061 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3062 entry->blob_support=MagickFalse;
3063 entry->seekable_stream=MagickFalse;
3064 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3065 if (*version != '\0')
3066 entry->version=ConstantString(version);
3067 entry->magick=(IsImageFormatHandler *) IsSVG;
3068 entry->module=ConstantString("SVG");
3069 (void) RegisterMagickInfo(entry);
3070 entry=SetMagickInfo("MSVG");
3071 #if defined(MAGICKCORE_XML_DELEGATE)
3072 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3074 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3075 entry->blob_support=MagickFalse;
3076 entry->seekable_stream=MagickFalse;
3077 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3078 entry->magick=(IsImageFormatHandler *) IsSVG;
3079 entry->module=ConstantString("SVG");
3080 (void) RegisterMagickInfo(entry);
3081 return(MagickImageCoderSignature);
3085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089 % U n r e g i s t e r S V G I m a g e %
3093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095 % UnregisterSVGImage() removes format registrations made by the
3096 % SVG module from the list of supported formats.
3098 % The format of the UnregisterSVGImage method is:
3100 % UnregisterSVGImage(void)
3103 ModuleExport void UnregisterSVGImage(void)
3105 (void) UnregisterMagickInfo("SVGZ");
3106 (void) UnregisterMagickInfo("SVG");
3107 (void) UnregisterMagickInfo("MSVG");
3108 #if defined(MAGICKCORE_RSVG_DELEGATE)
3114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3118 % W r i t e S V G I m a g e %
3122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3124 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3127 % The format of the WriteSVGImage method is:
3129 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3131 % A description of each parameter follows.
3133 % o image_info: the image info.
3135 % o image: The image.
3139 static void AffineToTransform(Image *image,AffineMatrix *affine)
3142 transform[MaxTextExtent];
3144 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3146 if ((fabs(affine->rx) < MagickEpsilon) &&
3147 (fabs(affine->ry) < MagickEpsilon))
3149 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3150 (fabs(affine->sy-1.0) < MagickEpsilon))
3152 (void) WriteBlobString(image,"\">\n");
3155 (void) FormatMagickString(transform,MaxTextExtent,
3156 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3157 (void) WriteBlobString(image,transform);
3162 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3163 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3164 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3170 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3171 (void) FormatMagickString(transform,MaxTextExtent,
3172 "\" transform=\"rotate(%g)\">\n",theta);
3173 (void) WriteBlobString(image,transform);
3180 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3181 (fabs(affine->rx) < MagickEpsilon) &&
3182 (fabs(affine->ry) < MagickEpsilon) &&
3183 (fabs(affine->sy-1.0) < MagickEpsilon))
3185 (void) FormatMagickString(transform,MaxTextExtent,
3186 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3187 (void) WriteBlobString(image,transform);
3191 (void) FormatMagickString(transform,MaxTextExtent,
3192 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",affine->sx,affine->rx,
3193 affine->ry,affine->sy,affine->tx,affine->ty);
3194 (void) WriteBlobString(image,transform);
3197 static MagickBooleanType IsPoint(const char *point)
3205 value=strtol(point,&p,10);
3206 return(p != point ? MagickTrue : MagickFalse);
3209 static MagickBooleanType TraceSVGImage(Image *image)
3214 register const PixelPacket
3220 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3225 at_fitting_opts_type
3244 Trace image and write as SVG.
3246 fitting_options=at_fitting_opts_new();
3247 output_options=at_output_opts_new();
3248 type=GetImageType(image,&image->exception);
3250 if ((type == BilevelType) || (type == GrayscaleType))
3252 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3254 for (y=0; y < (long) image->rows; y++)
3256 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3257 if (p == (const PixelPacket *) NULL)
3259 for (x=0; x < (long) image->columns; x++)
3261 trace->bitmap[i++]=p->red;
3262 if (number_planes == 3)
3264 trace->bitmap[i++]=p->green;
3265 trace->bitmap[i++]=p->blue;
3270 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3272 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3273 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3278 at_splines_free(splines);
3279 at_bitmap_free(trace);
3280 at_output_opts_free(output_options);
3281 at_fitting_opts_free(fitting_options);
3286 message[MaxTextExtent],
3287 tuple[MaxTextExtent];
3292 register const IndexPacket
3295 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3296 (void) WriteBlobString(image,
3297 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3298 (void) WriteBlobString(image,
3299 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3300 (void) FormatMagickString(message,MaxTextExtent,
3301 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3302 (void) WriteBlobString(image,message);
3303 GetMagickPixelPacket(image,&pixel);
3304 for (y=0; y < (long) image->rows; y++)
3306 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3307 if (p == (const PixelPacket *) NULL)
3309 indexes=GetVirtualIndexQueue(image);
3310 for (x=0; x < (long) image->columns; x++)
3312 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3313 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3315 (void) FormatMagickString(message,MaxTextExtent,
3316 " <circle cx=\"%ld\" cy=\"%ld\" r=\"1\" fill=\"%s\"/>\n",x,y,tuple);
3317 (void) WriteBlobString(image,message);
3321 (void) WriteBlobString(image,"</svg>\n");
3327 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3329 #define BezierQuantum 200
3335 keyword[MaxTextExtent],
3336 message[MaxTextExtent],
3337 name[MaxTextExtent],
3339 type[MaxTextExtent];
3381 Open output image file.
3383 assert(image_info != (const ImageInfo *) NULL);
3384 assert(image_info->signature == MagickSignature);
3385 assert(image != (Image *) NULL);
3386 assert(image->signature == MagickSignature);
3387 if (image->debug != MagickFalse)
3388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3389 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3390 if (status == MagickFalse)
3392 value=GetImageArtifact(image,"SVG");
3393 if (value != (char *) NULL)
3395 (void) WriteBlobString(image,value);
3396 (void) CloseBlob(image);
3399 value=GetImageArtifact(image,"MVG");
3400 if (value == (char *) NULL)
3401 return(TraceSVGImage(image));
3405 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3406 (void) WriteBlobString(image,
3407 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3408 (void) WriteBlobString(image,
3409 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3410 (void) FormatMagickString(message,MaxTextExtent,
3411 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3412 (void) WriteBlobString(image,message);
3414 Allocate primitive info memory.
3417 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3418 sizeof(*primitive_info));
3419 if (primitive_info == (PrimitiveInfo *) NULL)
3420 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3421 GetAffineMatrix(&affine);
3422 token=AcquireString(value);
3426 for (q=(const char *) value; *q != '\0'; )
3429 Interpret graphic primitive.
3431 GetMagickToken(q,&q,keyword);
3432 if (*keyword == '\0')
3434 if (*keyword == '#')
3439 if (active != MagickFalse)
3441 AffineToTransform(image,&affine);
3444 (void) WriteBlobString(image,"<desc>");
3445 (void) WriteBlobString(image,keyword+1);
3446 for ( ; (*q != '\n') && (*q != '\0'); q++)
3449 case '<': (void) WriteBlobString(image,"<"); break;
3450 case '>': (void) WriteBlobString(image,">"); break;
3451 case '&': (void) WriteBlobString(image,"&"); break;
3452 default: (void) WriteBlobByte(image,*q); break;
3454 (void) WriteBlobString(image,"</desc>\n");
3457 primitive_type=UndefinedPrimitive;
3465 if (LocaleCompare("affine",keyword) == 0)
3467 GetMagickToken(q,&q,token);
3468 affine.sx=atof(token);
3469 GetMagickToken(q,&q,token);
3471 GetMagickToken(q,&q,token);
3472 affine.rx=atof(token);
3473 GetMagickToken(q,&q,token);
3475 GetMagickToken(q,&q,token);
3476 affine.ry=atof(token);
3477 GetMagickToken(q,&q,token);
3479 GetMagickToken(q,&q,token);
3480 affine.sy=atof(token);
3481 GetMagickToken(q,&q,token);
3483 GetMagickToken(q,&q,token);
3484 affine.tx=atof(token);
3485 GetMagickToken(q,&q,token);
3487 GetMagickToken(q,&q,token);
3488 affine.ty=atof(token);
3491 if (LocaleCompare("angle",keyword) == 0)
3493 GetMagickToken(q,&q,token);
3494 affine.rx=atof(token);
3495 affine.ry=atof(token);
3498 if (LocaleCompare("arc",keyword) == 0)
3500 primitive_type=ArcPrimitive;
3509 if (LocaleCompare("bezier",keyword) == 0)
3511 primitive_type=BezierPrimitive;
3520 if (LocaleCompare("clip-path",keyword) == 0)
3522 GetMagickToken(q,&q,token);
3523 (void) FormatMagickString(message,MaxTextExtent,
3524 "clip-path:url(#%s);",token);
3525 (void) WriteBlobString(image,message);
3528 if (LocaleCompare("clip-rule",keyword) == 0)
3530 GetMagickToken(q,&q,token);
3531 (void) FormatMagickString(message,MaxTextExtent,
3532 "clip-rule:%s;",token);
3533 (void) WriteBlobString(image,message);
3536 if (LocaleCompare("clip-units",keyword) == 0)
3538 GetMagickToken(q,&q,token);
3539 (void) FormatMagickString(message,MaxTextExtent,
3540 "clipPathUnits=%s;",token);
3541 (void) WriteBlobString(image,message);
3544 if (LocaleCompare("circle",keyword) == 0)
3546 primitive_type=CirclePrimitive;
3549 if (LocaleCompare("color",keyword) == 0)
3551 primitive_type=ColorPrimitive;
3560 if (LocaleCompare("decorate",keyword) == 0)
3562 GetMagickToken(q,&q,token);
3563 (void) FormatMagickString(message,MaxTextExtent,
3564 "text-decoration:%s;",token);
3565 (void) WriteBlobString(image,message);
3574 if (LocaleCompare("ellipse",keyword) == 0)
3576 primitive_type=EllipsePrimitive;
3585 if (LocaleCompare("fill",keyword) == 0)
3587 GetMagickToken(q,&q,token);
3588 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3590 (void) WriteBlobString(image,message);
3593 if (LocaleCompare("fill-rule",keyword) == 0)
3595 GetMagickToken(q,&q,token);
3596 (void) FormatMagickString(message,MaxTextExtent,
3597 "fill-rule:%s;",token);
3598 (void) WriteBlobString(image,message);
3601 if (LocaleCompare("fill-opacity",keyword) == 0)
3603 GetMagickToken(q,&q,token);
3604 (void) FormatMagickString(message,MaxTextExtent,
3605 "fill-opacity:%s;",token);
3606 (void) WriteBlobString(image,message);
3609 if (LocaleCompare("font-family",keyword) == 0)
3611 GetMagickToken(q,&q,token);
3612 (void) FormatMagickString(message,MaxTextExtent,
3613 "font-family:%s;",token);
3614 (void) WriteBlobString(image,message);
3617 if (LocaleCompare("font-stretch",keyword) == 0)
3619 GetMagickToken(q,&q,token);
3620 (void) FormatMagickString(message,MaxTextExtent,
3621 "font-stretch:%s;",token);
3622 (void) WriteBlobString(image,message);
3625 if (LocaleCompare("font-style",keyword) == 0)
3627 GetMagickToken(q,&q,token);
3628 (void) FormatMagickString(message,MaxTextExtent,
3629 "font-style:%s;",token);
3630 (void) WriteBlobString(image,message);
3633 if (LocaleCompare("font-size",keyword) == 0)
3635 GetMagickToken(q,&q,token);
3636 (void) FormatMagickString(message,MaxTextExtent,
3637 "font-size:%s;",token);
3638 (void) WriteBlobString(image,message);
3641 if (LocaleCompare("font-weight",keyword) == 0)
3643 GetMagickToken(q,&q,token);
3644 (void) FormatMagickString(message,MaxTextExtent,
3645 "font-weight:%s;",token);
3646 (void) WriteBlobString(image,message);
3655 if (LocaleCompare("gradient-units",keyword) == 0)
3657 GetMagickToken(q,&q,token);
3660 if (LocaleCompare("text-align",keyword) == 0)
3662 GetMagickToken(q,&q,token);
3663 (void) FormatMagickString(message,MaxTextExtent,
3664 "text-align %s ",token);
3665 (void) WriteBlobString(image,message);
3668 if (LocaleCompare("text-anchor",keyword) == 0)
3670 GetMagickToken(q,&q,token);
3671 (void) FormatMagickString(message,MaxTextExtent,
3672 "text-anchor %s ",token);
3673 (void) WriteBlobString(image,message);
3682 if (LocaleCompare("image",keyword) == 0)
3684 GetMagickToken(q,&q,token);
3685 primitive_type=ImagePrimitive;
3694 if (LocaleCompare("line",keyword) == 0)
3696 primitive_type=LinePrimitive;
3705 if (LocaleCompare("matte",keyword) == 0)
3707 primitive_type=MattePrimitive;
3716 if (LocaleCompare("opacity",keyword) == 0)
3718 GetMagickToken(q,&q,token);
3719 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3721 (void) WriteBlobString(image,message);
3730 if (LocaleCompare("path",keyword) == 0)
3732 primitive_type=PathPrimitive;
3735 if (LocaleCompare("point",keyword) == 0)
3737 primitive_type=PointPrimitive;
3740 if (LocaleCompare("polyline",keyword) == 0)
3742 primitive_type=PolylinePrimitive;
3745 if (LocaleCompare("polygon",keyword) == 0)
3747 primitive_type=PolygonPrimitive;
3750 if (LocaleCompare("pop",keyword) == 0)
3752 GetMagickToken(q,&q,token);
3753 if (LocaleCompare("clip-path",token) == 0)
3755 (void) WriteBlobString(image,"</clipPath>\n");
3758 if (LocaleCompare("defs",token) == 0)
3760 (void) WriteBlobString(image,"</defs>\n");
3763 if (LocaleCompare("gradient",token) == 0)
3765 (void) FormatMagickString(message,MaxTextExtent,
3766 "</%sGradient>\n",type);
3767 (void) WriteBlobString(image,message);
3770 if (LocaleCompare("graphic-context",token) == 0)
3774 ThrowWriterException(DrawError,
3775 "UnbalancedGraphicContextPushPop");
3776 (void) WriteBlobString(image,"</g>\n");
3778 if (LocaleCompare("pattern",token) == 0)
3780 (void) WriteBlobString(image,"</pattern>\n");
3783 if (LocaleCompare("defs",token) == 0)
3784 (void) WriteBlobString(image,"</g>\n");
3787 if (LocaleCompare("push",keyword) == 0)
3789 GetMagickToken(q,&q,token);
3790 if (LocaleCompare("clip-path",token) == 0)
3792 GetMagickToken(q,&q,token);
3793 (void) FormatMagickString(message,MaxTextExtent,
3794 "<clipPath id=\"%s\">\n",token);
3795 (void) WriteBlobString(image,message);
3798 if (LocaleCompare("defs",token) == 0)
3800 (void) WriteBlobString(image,"<defs>\n");
3803 if (LocaleCompare("gradient",token) == 0)
3805 GetMagickToken(q,&q,token);
3806 (void) CopyMagickString(name,token,MaxTextExtent);
3807 GetMagickToken(q,&q,token);
3808 (void) CopyMagickString(type,token,MaxTextExtent);
3809 GetMagickToken(q,&q,token);
3810 svg_info.segment.x1=atof(token);
3811 svg_info.element.cx=atof(token);
3812 GetMagickToken(q,&q,token);
3814 GetMagickToken(q,&q,token);
3815 svg_info.segment.y1=atof(token);
3816 svg_info.element.cy=atof(token);
3817 GetMagickToken(q,&q,token);
3819 GetMagickToken(q,&q,token);
3820 svg_info.segment.x2=atof(token);
3821 svg_info.element.major=atof(token);
3822 GetMagickToken(q,&q,token);
3824 GetMagickToken(q,&q,token);
3825 svg_info.segment.y2=atof(token);
3826 svg_info.element.minor=atof(token);
3827 (void) FormatMagickString(message,MaxTextExtent,
3828 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3829 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3830 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3831 if (LocaleCompare(type,"radial") == 0)
3833 GetMagickToken(q,&q,token);
3835 GetMagickToken(q,&q,token);
3836 svg_info.element.angle=atof(token);
3837 (void) FormatMagickString(message,MaxTextExtent,
3838 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3839 "fx=\"%g\" fy=\"%g\">\n",type,name,svg_info.element.cx,
3840 svg_info.element.cy,svg_info.element.angle,
3841 svg_info.element.major,svg_info.element.minor);
3843 (void) WriteBlobString(image,message);
3846 if (LocaleCompare("graphic-context",token) == 0)
3851 AffineToTransform(image,&affine);
3854 (void) WriteBlobString(image,"<g style=\"");
3857 if (LocaleCompare("pattern",token) == 0)
3859 GetMagickToken(q,&q,token);
3860 (void) CopyMagickString(name,token,MaxTextExtent);
3861 GetMagickToken(q,&q,token);
3862 svg_info.bounds.x=atof(token);
3863 GetMagickToken(q,&q,token);
3865 GetMagickToken(q,&q,token);
3866 svg_info.bounds.y=atof(token);
3867 GetMagickToken(q,&q,token);
3869 GetMagickToken(q,&q,token);
3870 svg_info.bounds.width=atof(token);
3871 GetMagickToken(q,&q,token);
3873 GetMagickToken(q,&q,token);
3874 svg_info.bounds.height=atof(token);
3875 (void) FormatMagickString(message,MaxTextExtent,
3876 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3877 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
3878 svg_info.bounds.width,svg_info.bounds.height);
3879 (void) WriteBlobString(image,message);
3890 if (LocaleCompare("rectangle",keyword) == 0)
3892 primitive_type=RectanglePrimitive;
3895 if (LocaleCompare("roundRectangle",keyword) == 0)
3897 primitive_type=RoundRectanglePrimitive;
3900 if (LocaleCompare("rotate",keyword) == 0)
3902 GetMagickToken(q,&q,token);
3903 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3905 (void) WriteBlobString(image,message);
3914 if (LocaleCompare("scale",keyword) == 0)
3916 GetMagickToken(q,&q,token);
3917 affine.sx=atof(token);
3918 GetMagickToken(q,&q,token);
3920 GetMagickToken(q,&q,token);
3921 affine.sy=atof(token);
3924 if (LocaleCompare("skewX",keyword) == 0)
3926 GetMagickToken(q,&q,token);
3927 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3929 (void) WriteBlobString(image,message);
3932 if (LocaleCompare("skewY",keyword) == 0)
3934 GetMagickToken(q,&q,token);
3935 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3937 (void) WriteBlobString(image,message);
3940 if (LocaleCompare("stop-color",keyword) == 0)
3943 color[MaxTextExtent];
3945 GetMagickToken(q,&q,token);
3946 (void) CopyMagickString(color,token,MaxTextExtent);
3947 GetMagickToken(q,&q,token);
3948 (void) FormatMagickString(message,MaxTextExtent,
3949 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3950 (void) WriteBlobString(image,message);
3953 if (LocaleCompare("stroke",keyword) == 0)
3955 GetMagickToken(q,&q,token);
3956 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
3958 (void) WriteBlobString(image,message);
3961 if (LocaleCompare("stroke-antialias",keyword) == 0)
3963 GetMagickToken(q,&q,token);
3964 (void) FormatMagickString(message,MaxTextExtent,
3965 "stroke-antialias:%s;",token);
3966 (void) WriteBlobString(image,message);
3969 if (LocaleCompare("stroke-dasharray",keyword) == 0)
3977 GetMagickToken(p,&p,token);
3978 for (k=0; IsPoint(token); k++)
3979 GetMagickToken(p,&p,token);
3980 (void) WriteBlobString(image,"stroke-dasharray:");
3981 for (j=0; j < k; j++)
3983 GetMagickToken(q,&q,token);
3984 (void) FormatMagickString(message,MaxTextExtent,"%s ",
3986 (void) WriteBlobString(image,message);
3988 (void) WriteBlobString(image,";");
3991 GetMagickToken(q,&q,token);
3992 (void) FormatMagickString(message,MaxTextExtent,
3993 "stroke-dasharray:%s;",token);
3994 (void) WriteBlobString(image,message);
3997 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
3999 GetMagickToken(q,&q,token);
4000 (void) FormatMagickString(message,MaxTextExtent,
4001 "stroke-dashoffset:%s;",token);
4002 (void) WriteBlobString(image,message);
4005 if (LocaleCompare("stroke-linecap",keyword) == 0)
4007 GetMagickToken(q,&q,token);
4008 (void) FormatMagickString(message,MaxTextExtent,
4009 "stroke-linecap:%s;",token);
4010 (void) WriteBlobString(image,message);
4013 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4015 GetMagickToken(q,&q,token);
4016 (void) FormatMagickString(message,MaxTextExtent,
4017 "stroke-linejoin:%s;",token);
4018 (void) WriteBlobString(image,message);
4021 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4023 GetMagickToken(q,&q,token);
4024 (void) FormatMagickString(message,MaxTextExtent,
4025 "stroke-miterlimit:%s;",token);
4026 (void) WriteBlobString(image,message);
4029 if (LocaleCompare("stroke-opacity",keyword) == 0)
4031 GetMagickToken(q,&q,token);
4032 (void) FormatMagickString(message,MaxTextExtent,
4033 "stroke-opacity:%s;",token);
4034 (void) WriteBlobString(image,message);
4037 if (LocaleCompare("stroke-width",keyword) == 0)
4039 GetMagickToken(q,&q,token);
4040 (void) FormatMagickString(message,MaxTextExtent,
4041 "stroke-width:%s;",token);
4042 (void) WriteBlobString(image,message);
4051 if (LocaleCompare("text",keyword) == 0)
4053 primitive_type=TextPrimitive;
4056 if (LocaleCompare("text-antialias",keyword) == 0)
4058 GetMagickToken(q,&q,token);
4059 (void) FormatMagickString(message,MaxTextExtent,
4060 "text-antialias:%s;",token);
4061 (void) WriteBlobString(image,message);
4064 if (LocaleCompare("tspan",keyword) == 0)
4066 primitive_type=TextPrimitive;
4069 if (LocaleCompare("translate",keyword) == 0)
4071 GetMagickToken(q,&q,token);
4072 affine.tx=atof(token);
4073 GetMagickToken(q,&q,token);
4075 GetMagickToken(q,&q,token);
4076 affine.ty=atof(token);
4085 if (LocaleCompare("viewbox",keyword) == 0)
4087 GetMagickToken(q,&q,token);
4089 GetMagickToken(q,&q,token);
4090 GetMagickToken(q,&q,token);
4092 GetMagickToken(q,&q,token);
4093 GetMagickToken(q,&q,token);
4095 GetMagickToken(q,&q,token);
4096 GetMagickToken(q,&q,token);
4108 if (status == MagickFalse)
4110 if (primitive_type == UndefinedPrimitive)
4113 Parse the primitive attributes.
4117 for (x=0; *q != '\0'; x++)
4122 if (IsPoint(q) == MagickFalse)
4124 GetMagickToken(q,&q,token);
4125 point.x=atof(token);
4126 GetMagickToken(q,&q,token);
4128 GetMagickToken(q,&q,token);
4129 point.y=atof(token);
4130 GetMagickToken(q,(const char **) NULL,token);
4132 GetMagickToken(q,&q,token);
4133 primitive_info[i].primitive=primitive_type;
4134 primitive_info[i].point=point;
4135 primitive_info[i].coordinates=0;
4136 primitive_info[i].method=FloodfillMethod;
4138 if (i < (long) (number_points-6*BezierQuantum-360))
4140 number_points+=6*BezierQuantum+360;
4141 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4142 number_points,sizeof(*primitive_info));
4143 if (primitive_info == (PrimitiveInfo *) NULL)
4145 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4146 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4150 primitive_info[j].primitive=primitive_type;
4151 primitive_info[j].coordinates=x;
4152 primitive_info[j].method=FloodfillMethod;
4153 primitive_info[j].text=(char *) NULL;
4156 AffineToTransform(image,&affine);
4160 switch (primitive_type)
4162 case PointPrimitive:
4165 if (primitive_info[j].coordinates != 1)
4174 if (primitive_info[j].coordinates != 2)
4179 (void) FormatMagickString(message,MaxTextExtent,
4180 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4181 primitive_info[j].point.x,primitive_info[j].point.y,
4182 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4183 (void) WriteBlobString(image,message);
4186 case RectanglePrimitive:
4188 if (primitive_info[j].coordinates != 2)
4193 (void) FormatMagickString(message,MaxTextExtent,
4194 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4195 primitive_info[j].point.x,primitive_info[j].point.y,
4196 primitive_info[j+1].point.x-primitive_info[j].point.x,
4197 primitive_info[j+1].point.y-primitive_info[j].point.y);
4198 (void) WriteBlobString(image,message);
4201 case RoundRectanglePrimitive:
4203 if (primitive_info[j].coordinates != 3)
4208 (void) FormatMagickString(message,MaxTextExtent,
4209 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4210 "ry=\"%g\"/>\n",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 primitive_info[j+2].point.x,primitive_info[j+2].point.y);
4214 (void) WriteBlobString(image,message);
4219 if (primitive_info[j].coordinates != 3)
4226 case EllipsePrimitive:
4228 if (primitive_info[j].coordinates != 3)
4233 (void) FormatMagickString(message,MaxTextExtent,
4234 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4235 primitive_info[j].point.x,primitive_info[j].point.y,
4236 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4237 (void) WriteBlobString(image,message);
4240 case CirclePrimitive:
4246 if (primitive_info[j].coordinates != 2)
4251 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4252 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4253 (void) FormatMagickString(message,MaxTextExtent,
4254 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4255 primitive_info[j].point.x,primitive_info[j].point.y,
4257 (void) WriteBlobString(image,message);
4260 case PolylinePrimitive:
4262 if (primitive_info[j].coordinates < 2)
4267 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4268 (void) WriteBlobString(image,message);
4269 length=strlen(message);
4272 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4273 primitive_info[j].point.x,primitive_info[j].point.y);
4274 length+=strlen(message);
4277 (void) WriteBlobString(image,"\n ");
4278 length=strlen(message)+5;
4280 (void) WriteBlobString(image,message);
4282 (void) WriteBlobString(image,"\"/>\n");
4285 case PolygonPrimitive:
4287 if (primitive_info[j].coordinates < 3)
4292 primitive_info[i]=primitive_info[j];
4293 primitive_info[i].coordinates=0;
4294 primitive_info[j].coordinates++;
4296 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4297 (void) WriteBlobString(image,message);
4298 length=strlen(message);
4301 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4302 primitive_info[j].point.x,primitive_info[j].point.y);
4303 length+=strlen(message);
4306 (void) WriteBlobString(image,"\n ");
4307 length=strlen(message)+5;
4309 (void) WriteBlobString(image,message);
4311 (void) WriteBlobString(image,"\"/>\n");
4314 case BezierPrimitive:
4316 if (primitive_info[j].coordinates < 3)
4328 GetMagickToken(q,&q,token);
4329 number_attributes=1;
4330 for (p=token; *p != '\0'; p++)
4331 if (isalpha((int) *p))
4332 number_attributes++;
4333 if (i > (long) (number_points-6*BezierQuantum*number_attributes-1))
4335 number_points+=6*BezierQuantum*number_attributes;
4336 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4337 number_points,sizeof(*primitive_info));
4338 if (primitive_info == (PrimitiveInfo *) NULL)
4340 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4341 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4346 (void) WriteBlobString(image," <path d=\"");
4347 (void) WriteBlobString(image,token);
4348 (void) WriteBlobString(image,"\"/>\n");
4351 case ColorPrimitive:
4352 case MattePrimitive:
4354 if (primitive_info[j].coordinates != 1)
4359 GetMagickToken(q,&q,token);
4360 if (LocaleCompare("point",token) == 0)
4361 primitive_info[j].method=PointMethod;
4362 if (LocaleCompare("replace",token) == 0)
4363 primitive_info[j].method=ReplaceMethod;
4364 if (LocaleCompare("floodfill",token) == 0)
4365 primitive_info[j].method=FloodfillMethod;
4366 if (LocaleCompare("filltoborder",token) == 0)
4367 primitive_info[j].method=FillToBorderMethod;
4368 if (LocaleCompare("reset",token) == 0)
4369 primitive_info[j].method=ResetMethod;
4377 if (primitive_info[j].coordinates != 1)
4382 GetMagickToken(q,&q,token);
4383 (void) FormatMagickString(message,MaxTextExtent,
4384 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4385 primitive_info[j].point.y);
4386 (void) WriteBlobString(image,message);
4387 for (p=token; *p != '\0'; p++)
4390 case '<': (void) WriteBlobString(image,"<"); break;
4391 case '>': (void) WriteBlobString(image,">"); break;
4392 case '&': (void) WriteBlobString(image,"&"); break;
4393 default: (void) WriteBlobByte(image,*p); break;
4395 (void) WriteBlobString(image,"</text>\n");
4398 case ImagePrimitive:
4400 if (primitive_info[j].coordinates != 2)
4405 GetMagickToken(q,&q,token);
4406 (void) FormatMagickString(message,MaxTextExtent,
4407 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4408 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4409 primitive_info[j].point.y,primitive_info[j+1].point.x,
4410 primitive_info[j+1].point.y,token);
4411 (void) WriteBlobString(image,message);
4415 if (primitive_info == (PrimitiveInfo *) NULL)
4417 primitive_info[i].primitive=UndefinedPrimitive;
4418 if (status == MagickFalse)
4421 (void) WriteBlobString(image,"</svg>\n");
4423 Relinquish resources.
4425 token=DestroyString(token);
4426 if (primitive_info != (PrimitiveInfo *) NULL)
4427 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4428 (void) CloseBlob(image);