2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "magick/studio.h"
44 #include "magick/annotate.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/constitute.h"
51 #include "magick/composite-private.h"
52 #include "magick/draw.h"
53 #include "magick/exception.h"
54 #include "magick/exception-private.h"
55 #include "magick/gem.h"
56 #include "magick/image.h"
57 #include "magick/image-private.h"
58 #include "magick/list.h"
59 #include "magick/log.h"
60 #include "magick/magick.h"
61 #include "magick/memory_.h"
62 #include "magick/module.h"
63 #include "magick/monitor.h"
64 #include "magick/monitor-private.h"
65 #include "magick/quantum-private.h"
66 #include "magick/pixel-private.h"
67 #include "magick/property.h"
68 #include "magick/resource_.h"
69 #include "magick/static.h"
70 #include "magick/string_.h"
71 #include "magick/string-private.h"
72 #include "magick/token.h"
73 #include "magick/utility.h"
74 #if defined(MAGICKCORE_XML_DELEGATE)
75 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
76 # if defined(__MINGW32__)
79 # include <win32config.h>
82 # include <libxml/parser.h>
83 # include <libxml/xmlmemory.h>
84 # include <libxml/parserInternals.h>
85 # include <libxml/xmlerror.h>
88 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
89 #include "autotrace/autotrace.h"
92 #if defined(MAGICKCORE_RSVG_DELEGATE)
93 #include "librsvg/rsvg.h"
94 #if defined(MAGICKCORE_CAIRO_DELEGATE)
95 #include "librsvg/rsvg-cairo.h"
97 #include "librsvg/librsvg-features.h"
103 #define MVGPrintf (void) fprintf
106 Typedef declarations.
108 typedef struct _BoundingBox
117 typedef struct _ElementInfo
127 typedef struct _SVGInfo
181 #if defined(MAGICKCORE_XML_DELEGATE)
191 Forward declarations.
193 static MagickBooleanType
194 WriteSVGImage(const ImageInfo *,Image *);
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 % IsSVG()() returns MagickTrue if the image format type, identified by the
208 % magick string, is SVG.
210 % The format of the IsSVG method is:
212 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
214 % A description of each parameter follows:
216 % o magick: compare image format pattern against these bytes.
218 % o length: Specifies the length of the magick string.
221 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
225 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
230 #if defined(MAGICKCORE_XML_DELEGATE)
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 % R e a d S V G I m a g e %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
243 % allocates the memory necessary for the new Image structure and returns a
244 % pointer to the new image.
246 % The format of the ReadSVGImage method is:
248 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
250 % A description of each parameter follows:
252 % o image_info: the image info.
254 % o exception: return any errors or warnings in this structure.
258 static SVGInfo *AcquireSVGInfo(void)
263 svg_info=(SVGInfo *) AcquireAlignedMemory(1,sizeof(*svg_info));
264 if (svg_info == (SVGInfo *) NULL)
265 return((SVGInfo *) NULL);
266 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
267 svg_info->text=AcquireString("");
268 svg_info->scale=(double *) AcquireAlignedMemory(1,sizeof(*svg_info->scale));
269 if (svg_info->scale == (double *) NULL)
270 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
271 GetAffineMatrix(&svg_info->affine);
272 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
276 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
278 if (svg_info->text != (char *) NULL)
279 svg_info->text=DestroyString(svg_info->text);
280 if (svg_info->scale != (double *) NULL)
281 svg_info->scale=(double *) (svg_info->scale);
282 if (svg_info->title != (char *) NULL)
283 svg_info->title=DestroyString(svg_info->title);
284 if (svg_info->comment != (char *) NULL)
285 svg_info->comment=DestroyString(svg_info->comment);
286 return((SVGInfo *) RelinquishMagickMemory(svg_info));
289 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
293 token[MaxTextExtent];
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
302 assert(string != (const char *) NULL);
303 p=(const char *) string;
304 GetMagickToken(p,&p,token);
305 value=StringToDouble(token);
306 if (strchr(token,'%') != (char *) NULL)
314 if (svg_info->view_box.width == 0.0)
316 return(svg_info->view_box.width*value/100.0);
320 if (svg_info->view_box.height == 0.0)
322 return(svg_info->view_box.height*value/100.0);
324 alpha=value-svg_info->view_box.width;
325 beta=value-svg_info->view_box.height;
326 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
328 GetMagickToken(p,&p,token);
329 if (LocaleNCompare(token,"cm",2) == 0)
330 return(DefaultResolution*svg_info->scale[0]/2.54*value);
331 if (LocaleNCompare(token,"em",2) == 0)
332 return(svg_info->pointsize*value);
333 if (LocaleNCompare(token,"ex",2) == 0)
334 return(svg_info->pointsize*value/2.0);
335 if (LocaleNCompare(token,"in",2) == 0)
336 return(DefaultResolution*svg_info->scale[0]*value);
337 if (LocaleNCompare(token,"mm",2) == 0)
338 return(DefaultResolution*svg_info->scale[0]/25.4*value);
339 if (LocaleNCompare(token,"pc",2) == 0)
340 return(DefaultResolution*svg_info->scale[0]/6.0*value);
341 if (LocaleNCompare(token,"pt",2) == 0)
342 return(svg_info->scale[0]*value);
343 if (LocaleNCompare(token,"px",2) == 0)
348 static void StripStyleTokens(char *message)
357 assert(message != (char *) NULL);
358 if (*message == '\0')
360 length=strlen(message);
362 while (isspace((int) ((unsigned char) *p)) != 0)
365 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
367 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
369 StripString(message);
372 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
384 svg_info=(SVGInfo *) context;
386 if (style == (const char *) NULL)
387 return((char **) NULL);
388 text=AcquireString(style);
389 (void) SubstituteString(&text,":","\n");
390 (void) SubstituteString(&text,";","\n");
391 tokens=StringToList(text);
392 text=DestroyString(text);
393 for (i=0; tokens[i] != (char *) NULL; i++)
394 StripStyleTokens(tokens[i]);
399 static char **GetTransformTokens(void *context,const char *text,
415 svg_info=(SVGInfo *) context;
417 if (text == (const char *) NULL)
418 return((char **) NULL);
420 Determine the number of arguments.
422 for (p=text; *p != '\0'; p++)
427 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
428 if (tokens == (char **) NULL)
430 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
431 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
432 return((char **) NULL);
435 Convert string to an ASCII list.
439 for (q=p; *q != '\0'; q++)
441 if ((*q != '(') && (*q != ')') && (*q != '\0'))
443 tokens[i]=AcquireString(p);
444 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
445 StripString(tokens[i++]);
448 tokens[i]=AcquireString(p);
449 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
450 StripString(tokens[i++]);
451 tokens[i]=(char *) NULL;
455 #if defined(__cplusplus) || defined(c_plusplus)
459 static int SVGIsStandalone(void *context)
465 Is this document tagged standalone?
467 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
468 svg_info=(SVGInfo *) context;
469 return(svg_info->document->standalone == 1);
472 static int SVGHasInternalSubset(void *context)
478 Does this document has an internal subset?
480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
481 " SAX.SVGHasInternalSubset()");
482 svg_info=(SVGInfo *) context;
483 return(svg_info->document->intSubset != NULL);
486 static int SVGHasExternalSubset(void *context)
492 Does this document has an external subset?
494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
495 " SAX.SVGHasExternalSubset()");
496 svg_info=(SVGInfo *) context;
497 return(svg_info->document->extSubset != NULL);
500 static void SVGInternalSubset(void *context,const xmlChar *name,
501 const xmlChar *external_id,const xmlChar *system_id)
507 Does this document has an internal subset?
509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
510 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
511 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
512 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
513 svg_info=(SVGInfo *) context;
514 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
517 static xmlParserInputPtr SVGResolveEntity(void *context,
518 const xmlChar *public_id,const xmlChar *system_id)
527 Special entity resolver, better left to the parser, it has more
528 context than the application layer. The default behaviour is to
529 not resolve the entities, in that case the ENTITY_REF nodes are
530 built in the structure (and the parameter values).
532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
533 " SAX.resolveEntity(%s, %s)",
534 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
535 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
536 svg_info=(SVGInfo *) context;
537 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
538 public_id,svg_info->parser);
542 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
548 Get an entity by name.
550 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
552 svg_info=(SVGInfo *) context;
553 return(xmlGetDocEntity(svg_info->document,name));
556 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
562 Get a parameter entity by name.
564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
565 " SAX.getParameterEntity(%s)",name);
566 svg_info=(SVGInfo *) context;
567 return(xmlGetParameterEntity(svg_info->document,name));
570 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
571 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
577 An entity definition has been parsed.
579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
580 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
581 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
582 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
583 svg_info=(SVGInfo *) context;
584 if (svg_info->parser->inSubset == 1)
585 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
588 if (svg_info->parser->inSubset == 2)
589 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
593 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
594 const xmlChar *name,int type,int value,const xmlChar *default_value,
595 xmlEnumerationPtr tree)
608 An attribute definition has been parsed.
610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
611 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
613 svg_info=(SVGInfo *) context;
614 fullname=(xmlChar *) NULL;
615 prefix=(xmlChar *) NULL;
616 parser=svg_info->parser;
617 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
618 if (parser->inSubset == 1)
619 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
620 element,fullname,prefix,(xmlAttributeType) type,
621 (xmlAttributeDefault) value,default_value,tree);
623 if (parser->inSubset == 2)
624 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
625 element,fullname,prefix,(xmlAttributeType) type,
626 (xmlAttributeDefault) value,default_value,tree);
627 if (prefix != (xmlChar *) NULL)
629 if (fullname != (xmlChar *) NULL)
633 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
634 xmlElementContentPtr content)
643 An element definition has been parsed.
645 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
646 " SAX.elementDecl(%s, %d, ...)",name,type);
647 svg_info=(SVGInfo *) context;
648 parser=svg_info->parser;
649 if (parser->inSubset == 1)
650 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
651 name,(xmlElementTypeVal) type,content);
653 if (parser->inSubset == 2)
654 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
655 name,(xmlElementTypeVal) type,content);
658 static void SVGNotationDeclaration(void *context,const xmlChar *name,
659 const xmlChar *public_id,const xmlChar *system_id)
668 What to do when a notation declaration has been parsed.
670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
671 " SAX.notationDecl(%s, %s, %s)",name,
672 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
673 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
674 svg_info=(SVGInfo *) context;
675 parser=svg_info->parser;
676 if (parser->inSubset == 1)
677 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
678 name,public_id,system_id);
680 if (parser->inSubset == 2)
681 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
682 name,public_id,system_id);
685 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
686 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
692 What to do when an unparsed entity declaration is parsed.
694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
695 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
696 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
697 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
698 svg_info=(SVGInfo *) context;
699 (void) xmlAddDocEntity(svg_info->document,name,
700 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
704 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
710 Receive the document locator at startup, actually xmlDefaultSAXLocator.
713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
714 " SAX.setDocumentLocator()");
715 svg_info=(SVGInfo *) context;
718 static void SVGStartDocument(void *context)
727 Called when the document start being processed.
729 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
730 svg_info=(SVGInfo *) context;
731 GetExceptionInfo(svg_info->exception);
732 parser=svg_info->parser;
733 svg_info->document=xmlNewDoc(parser->version);
734 if (svg_info->document == (xmlDocPtr) NULL)
736 if (parser->encoding == NULL)
737 svg_info->document->encoding=(const xmlChar *) NULL;
739 svg_info->document->encoding=xmlStrdup(parser->encoding);
740 svg_info->document->standalone=parser->standalone;
743 static void SVGEndDocument(void *context)
749 Called when the document end has been detected.
751 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
752 svg_info=(SVGInfo *) context;
753 if (svg_info->offset != (char *) NULL)
754 svg_info->offset=DestroyString(svg_info->offset);
755 if (svg_info->stop_color != (char *) NULL)
756 svg_info->stop_color=DestroyString(svg_info->stop_color);
757 if (svg_info->scale != (double *) NULL)
758 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
759 if (svg_info->text != (char *) NULL)
760 svg_info->text=DestroyString(svg_info->text);
761 if (svg_info->vertices != (char *) NULL)
762 svg_info->vertices=DestroyString(svg_info->vertices);
763 if (svg_info->url != (char *) NULL)
764 svg_info->url=DestroyString(svg_info->url);
765 #if defined(MAGICKCORE_XML_DELEGATE)
766 if (svg_info->document != (xmlDocPtr) NULL)
768 xmlFreeDoc(svg_info->document);
769 svg_info->document=(xmlDocPtr) NULL;
774 static void SVGStartElement(void *context,const xmlChar *name,
775 const xmlChar **attributes)
780 token[MaxTextExtent],
800 Called when an opening tag has been processed.
802 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
804 svg_info=(SVGInfo *) context;
806 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
807 svg_info->n+1UL,sizeof(*svg_info->scale));
808 if (svg_info->scale == (double *) NULL)
810 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
811 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
814 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
815 color=AcquireString("none");
816 units=AcquireString("userSpaceOnUse");
817 value=(const char *) NULL;
818 if (attributes != (const xmlChar **) NULL)
819 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
821 keyword=(const char *) attributes[i];
822 value=(const char *) attributes[i+1];
828 if (LocaleCompare(keyword,"cx") == 0)
830 svg_info->element.cx=
831 GetUserSpaceCoordinateValue(svg_info,1,value);
834 if (LocaleCompare(keyword,"cy") == 0)
836 svg_info->element.cy=
837 GetUserSpaceCoordinateValue(svg_info,-1,value);
845 if (LocaleCompare(keyword,"fx") == 0)
847 svg_info->element.major=
848 GetUserSpaceCoordinateValue(svg_info,1,value);
851 if (LocaleCompare(keyword,"fy") == 0)
853 svg_info->element.minor=
854 GetUserSpaceCoordinateValue(svg_info,-1,value);
862 if (LocaleCompare(keyword,"height") == 0)
864 svg_info->bounds.height=
865 GetUserSpaceCoordinateValue(svg_info,-1,value);
873 if (LocaleCompare(keyword,"id") == 0)
875 (void) CopyMagickString(id,value,MaxTextExtent);
883 if (LocaleCompare(keyword,"r") == 0)
885 svg_info->element.angle=
886 GetUserSpaceCoordinateValue(svg_info,0,value);
894 if (LocaleCompare(keyword,"width") == 0)
896 svg_info->bounds.width=
897 GetUserSpaceCoordinateValue(svg_info,1,value);
905 if (LocaleCompare(keyword,"x") == 0)
907 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
911 if (LocaleCompare(keyword,"x1") == 0)
913 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
917 if (LocaleCompare(keyword,"x2") == 0)
919 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
928 if (LocaleCompare(keyword,"y") == 0)
930 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
934 if (LocaleCompare(keyword,"y1") == 0)
936 svg_info->segment.y1=
937 GetUserSpaceCoordinateValue(svg_info,-1,value);
940 if (LocaleCompare(keyword,"y2") == 0)
942 svg_info->segment.y2=
943 GetUserSpaceCoordinateValue(svg_info,-1,value);
957 if (LocaleCompare((const char *) name,"circle") == 0)
959 MVGPrintf(svg_info->file,"push graphic-context\n");
962 if (LocaleCompare((const char *) name,"clipPath") == 0)
964 MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
972 if (LocaleCompare((const char *) name,"defs") == 0)
974 MVGPrintf(svg_info->file,"push defs\n");
982 if (LocaleCompare((const char *) name,"ellipse") == 0)
984 MVGPrintf(svg_info->file,"push graphic-context\n");
992 if (LocaleCompare((const char *) name,"g") == 0)
994 MVGPrintf(svg_info->file,"push graphic-context\n");
1002 if (LocaleCompare((const char *) name,"image") == 0)
1004 MVGPrintf(svg_info->file,"push graphic-context\n");
1012 if (LocaleCompare((const char *) name,"line") == 0)
1014 MVGPrintf(svg_info->file,"push graphic-context\n");
1017 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1019 MVGPrintf(svg_info->file,
1020 "push gradient '%s' linear %g,%g %g,%g\n",id,
1021 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1022 svg_info->segment.y2);
1030 if (LocaleCompare((const char *) name,"path") == 0)
1032 MVGPrintf(svg_info->file,"push graphic-context\n");
1035 if (LocaleCompare((const char *) name,"pattern") == 0)
1037 MVGPrintf(svg_info->file,
1038 "push pattern '%s' %g,%g %g,%g\n",id,
1039 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1040 svg_info->bounds.height);
1043 if (LocaleCompare((const char *) name,"polygon") == 0)
1045 MVGPrintf(svg_info->file,"push graphic-context\n");
1048 if (LocaleCompare((const char *) name,"polyline") == 0)
1050 MVGPrintf(svg_info->file,"push graphic-context\n");
1058 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1060 MVGPrintf(svg_info->file,
1061 "push gradient '%s' radial %g,%g %g,%g %g\n",
1062 id,svg_info->element.cx,svg_info->element.cy,
1063 svg_info->element.major,svg_info->element.minor,
1064 svg_info->element.angle);
1067 if (LocaleCompare((const char *) name,"rect") == 0)
1069 MVGPrintf(svg_info->file,"push graphic-context\n");
1077 if (LocaleCompare((const char *) name,"svg") == 0)
1079 MVGPrintf(svg_info->file,"push graphic-context\n");
1087 if (LocaleCompare((const char *) name,"text") == 0)
1089 MVGPrintf(svg_info->file,"push graphic-context\n");
1092 if (LocaleCompare((const char *) name,"tspan") == 0)
1094 if (*svg_info->text != '\0')
1105 text=EscapeString(svg_info->text,'\'');
1106 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
1107 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1108 svg_info->center.y,text);
1109 text=DestroyString(text);
1110 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1111 draw_info->pointsize=svg_info->pointsize;
1112 draw_info->text=AcquireString(svg_info->text);
1113 (void) ConcatenateString(&draw_info->text," ");
1114 GetTypeMetrics(svg_info->image,draw_info,&metrics);
1115 svg_info->bounds.x+=metrics.width;
1116 draw_info=DestroyDrawInfo(draw_info);
1117 *svg_info->text='\0';
1119 MVGPrintf(svg_info->file,"push graphic-context\n");
1127 if (attributes != (const xmlChar **) NULL)
1128 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1130 keyword=(const char *) attributes[i];
1131 value=(const char *) attributes[i+1];
1132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1133 " %s = %s",keyword,value);
1139 if (LocaleCompare(keyword,"angle") == 0)
1141 MVGPrintf(svg_info->file,"angle %g\n",
1142 GetUserSpaceCoordinateValue(svg_info,0,value));
1150 if (LocaleCompare(keyword,"clip-path") == 0)
1152 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1155 if (LocaleCompare(keyword,"clip-rule") == 0)
1157 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1160 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1162 (void) CloneString(&units,value);
1163 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1166 if (LocaleCompare(keyword,"color") == 0)
1168 (void) CloneString(&color,value);
1171 if (LocaleCompare(keyword,"cx") == 0)
1173 svg_info->element.cx=
1174 GetUserSpaceCoordinateValue(svg_info,1,value);
1177 if (LocaleCompare(keyword,"cy") == 0)
1179 svg_info->element.cy=
1180 GetUserSpaceCoordinateValue(svg_info,-1,value);
1188 if (LocaleCompare(keyword,"d") == 0)
1190 (void) CloneString(&svg_info->vertices,value);
1193 if (LocaleCompare(keyword,"dx") == 0)
1195 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1198 if (LocaleCompare(keyword,"dy") == 0)
1200 svg_info->bounds.y+=
1201 GetUserSpaceCoordinateValue(svg_info,-1,value);
1209 if (LocaleCompare(keyword,"fill") == 0)
1211 if (LocaleCompare(value,"currentColor") == 0)
1213 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1216 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1219 if (LocaleCompare(keyword,"fillcolor") == 0)
1221 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1224 if (LocaleCompare(keyword,"fill-rule") == 0)
1226 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1229 if (LocaleCompare(keyword,"fill-opacity") == 0)
1231 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1234 if (LocaleCompare(keyword,"font-family") == 0)
1236 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1239 if (LocaleCompare(keyword,"font-stretch") == 0)
1241 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1244 if (LocaleCompare(keyword,"font-style") == 0)
1246 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1249 if (LocaleCompare(keyword,"font-size") == 0)
1251 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1252 MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1255 if (LocaleCompare(keyword,"font-weight") == 0)
1257 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1265 if (LocaleCompare(keyword,"gradientTransform") == 0)
1272 GetAffineMatrix(&transform);
1273 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1274 tokens=GetTransformTokens(context,value,&number_tokens);
1275 for (j=0; j < (number_tokens-1); j+=2)
1277 keyword=(char *) tokens[j];
1278 if (keyword == (char *) NULL)
1280 value=(char *) tokens[j+1];
1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1282 " %s: %s",keyword,value);
1284 GetAffineMatrix(&affine);
1290 if (LocaleCompare(keyword,"matrix") == 0)
1292 p=(const char *) value;
1293 GetMagickToken(p,&p,token);
1294 affine.sx=StringToDouble(value);
1295 GetMagickToken(p,&p,token);
1297 GetMagickToken(p,&p,token);
1298 affine.rx=StringToDouble(token);
1299 GetMagickToken(p,&p,token);
1301 GetMagickToken(p,&p,token);
1302 affine.ry=StringToDouble(token);
1303 GetMagickToken(p,&p,token);
1305 GetMagickToken(p,&p,token);
1306 affine.sy=StringToDouble(token);
1307 GetMagickToken(p,&p,token);
1309 GetMagickToken(p,&p,token);
1310 affine.tx=StringToDouble(token);
1311 GetMagickToken(p,&p,token);
1313 GetMagickToken(p,&p,token);
1314 affine.ty=StringToDouble(token);
1322 if (LocaleCompare(keyword,"rotate") == 0)
1327 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1328 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1329 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1330 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1331 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1339 if (LocaleCompare(keyword,"scale") == 0)
1341 for (p=(const char *) value; *p != '\0'; p++)
1342 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1345 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1346 affine.sy=affine.sx;
1349 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1350 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1353 if (LocaleCompare(keyword,"skewX") == 0)
1355 affine.sx=svg_info->affine.sx;
1356 affine.ry=tan(DegreesToRadians(fmod(
1357 GetUserSpaceCoordinateValue(svg_info,1,value),
1359 affine.sy=svg_info->affine.sy;
1362 if (LocaleCompare(keyword,"skewY") == 0)
1364 affine.sx=svg_info->affine.sx;
1365 affine.rx=tan(DegreesToRadians(fmod(
1366 GetUserSpaceCoordinateValue(svg_info,-1,value),
1368 affine.sy=svg_info->affine.sy;
1376 if (LocaleCompare(keyword,"translate") == 0)
1378 for (p=(const char *) value; *p != '\0'; p++)
1379 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1382 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1383 affine.ty=affine.tx;
1386 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1394 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1395 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1396 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1397 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1398 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1400 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1403 MVGPrintf(svg_info->file,
1404 "affine %g %g %g %g %g %g\n",transform.sx,
1405 transform.rx,transform.ry,transform.sy,transform.tx,
1407 for (j=0; tokens[j] != (char *) NULL; j++)
1408 tokens[j]=DestroyString(tokens[j]);
1409 tokens=(char **) RelinquishMagickMemory(tokens);
1412 if (LocaleCompare(keyword,"gradientUnits") == 0)
1414 (void) CloneString(&units,value);
1415 MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1423 if (LocaleCompare(keyword,"height") == 0)
1425 svg_info->bounds.height=
1426 GetUserSpaceCoordinateValue(svg_info,-1,value);
1429 if (LocaleCompare(keyword,"href") == 0)
1431 (void) CloneString(&svg_info->url,value);
1439 if (LocaleCompare(keyword,"major") == 0)
1441 svg_info->element.major=
1442 GetUserSpaceCoordinateValue(svg_info,1,value);
1445 if (LocaleCompare(keyword,"minor") == 0)
1447 svg_info->element.minor=
1448 GetUserSpaceCoordinateValue(svg_info,-1,value);
1456 if (LocaleCompare(keyword,"offset") == 0)
1458 (void) CloneString(&svg_info->offset,value);
1461 if (LocaleCompare(keyword,"opacity") == 0)
1463 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1471 if (LocaleCompare(keyword,"path") == 0)
1473 (void) CloneString(&svg_info->url,value);
1476 if (LocaleCompare(keyword,"points") == 0)
1478 (void) CloneString(&svg_info->vertices,value);
1486 if (LocaleCompare(keyword,"r") == 0)
1488 svg_info->element.major=
1489 GetUserSpaceCoordinateValue(svg_info,1,value);
1490 svg_info->element.minor=
1491 GetUserSpaceCoordinateValue(svg_info,-1,value);
1494 if (LocaleCompare(keyword,"rotate") == 0)
1499 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1500 MVGPrintf(svg_info->file,"translate %g,%g\n",
1501 svg_info->bounds.x,svg_info->bounds.y);
1502 svg_info->bounds.x=0;
1503 svg_info->bounds.y=0;
1504 MVGPrintf(svg_info->file,"rotate %g\n",angle);
1507 if (LocaleCompare(keyword,"rx") == 0)
1509 if (LocaleCompare((const char *) name,"ellipse") == 0)
1510 svg_info->element.major=
1511 GetUserSpaceCoordinateValue(svg_info,1,value);
1514 GetUserSpaceCoordinateValue(svg_info,1,value);
1517 if (LocaleCompare(keyword,"ry") == 0)
1519 if (LocaleCompare((const char *) name,"ellipse") == 0)
1520 svg_info->element.minor=
1521 GetUserSpaceCoordinateValue(svg_info,-1,value);
1524 GetUserSpaceCoordinateValue(svg_info,-1,value);
1532 if (LocaleCompare(keyword,"stop-color") == 0)
1534 (void) CloneString(&svg_info->stop_color,value);
1537 if (LocaleCompare(keyword,"stroke") == 0)
1539 if (LocaleCompare(value,"currentColor") == 0)
1541 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1544 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1547 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1549 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1550 LocaleCompare(value,"true") == 0);
1553 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1555 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1558 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1560 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1563 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1565 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1568 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1570 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1573 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1575 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1578 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1580 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1583 if (LocaleCompare(keyword,"stroke-width") == 0)
1585 MVGPrintf(svg_info->file,"stroke-width %g\n",
1586 GetUserSpaceCoordinateValue(svg_info,1,value));
1589 if (LocaleCompare(keyword,"style") == 0)
1591 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1592 tokens=GetStyleTokens(context,value,&number_tokens);
1593 for (j=0; j < (number_tokens-1); j+=2)
1595 keyword=(char *) tokens[j];
1596 value=(char *) tokens[j+1];
1597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1598 " %s: %s",keyword,value);
1604 if (LocaleCompare(keyword,"clip-path") == 0)
1606 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1609 if (LocaleCompare(keyword,"clip-rule") == 0)
1611 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1614 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1616 (void) CloneString(&units,value);
1617 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1620 if (LocaleCompare(keyword,"color") == 0)
1622 (void) CloneString(&color,value);
1630 if (LocaleCompare(keyword,"fill") == 0)
1632 if (LocaleCompare(value,"currentColor") == 0)
1634 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1637 if (LocaleCompare(value,"#00000000") == 0)
1638 MVGPrintf(svg_info->file,"fill '#000000'\n");
1640 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1643 if (LocaleCompare(keyword,"fillcolor") == 0)
1645 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1648 if (LocaleCompare(keyword,"fill-rule") == 0)
1650 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1653 if (LocaleCompare(keyword,"fill-opacity") == 0)
1655 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1658 if (LocaleCompare(keyword,"font-family") == 0)
1660 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1663 if (LocaleCompare(keyword,"font-stretch") == 0)
1665 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1668 if (LocaleCompare(keyword,"font-style") == 0)
1670 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1673 if (LocaleCompare(keyword,"font-size") == 0)
1675 svg_info->pointsize=GetUserSpaceCoordinateValue(
1677 MVGPrintf(svg_info->file,"font-size %g\n",
1678 svg_info->pointsize);
1681 if (LocaleCompare(keyword,"font-weight") == 0)
1683 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1691 if (LocaleCompare(keyword,"offset") == 0)
1693 MVGPrintf(svg_info->file,"offset %g\n",
1694 GetUserSpaceCoordinateValue(svg_info,1,value));
1697 if (LocaleCompare(keyword,"opacity") == 0)
1699 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1707 if (LocaleCompare(keyword,"stop-color") == 0)
1709 (void) CloneString(&svg_info->stop_color,value);
1712 if (LocaleCompare(keyword,"stroke") == 0)
1714 if (LocaleCompare(value,"currentColor") == 0)
1716 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1719 if (LocaleCompare(value,"#00000000") == 0)
1720 MVGPrintf(svg_info->file,"fill '#000000'\n");
1722 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1725 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1727 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1728 LocaleCompare(value,"true") == 0);
1731 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1733 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1736 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1738 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1742 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1744 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1747 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1749 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1753 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1755 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1759 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1761 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1764 if (LocaleCompare(keyword,"stroke-width") == 0)
1766 MVGPrintf(svg_info->file,"stroke-width %g\n",
1767 GetUserSpaceCoordinateValue(svg_info,1,value));
1775 if (LocaleCompare(keyword,"text-align") == 0)
1777 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1780 if (LocaleCompare(keyword,"text-anchor") == 0)
1782 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1785 if (LocaleCompare(keyword,"text-decoration") == 0)
1787 if (LocaleCompare(value,"underline") == 0)
1788 MVGPrintf(svg_info->file,"decorate underline\n");
1789 if (LocaleCompare(value,"line-through") == 0)
1790 MVGPrintf(svg_info->file,"decorate line-through\n");
1791 if (LocaleCompare(value,"overline") == 0)
1792 MVGPrintf(svg_info->file,"decorate overline\n");
1795 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1797 MVGPrintf(svg_info->file,"text-antialias %d\n",
1798 LocaleCompare(value,"true") == 0);
1807 for (j=0; tokens[j] != (char *) NULL; j++)
1808 tokens[j]=DestroyString(tokens[j]);
1809 tokens=(char **) RelinquishMagickMemory(tokens);
1817 if (LocaleCompare(keyword,"text-align") == 0)
1819 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1822 if (LocaleCompare(keyword,"text-anchor") == 0)
1824 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1827 if (LocaleCompare(keyword,"text-decoration") == 0)
1829 if (LocaleCompare(value,"underline") == 0)
1830 MVGPrintf(svg_info->file,"decorate underline\n");
1831 if (LocaleCompare(value,"line-through") == 0)
1832 MVGPrintf(svg_info->file,"decorate line-through\n");
1833 if (LocaleCompare(value,"overline") == 0)
1834 MVGPrintf(svg_info->file,"decorate overline\n");
1837 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1839 MVGPrintf(svg_info->file,"text-antialias %d\n",
1840 LocaleCompare(value,"true") == 0);
1843 if (LocaleCompare(keyword,"transform") == 0)
1850 GetAffineMatrix(&transform);
1851 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1852 tokens=GetTransformTokens(context,value,&number_tokens);
1853 for (j=0; j < (number_tokens-1); j+=2)
1855 keyword=(char *) tokens[j];
1856 value=(char *) tokens[j+1];
1857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1858 " %s: %s",keyword,value);
1860 GetAffineMatrix(&affine);
1866 if (LocaleCompare(keyword,"matrix") == 0)
1868 p=(const char *) value;
1869 GetMagickToken(p,&p,token);
1870 affine.sx=StringToDouble(value);
1871 GetMagickToken(p,&p,token);
1873 GetMagickToken(p,&p,token);
1874 affine.rx=StringToDouble(token);
1875 GetMagickToken(p,&p,token);
1877 GetMagickToken(p,&p,token);
1878 affine.ry=StringToDouble(token);
1879 GetMagickToken(p,&p,token);
1881 GetMagickToken(p,&p,token);
1882 affine.sy=StringToDouble(token);
1883 GetMagickToken(p,&p,token);
1885 GetMagickToken(p,&p,token);
1886 affine.tx=StringToDouble(token);
1887 GetMagickToken(p,&p,token);
1889 GetMagickToken(p,&p,token);
1890 affine.ty=StringToDouble(token);
1898 if (LocaleCompare(keyword,"rotate") == 0)
1905 p=(const char *) value;
1906 GetMagickToken(p,&p,token);
1907 angle=StringToDouble(value);
1908 GetMagickToken(p,&p,token);
1910 GetMagickToken(p,&p,token);
1911 x=StringToDouble(token);
1912 GetMagickToken(p,&p,token);
1914 GetMagickToken(p,&p,token);
1915 y=StringToDouble(token);
1916 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1917 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1918 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1919 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1922 svg_info->center.x=x;
1923 svg_info->center.y=y;
1931 if (LocaleCompare(keyword,"scale") == 0)
1933 for (p=(const char *) value; *p != '\0'; p++)
1934 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1937 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1938 affine.sy=affine.sx;
1940 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1942 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1945 if (LocaleCompare(keyword,"skewX") == 0)
1947 affine.sx=svg_info->affine.sx;
1948 affine.ry=tan(DegreesToRadians(fmod(
1949 GetUserSpaceCoordinateValue(svg_info,1,value),
1951 affine.sy=svg_info->affine.sy;
1954 if (LocaleCompare(keyword,"skewY") == 0)
1956 affine.sx=svg_info->affine.sx;
1957 affine.rx=tan(DegreesToRadians(fmod(
1958 GetUserSpaceCoordinateValue(svg_info,-1,value),
1960 affine.sy=svg_info->affine.sy;
1968 if (LocaleCompare(keyword,"translate") == 0)
1970 for (p=(const char *) value; *p != '\0'; p++)
1971 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1974 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1975 affine.ty=affine.tx;
1977 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
1986 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1987 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1988 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1989 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1990 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1992 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1995 MVGPrintf(svg_info->file,
1996 "affine %g %g %g %g %g %g\n",transform.sx,
1997 transform.rx,transform.ry,transform.sy,transform.tx,
1999 for (j=0; tokens[j] != (char *) NULL; j++)
2000 tokens[j]=DestroyString(tokens[j]);
2001 tokens=(char **) RelinquishMagickMemory(tokens);
2009 if (LocaleCompare(keyword,"verts") == 0)
2011 (void) CloneString(&svg_info->vertices,value);
2014 if (LocaleCompare(keyword,"viewBox") == 0)
2016 p=(const char *) value;
2017 GetMagickToken(p,&p,token);
2018 svg_info->view_box.x=StringToDouble(token);
2019 GetMagickToken(p,&p,token);
2021 GetMagickToken(p,&p,token);
2022 svg_info->view_box.y=StringToDouble(token);
2023 GetMagickToken(p,&p,token);
2025 GetMagickToken(p,&p,token);
2026 svg_info->view_box.width=StringToDouble(token);
2027 if (svg_info->bounds.width == 0)
2028 svg_info->bounds.width=svg_info->view_box.width;
2029 GetMagickToken(p,&p,token);
2031 GetMagickToken(p,&p,token);
2032 svg_info->view_box.height=StringToDouble(token);
2033 if (svg_info->bounds.height == 0)
2034 svg_info->bounds.height=svg_info->view_box.height;
2042 if (LocaleCompare(keyword,"width") == 0)
2044 svg_info->bounds.width=
2045 GetUserSpaceCoordinateValue(svg_info,1,value);
2053 if (LocaleCompare(keyword,"x") == 0)
2055 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2058 if (LocaleCompare(keyword,"xlink:href") == 0)
2060 (void) CloneString(&svg_info->url,value);
2063 if (LocaleCompare(keyword,"x1") == 0)
2065 svg_info->segment.x1=
2066 GetUserSpaceCoordinateValue(svg_info,1,value);
2069 if (LocaleCompare(keyword,"x2") == 0)
2071 svg_info->segment.x2=
2072 GetUserSpaceCoordinateValue(svg_info,1,value);
2080 if (LocaleCompare(keyword,"y") == 0)
2082 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2085 if (LocaleCompare(keyword,"y1") == 0)
2087 svg_info->segment.y1=
2088 GetUserSpaceCoordinateValue(svg_info,-1,value);
2091 if (LocaleCompare(keyword,"y2") == 0)
2093 svg_info->segment.y2=
2094 GetUserSpaceCoordinateValue(svg_info,-1,value);
2103 if (LocaleCompare((const char *) name,"svg") == 0)
2105 if (svg_info->document->encoding != (const xmlChar *) NULL)
2106 MVGPrintf(svg_info->file,"encoding \"%s\"\n",
2107 (const char *) svg_info->document->encoding);
2108 if (attributes != (const xmlChar **) NULL)
2114 if ((svg_info->view_box.width == 0.0) ||
2115 (svg_info->view_box.height == 0.0))
2116 svg_info->view_box=svg_info->bounds;
2117 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2118 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2119 MVGPrintf(svg_info->file,"viewbox 0 0 %lu %lu\n",svg_info->width,
2121 sx=(double) svg_info->width/svg_info->view_box.width;
2122 sy=(double) svg_info->height/svg_info->view_box.height;
2123 MVGPrintf(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",sx,sy);
2126 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2127 units=DestroyString(units);
2128 if (color != (char *) NULL)
2129 color=DestroyString(color);
2132 static void SVGEndElement(void *context,const xmlChar *name)
2138 Called when the end of an element has been detected.
2140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2141 " SAX.endElement(%s)",name);
2142 svg_info=(SVGInfo *) context;
2148 if (LocaleCompare((const char *) name,"circle") == 0)
2150 MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",
2151 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2152 svg_info->element.cy+svg_info->element.minor);
2153 MVGPrintf(svg_info->file,"pop graphic-context\n");
2156 if (LocaleCompare((const char *) name,"clipPath") == 0)
2158 MVGPrintf(svg_info->file,"pop clip-path\n");
2166 if (LocaleCompare((const char *) name,"defs") == 0)
2168 MVGPrintf(svg_info->file,"pop defs\n");
2171 if (LocaleCompare((const char *) name,"desc") == 0)
2176 if (*svg_info->text == '\0')
2178 (void) fputc('#',svg_info->file);
2179 for (p=svg_info->text; *p != '\0'; p++)
2181 (void) fputc(*p,svg_info->file);
2183 (void) fputc('#',svg_info->file);
2185 (void) fputc('\n',svg_info->file);
2186 *svg_info->text='\0';
2194 if (LocaleCompare((const char *) name,"ellipse") == 0)
2199 angle=svg_info->element.angle;
2200 MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2201 svg_info->element.cx,svg_info->element.cy,
2202 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2203 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2204 MVGPrintf(svg_info->file,"pop graphic-context\n");
2212 if (LocaleCompare((const char *) name,"g") == 0)
2214 MVGPrintf(svg_info->file,"pop graphic-context\n");
2222 if (LocaleCompare((const char *) name,"image") == 0)
2224 MVGPrintf(svg_info->file,"image Over %g,%g %g,%g '%s'\n",
2225 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2226 svg_info->bounds.height,svg_info->url);
2227 MVGPrintf(svg_info->file,"pop graphic-context\n");
2235 if (LocaleCompare((const char *) name,"line") == 0)
2237 MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",
2238 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2239 svg_info->segment.y2);
2240 MVGPrintf(svg_info->file,"pop graphic-context\n");
2243 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2245 MVGPrintf(svg_info->file,"pop gradient\n");
2253 if (LocaleCompare((const char *) name,"pattern") == 0)
2255 MVGPrintf(svg_info->file,"pop pattern\n");
2258 if (LocaleCompare((const char *) name,"path") == 0)
2260 MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2261 MVGPrintf(svg_info->file,"pop graphic-context\n");
2264 if (LocaleCompare((const char *) name,"polygon") == 0)
2266 MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2267 MVGPrintf(svg_info->file,"pop graphic-context\n");
2270 if (LocaleCompare((const char *) name,"polyline") == 0)
2272 MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2273 MVGPrintf(svg_info->file,"pop graphic-context\n");
2281 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2283 MVGPrintf(svg_info->file,"pop gradient\n");
2286 if (LocaleCompare((const char *) name,"rect") == 0)
2288 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2290 MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2291 svg_info->bounds.x,svg_info->bounds.y,
2292 svg_info->bounds.x+svg_info->bounds.width,
2293 svg_info->bounds.y+svg_info->bounds.height);
2294 MVGPrintf(svg_info->file,"pop graphic-context\n");
2297 if (svg_info->radius.x == 0.0)
2298 svg_info->radius.x=svg_info->radius.y;
2299 if (svg_info->radius.y == 0.0)
2300 svg_info->radius.y=svg_info->radius.x;
2301 MVGPrintf(svg_info->file,
2302 "roundRectangle %g,%g %g,%g %g,%g\n",
2303 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2304 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2305 svg_info->radius.x,svg_info->radius.y);
2306 svg_info->radius.x=0.0;
2307 svg_info->radius.y=0.0;
2308 MVGPrintf(svg_info->file,"pop graphic-context\n");
2316 if (LocaleCompare((const char *) name,"stop") == 0)
2318 MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2322 if (LocaleCompare((const char *) name,"svg") == 0)
2324 MVGPrintf(svg_info->file,"pop graphic-context\n");
2332 if (LocaleCompare((const char *) name,"text") == 0)
2334 if (*svg_info->text != '\0')
2339 text=EscapeString(svg_info->text,'\'');
2341 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
2342 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
2343 svg_info->center.y,text);
2344 text=DestroyString(text);
2345 *svg_info->text='\0';
2347 MVGPrintf(svg_info->file,"pop graphic-context\n");
2350 if (LocaleCompare((const char *) name,"tspan") == 0)
2352 if (*svg_info->text != '\0')
2363 text=EscapeString(svg_info->text,'\'');
2365 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
2366 svg_info->bounds.x,svg_info->bounds.y,text);
2367 text=DestroyString(text);
2368 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2369 draw_info->pointsize=svg_info->pointsize;
2370 draw_info->text=AcquireString(svg_info->text);
2371 (void) ConcatenateString(&draw_info->text," ");
2372 GetTypeMetrics(svg_info->image,draw_info,&metrics);
2373 svg_info->bounds.x+=metrics.width;
2374 draw_info=DestroyDrawInfo(draw_info);
2375 *svg_info->text='\0';
2377 MVGPrintf(svg_info->file,"pop graphic-context\n");
2380 if (LocaleCompare((const char *) name,"title") == 0)
2382 if (*svg_info->text == '\0')
2384 (void) CloneString(&svg_info->title,svg_info->text);
2385 *svg_info->text='\0';
2393 *svg_info->text='\0';
2394 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2395 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2399 static void SVGCharacters(void *context,const xmlChar *c,int length)
2411 Receiving some characters from the parser.
2413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2414 " SAX.characters(%s,%lu)",c,(size_t) length);
2415 svg_info=(SVGInfo *) context;
2416 if (svg_info->text != (char *) NULL)
2417 svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
2418 strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
2421 svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2422 sizeof(*svg_info->text));
2423 if (svg_info->text != (char *) NULL)
2424 *svg_info->text='\0';
2426 if (svg_info->text == (char *) NULL)
2428 p=svg_info->text+strlen(svg_info->text);
2429 for (i=0; i < (ssize_t) length; i++)
2434 static void SVGReference(void *context,const xmlChar *name)
2443 Called when an entity reference is detected.
2445 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2447 svg_info=(SVGInfo *) context;
2448 parser=svg_info->parser;
2449 if (parser == (xmlParserCtxtPtr) NULL)
2451 if (parser->node == (xmlNodePtr) NULL)
2454 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2456 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2459 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2465 Receiving some ignorable whitespaces from the parser.
2467 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2468 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2469 svg_info=(SVGInfo *) context;
2472 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2473 const xmlChar *data)
2479 A processing instruction has been parsed.
2481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2482 " SAX.processingInstruction(%s, %s)",target,data);
2483 svg_info=(SVGInfo *) context;
2486 static void SVGComment(void *context,const xmlChar *value)
2492 A comment has been parsed.
2494 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2496 svg_info=(SVGInfo *) context;
2497 if (svg_info->comment != (char *) NULL)
2498 (void) ConcatenateString(&svg_info->comment,"\n");
2499 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2502 static void SVGWarning(void *context,const char *format,...)
2506 reason[MaxTextExtent];
2515 Display and format a warning messages, gives file, line, position and
2518 va_start(operands,format);
2519 svg_info=(SVGInfo *) context;
2520 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2522 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2523 (void) vsprintf(reason,format,operands);
2525 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2527 message=GetExceptionMessage(errno);
2528 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2529 DelegateWarning,reason,"`%s`",message);
2530 message=DestroyString(message);
2534 static void SVGError(void *context,const char *format,...)
2538 reason[MaxTextExtent];
2547 Display and format a error formats, gives file, line, position and
2550 va_start(operands,format);
2551 svg_info=(SVGInfo *) context;
2552 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2554 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2555 (void) vsprintf(reason,format,operands);
2557 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2559 message=GetExceptionMessage(errno);
2560 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2561 reason,"`%s`",message);
2562 message=DestroyString(message);
2566 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2578 Called when a pcdata block has been parsed.
2580 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2582 svg_info=(SVGInfo *) context;
2583 parser=svg_info->parser;
2584 child=xmlGetLastChild(parser->node);
2585 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2587 xmlTextConcat(child,value,length);
2590 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2593 static void SVGExternalSubset(void *context,const xmlChar *name,
2594 const xmlChar *external_id,const xmlChar *system_id)
2609 Does this document has an external subset?
2611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2612 " SAX.externalSubset(%s, %s, %s)",name,
2613 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2614 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2615 svg_info=(SVGInfo *) context;
2616 parser=svg_info->parser;
2617 if (((external_id == NULL) && (system_id == NULL)) ||
2618 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2619 (svg_info->document == 0)))
2621 input=SVGResolveEntity(context,external_id,system_id);
2624 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2625 parser_context=(*parser);
2626 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2627 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2629 parser->errNo=XML_ERR_NO_MEMORY;
2630 parser->input=parser_context.input;
2631 parser->inputNr=parser_context.inputNr;
2632 parser->inputMax=parser_context.inputMax;
2633 parser->inputTab=parser_context.inputTab;
2639 xmlPushInput(parser,input);
2640 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2641 if (input->filename == (char *) NULL)
2642 input->filename=(char *) xmlStrdup(system_id);
2645 input->base=parser->input->cur;
2646 input->cur=parser->input->cur;
2648 xmlParseExternalSubset(parser,external_id,system_id);
2649 while (parser->inputNr > 1)
2650 (void) xmlPopInput(parser);
2651 xmlFreeInputStream(parser->input);
2652 xmlFree(parser->inputTab);
2653 parser->input=parser_context.input;
2654 parser->inputNr=parser_context.inputNr;
2655 parser->inputMax=parser_context.inputMax;
2656 parser->inputTab=parser_context.inputTab;
2659 #if defined(MAGICKCORE_RSVG_DELEGATE)
2660 static void SVGSetImageSize(int *width,int *height,gpointer context)
2665 image=(Image *) context;
2666 *width=(int) (*width*image->x_resolution/72.0);
2667 *height=(int) (*height*image->y_resolution/72.0);
2671 #if defined(__cplusplus) || defined(c_plusplus)
2675 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2678 filename[MaxTextExtent];
2697 message[MaxTextExtent];
2708 assert(image_info != (const ImageInfo *) NULL);
2709 assert(image_info->signature == MagickSignature);
2710 assert(exception != (ExceptionInfo *) NULL);
2711 if (image_info->debug != MagickFalse)
2712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2713 image_info->filename);
2714 assert(exception->signature == MagickSignature);
2715 image=AcquireImage(image_info);
2716 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2717 if (status == MagickFalse)
2719 image=DestroyImageList(image);
2720 return((Image *) NULL);
2722 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2724 #if defined(MAGICKCORE_RSVG_DELEGATE)
2725 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2732 register unsigned char
2745 register const guchar
2762 register PixelPacket
2768 svg_handle=rsvg_handle_new();
2769 if (svg_handle == (RsvgHandle *) NULL)
2770 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2771 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2772 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2773 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2774 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2775 image->y_resolution);
2776 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2778 error=(GError *) NULL;
2779 (void) rsvg_handle_write(svg_handle,message,n,&error);
2780 if (error != (GError *) NULL)
2781 g_error_free(error);
2783 error=(GError *) NULL;
2784 rsvg_handle_close(svg_handle,&error);
2785 if (error != (GError *) NULL)
2786 g_error_free(error);
2787 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2788 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2789 image->columns=dimension_info.width;
2790 image->rows=dimension_info.height;
2791 pixels=(unsigned char *) NULL;
2793 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2794 rsvg_handle_free(svg_handle);
2795 image->columns=gdk_pixbuf_get_width(pixel_info);
2796 image->rows=gdk_pixbuf_get_height(pixel_info);
2798 image->matte=MagickTrue;
2799 SetImageProperty(image,"svg:base-uri",
2800 rsvg_handle_get_base_uri(svg_handle));
2801 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2802 SetImageProperty(image,"svg:description",
2803 rsvg_handle_get_desc(svg_handle));
2804 if ((image->columns == 0) || (image->rows == 0))
2806 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2807 g_object_unref(G_OBJECT(pixel_info));
2809 g_object_unref(svg_handle);
2810 ThrowReaderException(MissingDelegateError,
2811 "NoDecodeDelegateForThisImageFormat");
2813 if (image_info->ping == MagickFalse)
2815 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2816 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2817 image->rows*sizeof(*pixels));
2818 if (pixels == (unsigned char *) NULL)
2820 g_object_unref(svg_handle);
2821 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2824 (void) SetImageBackgroundColor(image);
2825 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2826 cairo_surface=cairo_image_surface_create_for_data(pixels,
2827 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2828 if (cairo_surface == (cairo_surface_t *) NULL)
2830 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2831 g_object_unref(svg_handle);
2832 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2834 cairo_info=cairo_create(cairo_surface);
2835 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2836 cairo_paint(cairo_info);
2837 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2838 rsvg_handle_render_cairo(svg_handle,cairo_info);
2839 cairo_destroy(cairo_info);
2840 cairo_surface_destroy(cairo_surface);
2841 g_object_unref(svg_handle);
2844 p=gdk_pixbuf_get_pixels(pixel_info);
2846 for (y=0; y < (ssize_t) image->rows; y++)
2848 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2849 if (q == (PixelPacket *) NULL)
2851 for (x=0; x < (ssize_t) image->columns; x++)
2853 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2854 fill_color.blue=ScaleCharToQuantum(*p++);
2855 fill_color.green=ScaleCharToQuantum(*p++);
2856 fill_color.red=ScaleCharToQuantum(*p++);
2858 fill_color.red=ScaleCharToQuantum(*p++);
2859 fill_color.green=ScaleCharToQuantum(*p++);
2860 fill_color.blue=ScaleCharToQuantum(*p++);
2862 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2863 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2868 gamma=1.0-QuantumScale*fill_color.opacity;
2869 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2870 fill_color.blue*=gamma;
2871 fill_color.green*=gamma;
2872 fill_color.red*=gamma;
2875 MagickCompositeOver(&fill_color,fill_color.opacity,q,
2876 (MagickRealType) q->opacity,q);
2879 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2881 if (image->previous == (Image *) NULL)
2883 status=SetImageProgress(image,LoadImageTag,y,image->rows);
2884 if (status == MagickFalse)
2889 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2890 if (pixels != (unsigned char *) NULL)
2891 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2893 g_object_unref(G_OBJECT(pixel_info));
2895 (void) CloseBlob(image);
2896 return(GetFirstImageInList(image));
2903 unique_file=AcquireUniqueFileResource(filename);
2904 if (unique_file != -1)
2905 file=fdopen(unique_file,"w");
2906 if ((unique_file == -1) || (file == (FILE *) NULL))
2908 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2909 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2911 image=DestroyImageList(image);
2912 return((Image *) NULL);
2917 svg_info=AcquireSVGInfo();
2918 if (svg_info == (SVGInfo *) NULL)
2919 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2920 svg_info->file=file;
2921 svg_info->exception=exception;
2922 svg_info->image=image;
2923 svg_info->image_info=image_info;
2924 svg_info->bounds.width=image->columns;
2925 svg_info->bounds.height=image->rows;
2926 if (image_info->size != (char *) NULL)
2927 (void) CloneString(&svg_info->size,image_info->size);
2928 if (image->debug != MagickFalse)
2929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2931 (void) xmlSubstituteEntitiesDefault(1);
2932 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
2933 sax_modules.internalSubset=SVGInternalSubset;
2934 sax_modules.isStandalone=SVGIsStandalone;
2935 sax_modules.hasInternalSubset=SVGHasInternalSubset;
2936 sax_modules.hasExternalSubset=SVGHasExternalSubset;
2937 sax_modules.resolveEntity=SVGResolveEntity;
2938 sax_modules.getEntity=SVGGetEntity;
2939 sax_modules.entityDecl=SVGEntityDeclaration;
2940 sax_modules.notationDecl=SVGNotationDeclaration;
2941 sax_modules.attributeDecl=SVGAttributeDeclaration;
2942 sax_modules.elementDecl=SVGElementDeclaration;
2943 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
2944 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
2945 sax_modules.startDocument=SVGStartDocument;
2946 sax_modules.endDocument=SVGEndDocument;
2947 sax_modules.startElement=SVGStartElement;
2948 sax_modules.endElement=SVGEndElement;
2949 sax_modules.reference=SVGReference;
2950 sax_modules.characters=SVGCharacters;
2951 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
2952 sax_modules.processingInstruction=SVGProcessingInstructions;
2953 sax_modules.comment=SVGComment;
2954 sax_modules.warning=SVGWarning;
2955 sax_modules.error=SVGError;
2956 sax_modules.fatalError=SVGError;
2957 sax_modules.getParameterEntity=SVGGetParameterEntity;
2958 sax_modules.cdataBlock=SVGCDataBlock;
2959 sax_modules.externalSubset=SVGExternalSubset;
2960 sax_handler=(&sax_modules);
2961 n=ReadBlob(image,MaxTextExtent,message);
2964 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2965 message,n,image->filename);
2966 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2968 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2973 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2974 xmlFreeParserCtxt(svg_info->parser);
2975 if (image->debug != MagickFalse)
2976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2978 (void) fclose(file);
2979 (void) CloseBlob(image);
2980 image->columns=svg_info->width;
2981 image->rows=svg_info->height;
2982 if (exception->severity >= ErrorException)
2984 image=DestroyImage(image);
2985 return((Image *) NULL);
2987 if (image_info->ping == MagickFalse)
2995 image=DestroyImage(image);
2996 image=(Image *) NULL;
2997 read_info=CloneImageInfo(image_info);
2998 SetImageInfoBlob(read_info,(void *) NULL,0);
2999 if (read_info->density != (char *) NULL)
3000 read_info->density=DestroyString(read_info->density);
3001 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
3003 image=ReadImage(read_info,exception);
3004 read_info=DestroyImageInfo(read_info);
3005 if (image != (Image *) NULL)
3006 (void) CopyMagickString(image->filename,image_info->filename,
3010 Relinquish resources.
3012 if (image != (Image *) NULL)
3014 if (svg_info->title != (char *) NULL)
3015 (void) SetImageProperty(image,"svg:title",svg_info->title);
3016 if (svg_info->comment != (char *) NULL)
3017 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3019 svg_info=DestroySVGInfo(svg_info);
3020 (void) RelinquishUniqueFileResource(filename);
3021 return(GetFirstImageInList(image));
3026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3030 % R e g i s t e r S V G I m a g e %
3034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3036 % RegisterSVGImage() adds attributes for the SVG image format to
3037 % the list of supported formats. The attributes include the image format
3038 % tag, a method to read and/or write the format, whether the format
3039 % supports the saving of more than one frame to the same file or blob,
3040 % whether the format supports native in-memory I/O, and a brief
3041 % description of the format.
3043 % The format of the RegisterSVGImage method is:
3045 % size_t RegisterSVGImage(void)
3048 ModuleExport size_t RegisterSVGImage(void)
3051 version[MaxTextExtent];
3057 #if defined(LIBXML_DOTTED_VERSION)
3058 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3060 #if defined(MAGICKCORE_RSVG_DELEGATE)
3062 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3063 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3065 entry=SetMagickInfo("SVG");
3066 #if defined(MAGICKCORE_XML_DELEGATE)
3067 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3069 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3070 entry->blob_support=MagickFalse;
3071 entry->seekable_stream=MagickFalse;
3072 entry->description=ConstantString("Scalable Vector Graphics");
3073 if (*version != '\0')
3074 entry->version=ConstantString(version);
3075 entry->magick=(IsImageFormatHandler *) IsSVG;
3076 entry->module=ConstantString("SVG");
3077 (void) RegisterMagickInfo(entry);
3078 entry=SetMagickInfo("SVGZ");
3079 #if defined(MAGICKCORE_XML_DELEGATE)
3080 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3082 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3083 entry->blob_support=MagickFalse;
3084 entry->seekable_stream=MagickFalse;
3085 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3086 if (*version != '\0')
3087 entry->version=ConstantString(version);
3088 entry->magick=(IsImageFormatHandler *) IsSVG;
3089 entry->module=ConstantString("SVG");
3090 (void) RegisterMagickInfo(entry);
3091 entry=SetMagickInfo("MSVG");
3092 #if defined(MAGICKCORE_XML_DELEGATE)
3093 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3095 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3096 entry->blob_support=MagickFalse;
3097 entry->seekable_stream=MagickFalse;
3098 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3099 entry->magick=(IsImageFormatHandler *) IsSVG;
3100 entry->module=ConstantString("SVG");
3101 (void) RegisterMagickInfo(entry);
3102 return(MagickImageCoderSignature);
3106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3110 % U n r e g i s t e r S V G I m a g e %
3114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3116 % UnregisterSVGImage() removes format registrations made by the
3117 % SVG module from the list of supported formats.
3119 % The format of the UnregisterSVGImage method is:
3121 % UnregisterSVGImage(void)
3124 ModuleExport void UnregisterSVGImage(void)
3126 (void) UnregisterMagickInfo("SVGZ");
3127 (void) UnregisterMagickInfo("SVG");
3128 (void) UnregisterMagickInfo("MSVG");
3129 #if defined(MAGICKCORE_RSVG_DELEGATE)
3135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3139 % W r i t e S V G I m a g e %
3143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3145 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3148 % The format of the WriteSVGImage method is:
3150 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3152 % A description of each parameter follows.
3154 % o image_info: the image info.
3156 % o image: The image.
3160 static void AffineToTransform(Image *image,AffineMatrix *affine)
3163 transform[MaxTextExtent];
3165 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3167 if ((fabs(affine->rx) < MagickEpsilon) &&
3168 (fabs(affine->ry) < MagickEpsilon))
3170 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3171 (fabs(affine->sy-1.0) < MagickEpsilon))
3173 (void) WriteBlobString(image,"\">\n");
3176 (void) FormatMagickString(transform,MaxTextExtent,
3177 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3178 (void) WriteBlobString(image,transform);
3183 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3184 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3185 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3191 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3192 (void) FormatMagickString(transform,MaxTextExtent,
3193 "\" transform=\"rotate(%g)\">\n",theta);
3194 (void) WriteBlobString(image,transform);
3201 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3202 (fabs(affine->rx) < MagickEpsilon) &&
3203 (fabs(affine->ry) < MagickEpsilon) &&
3204 (fabs(affine->sy-1.0) < MagickEpsilon))
3206 (void) FormatMagickString(transform,MaxTextExtent,
3207 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3208 (void) WriteBlobString(image,transform);
3212 (void) FormatMagickString(transform,MaxTextExtent,
3213 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3214 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3215 (void) WriteBlobString(image,transform);
3218 static MagickBooleanType IsPoint(const char *point)
3226 value=strtol(point,&p,10);
3227 return(p != point ? MagickTrue : MagickFalse);
3230 static MagickBooleanType TraceSVGImage(Image *image)
3235 register const PixelPacket
3241 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3246 at_fitting_opts_type
3265 Trace image and write as SVG.
3267 fitting_options=at_fitting_opts_new();
3268 output_options=at_output_opts_new();
3269 type=GetImageType(image,&image->exception);
3271 if ((type == BilevelType) || (type == GrayscaleType))
3273 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3275 for (y=0; y < (ssize_t) image->rows; y++)
3277 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3278 if (p == (const PixelPacket *) NULL)
3280 for (x=0; x < (ssize_t) image->columns; x++)
3282 trace->bitmap[i++]=GetRedPixelComponent(p);
3283 if (number_planes == 3)
3285 trace->bitmap[i++]=GetGreenPixelComponent(p);
3286 trace->bitmap[i++]=GetBluePixelComponent(p);
3291 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3293 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3294 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3299 at_splines_free(splines);
3300 at_bitmap_free(trace);
3301 at_output_opts_free(output_options);
3302 at_fitting_opts_free(fitting_options);
3307 message[MaxTextExtent],
3308 tuple[MaxTextExtent];
3313 register const IndexPacket
3316 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3317 (void) WriteBlobString(image,
3318 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3319 (void) WriteBlobString(image,
3320 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3321 (void) FormatMagickString(message,MaxTextExtent,
3322 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3323 (void) WriteBlobString(image,message);
3324 GetMagickPixelPacket(image,&pixel);
3325 for (y=0; y < (ssize_t) image->rows; y++)
3327 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3328 if (p == (const PixelPacket *) NULL)
3330 indexes=GetVirtualIndexQueue(image);
3331 for (x=0; x < (ssize_t) image->columns; x++)
3333 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3334 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3336 (void) FormatMagickString(message,MaxTextExtent,
3337 " <circle cx=\"%ld\" cy=\"%ld\" r=\"1\" fill=\"%s\"/>\n",x,y,tuple);
3338 (void) WriteBlobString(image,message);
3342 (void) WriteBlobString(image,"</svg>\n");
3348 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3350 #define BezierQuantum 200
3356 keyword[MaxTextExtent],
3357 message[MaxTextExtent],
3358 name[MaxTextExtent],
3360 type[MaxTextExtent];
3402 Open output image file.
3404 assert(image_info != (const ImageInfo *) NULL);
3405 assert(image_info->signature == MagickSignature);
3406 assert(image != (Image *) NULL);
3407 assert(image->signature == MagickSignature);
3408 if (image->debug != MagickFalse)
3409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3410 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3411 if (status == MagickFalse)
3413 value=GetImageArtifact(image,"SVG");
3414 if (value != (char *) NULL)
3416 (void) WriteBlobString(image,value);
3417 (void) CloseBlob(image);
3420 value=GetImageArtifact(image,"MVG");
3421 if (value == (char *) NULL)
3422 return(TraceSVGImage(image));
3426 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3427 (void) WriteBlobString(image,
3428 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3429 (void) WriteBlobString(image,
3430 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3431 (void) FormatMagickString(message,MaxTextExtent,
3432 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3433 (void) WriteBlobString(image,message);
3435 Allocate primitive info memory.
3438 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3439 sizeof(*primitive_info));
3440 if (primitive_info == (PrimitiveInfo *) NULL)
3441 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3442 GetAffineMatrix(&affine);
3443 token=AcquireString(value);
3447 for (q=(const char *) value; *q != '\0'; )
3450 Interpret graphic primitive.
3452 GetMagickToken(q,&q,keyword);
3453 if (*keyword == '\0')
3455 if (*keyword == '#')
3460 if (active != MagickFalse)
3462 AffineToTransform(image,&affine);
3465 (void) WriteBlobString(image,"<desc>");
3466 (void) WriteBlobString(image,keyword+1);
3467 for ( ; (*q != '\n') && (*q != '\0'); q++)
3470 case '<': (void) WriteBlobString(image,"<"); break;
3471 case '>': (void) WriteBlobString(image,">"); break;
3472 case '&': (void) WriteBlobString(image,"&"); break;
3473 default: (void) WriteBlobByte(image,*q); break;
3475 (void) WriteBlobString(image,"</desc>\n");
3478 primitive_type=UndefinedPrimitive;
3486 if (LocaleCompare("affine",keyword) == 0)
3488 GetMagickToken(q,&q,token);
3489 affine.sx=StringToDouble(token);
3490 GetMagickToken(q,&q,token);
3492 GetMagickToken(q,&q,token);
3493 affine.rx=StringToDouble(token);
3494 GetMagickToken(q,&q,token);
3496 GetMagickToken(q,&q,token);
3497 affine.ry=StringToDouble(token);
3498 GetMagickToken(q,&q,token);
3500 GetMagickToken(q,&q,token);
3501 affine.sy=StringToDouble(token);
3502 GetMagickToken(q,&q,token);
3504 GetMagickToken(q,&q,token);
3505 affine.tx=StringToDouble(token);
3506 GetMagickToken(q,&q,token);
3508 GetMagickToken(q,&q,token);
3509 affine.ty=StringToDouble(token);
3512 if (LocaleCompare("angle",keyword) == 0)
3514 GetMagickToken(q,&q,token);
3515 affine.rx=StringToDouble(token);
3516 affine.ry=StringToDouble(token);
3519 if (LocaleCompare("arc",keyword) == 0)
3521 primitive_type=ArcPrimitive;
3530 if (LocaleCompare("bezier",keyword) == 0)
3532 primitive_type=BezierPrimitive;
3541 if (LocaleCompare("clip-path",keyword) == 0)
3543 GetMagickToken(q,&q,token);
3544 (void) FormatMagickString(message,MaxTextExtent,
3545 "clip-path:url(#%s);",token);
3546 (void) WriteBlobString(image,message);
3549 if (LocaleCompare("clip-rule",keyword) == 0)
3551 GetMagickToken(q,&q,token);
3552 (void) FormatMagickString(message,MaxTextExtent,
3553 "clip-rule:%s;",token);
3554 (void) WriteBlobString(image,message);
3557 if (LocaleCompare("clip-units",keyword) == 0)
3559 GetMagickToken(q,&q,token);
3560 (void) FormatMagickString(message,MaxTextExtent,
3561 "clipPathUnits=%s;",token);
3562 (void) WriteBlobString(image,message);
3565 if (LocaleCompare("circle",keyword) == 0)
3567 primitive_type=CirclePrimitive;
3570 if (LocaleCompare("color",keyword) == 0)
3572 primitive_type=ColorPrimitive;
3581 if (LocaleCompare("decorate",keyword) == 0)
3583 GetMagickToken(q,&q,token);
3584 (void) FormatMagickString(message,MaxTextExtent,
3585 "text-decoration:%s;",token);
3586 (void) WriteBlobString(image,message);
3595 if (LocaleCompare("ellipse",keyword) == 0)
3597 primitive_type=EllipsePrimitive;
3606 if (LocaleCompare("fill",keyword) == 0)
3608 GetMagickToken(q,&q,token);
3609 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3611 (void) WriteBlobString(image,message);
3614 if (LocaleCompare("fill-rule",keyword) == 0)
3616 GetMagickToken(q,&q,token);
3617 (void) FormatMagickString(message,MaxTextExtent,
3618 "fill-rule:%s;",token);
3619 (void) WriteBlobString(image,message);
3622 if (LocaleCompare("fill-opacity",keyword) == 0)
3624 GetMagickToken(q,&q,token);
3625 (void) FormatMagickString(message,MaxTextExtent,
3626 "fill-opacity:%s;",token);
3627 (void) WriteBlobString(image,message);
3630 if (LocaleCompare("font-family",keyword) == 0)
3632 GetMagickToken(q,&q,token);
3633 (void) FormatMagickString(message,MaxTextExtent,
3634 "font-family:%s;",token);
3635 (void) WriteBlobString(image,message);
3638 if (LocaleCompare("font-stretch",keyword) == 0)
3640 GetMagickToken(q,&q,token);
3641 (void) FormatMagickString(message,MaxTextExtent,
3642 "font-stretch:%s;",token);
3643 (void) WriteBlobString(image,message);
3646 if (LocaleCompare("font-style",keyword) == 0)
3648 GetMagickToken(q,&q,token);
3649 (void) FormatMagickString(message,MaxTextExtent,
3650 "font-style:%s;",token);
3651 (void) WriteBlobString(image,message);
3654 if (LocaleCompare("font-size",keyword) == 0)
3656 GetMagickToken(q,&q,token);
3657 (void) FormatMagickString(message,MaxTextExtent,
3658 "font-size:%s;",token);
3659 (void) WriteBlobString(image,message);
3662 if (LocaleCompare("font-weight",keyword) == 0)
3664 GetMagickToken(q,&q,token);
3665 (void) FormatMagickString(message,MaxTextExtent,
3666 "font-weight:%s;",token);
3667 (void) WriteBlobString(image,message);
3676 if (LocaleCompare("gradient-units",keyword) == 0)
3678 GetMagickToken(q,&q,token);
3681 if (LocaleCompare("text-align",keyword) == 0)
3683 GetMagickToken(q,&q,token);
3684 (void) FormatMagickString(message,MaxTextExtent,
3685 "text-align %s ",token);
3686 (void) WriteBlobString(image,message);
3689 if (LocaleCompare("text-anchor",keyword) == 0)
3691 GetMagickToken(q,&q,token);
3692 (void) FormatMagickString(message,MaxTextExtent,
3693 "text-anchor %s ",token);
3694 (void) WriteBlobString(image,message);
3703 if (LocaleCompare("image",keyword) == 0)
3705 GetMagickToken(q,&q,token);
3706 primitive_type=ImagePrimitive;
3715 if (LocaleCompare("line",keyword) == 0)
3717 primitive_type=LinePrimitive;
3726 if (LocaleCompare("matte",keyword) == 0)
3728 primitive_type=MattePrimitive;
3737 if (LocaleCompare("opacity",keyword) == 0)
3739 GetMagickToken(q,&q,token);
3740 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3742 (void) WriteBlobString(image,message);
3751 if (LocaleCompare("path",keyword) == 0)
3753 primitive_type=PathPrimitive;
3756 if (LocaleCompare("point",keyword) == 0)
3758 primitive_type=PointPrimitive;
3761 if (LocaleCompare("polyline",keyword) == 0)
3763 primitive_type=PolylinePrimitive;
3766 if (LocaleCompare("polygon",keyword) == 0)
3768 primitive_type=PolygonPrimitive;
3771 if (LocaleCompare("pop",keyword) == 0)
3773 GetMagickToken(q,&q,token);
3774 if (LocaleCompare("clip-path",token) == 0)
3776 (void) WriteBlobString(image,"</clipPath>\n");
3779 if (LocaleCompare("defs",token) == 0)
3781 (void) WriteBlobString(image,"</defs>\n");
3784 if (LocaleCompare("gradient",token) == 0)
3786 (void) FormatMagickString(message,MaxTextExtent,
3787 "</%sGradient>\n",type);
3788 (void) WriteBlobString(image,message);
3791 if (LocaleCompare("graphic-context",token) == 0)
3795 ThrowWriterException(DrawError,
3796 "UnbalancedGraphicContextPushPop");
3797 (void) WriteBlobString(image,"</g>\n");
3799 if (LocaleCompare("pattern",token) == 0)
3801 (void) WriteBlobString(image,"</pattern>\n");
3804 if (LocaleCompare("defs",token) == 0)
3805 (void) WriteBlobString(image,"</g>\n");
3808 if (LocaleCompare("push",keyword) == 0)
3810 GetMagickToken(q,&q,token);
3811 if (LocaleCompare("clip-path",token) == 0)
3813 GetMagickToken(q,&q,token);
3814 (void) FormatMagickString(message,MaxTextExtent,
3815 "<clipPath id=\"%s\">\n",token);
3816 (void) WriteBlobString(image,message);
3819 if (LocaleCompare("defs",token) == 0)
3821 (void) WriteBlobString(image,"<defs>\n");
3824 if (LocaleCompare("gradient",token) == 0)
3826 GetMagickToken(q,&q,token);
3827 (void) CopyMagickString(name,token,MaxTextExtent);
3828 GetMagickToken(q,&q,token);
3829 (void) CopyMagickString(type,token,MaxTextExtent);
3830 GetMagickToken(q,&q,token);
3831 svg_info.segment.x1=StringToDouble(token);
3832 svg_info.element.cx=StringToDouble(token);
3833 GetMagickToken(q,&q,token);
3835 GetMagickToken(q,&q,token);
3836 svg_info.segment.y1=StringToDouble(token);
3837 svg_info.element.cy=StringToDouble(token);
3838 GetMagickToken(q,&q,token);
3840 GetMagickToken(q,&q,token);
3841 svg_info.segment.x2=StringToDouble(token);
3842 svg_info.element.major=StringToDouble(token);
3843 GetMagickToken(q,&q,token);
3845 GetMagickToken(q,&q,token);
3846 svg_info.segment.y2=StringToDouble(token);
3847 svg_info.element.minor=StringToDouble(token);
3848 (void) FormatMagickString(message,MaxTextExtent,
3849 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3850 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3851 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3852 if (LocaleCompare(type,"radial") == 0)
3854 GetMagickToken(q,&q,token);
3856 GetMagickToken(q,&q,token);
3857 svg_info.element.angle=StringToDouble(token);
3858 (void) FormatMagickString(message,MaxTextExtent,
3859 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3860 "fx=\"%g\" fy=\"%g\">\n",type,name,
3861 svg_info.element.cx,svg_info.element.cy,
3862 svg_info.element.angle,svg_info.element.major,
3863 svg_info.element.minor);
3865 (void) WriteBlobString(image,message);
3868 if (LocaleCompare("graphic-context",token) == 0)
3873 AffineToTransform(image,&affine);
3876 (void) WriteBlobString(image,"<g style=\"");
3879 if (LocaleCompare("pattern",token) == 0)
3881 GetMagickToken(q,&q,token);
3882 (void) CopyMagickString(name,token,MaxTextExtent);
3883 GetMagickToken(q,&q,token);
3884 svg_info.bounds.x=StringToDouble(token);
3885 GetMagickToken(q,&q,token);
3887 GetMagickToken(q,&q,token);
3888 svg_info.bounds.y=StringToDouble(token);
3889 GetMagickToken(q,&q,token);
3891 GetMagickToken(q,&q,token);
3892 svg_info.bounds.width=StringToDouble(token);
3893 GetMagickToken(q,&q,token);
3895 GetMagickToken(q,&q,token);
3896 svg_info.bounds.height=StringToDouble(token);
3897 (void) FormatMagickString(message,MaxTextExtent,
3898 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3899 "height=\"%g\">\n",name,svg_info.bounds.x,
3900 svg_info.bounds.y,svg_info.bounds.width,
3901 svg_info.bounds.height);
3902 (void) WriteBlobString(image,message);
3913 if (LocaleCompare("rectangle",keyword) == 0)
3915 primitive_type=RectanglePrimitive;
3918 if (LocaleCompare("roundRectangle",keyword) == 0)
3920 primitive_type=RoundRectanglePrimitive;
3923 if (LocaleCompare("rotate",keyword) == 0)
3925 GetMagickToken(q,&q,token);
3926 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3928 (void) WriteBlobString(image,message);
3937 if (LocaleCompare("scale",keyword) == 0)
3939 GetMagickToken(q,&q,token);
3940 affine.sx=StringToDouble(token);
3941 GetMagickToken(q,&q,token);
3943 GetMagickToken(q,&q,token);
3944 affine.sy=StringToDouble(token);
3947 if (LocaleCompare("skewX",keyword) == 0)
3949 GetMagickToken(q,&q,token);
3950 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3952 (void) WriteBlobString(image,message);
3955 if (LocaleCompare("skewY",keyword) == 0)
3957 GetMagickToken(q,&q,token);
3958 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3960 (void) WriteBlobString(image,message);
3963 if (LocaleCompare("stop-color",keyword) == 0)
3966 color[MaxTextExtent];
3968 GetMagickToken(q,&q,token);
3969 (void) CopyMagickString(color,token,MaxTextExtent);
3970 GetMagickToken(q,&q,token);
3971 (void) FormatMagickString(message,MaxTextExtent,
3972 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3973 (void) WriteBlobString(image,message);
3976 if (LocaleCompare("stroke",keyword) == 0)
3978 GetMagickToken(q,&q,token);
3979 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
3981 (void) WriteBlobString(image,message);
3984 if (LocaleCompare("stroke-antialias",keyword) == 0)
3986 GetMagickToken(q,&q,token);
3987 (void) FormatMagickString(message,MaxTextExtent,
3988 "stroke-antialias:%s;",token);
3989 (void) WriteBlobString(image,message);
3992 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4000 GetMagickToken(p,&p,token);
4001 for (k=0; IsPoint(token); k++)
4002 GetMagickToken(p,&p,token);
4003 (void) WriteBlobString(image,"stroke-dasharray:");
4004 for (j=0; j < k; j++)
4006 GetMagickToken(q,&q,token);
4007 (void) FormatMagickString(message,MaxTextExtent,"%s ",
4009 (void) WriteBlobString(image,message);
4011 (void) WriteBlobString(image,";");
4014 GetMagickToken(q,&q,token);
4015 (void) FormatMagickString(message,MaxTextExtent,
4016 "stroke-dasharray:%s;",token);
4017 (void) WriteBlobString(image,message);
4020 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4022 GetMagickToken(q,&q,token);
4023 (void) FormatMagickString(message,MaxTextExtent,
4024 "stroke-dashoffset:%s;",token);
4025 (void) WriteBlobString(image,message);
4028 if (LocaleCompare("stroke-linecap",keyword) == 0)
4030 GetMagickToken(q,&q,token);
4031 (void) FormatMagickString(message,MaxTextExtent,
4032 "stroke-linecap:%s;",token);
4033 (void) WriteBlobString(image,message);
4036 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4038 GetMagickToken(q,&q,token);
4039 (void) FormatMagickString(message,MaxTextExtent,
4040 "stroke-linejoin:%s;",token);
4041 (void) WriteBlobString(image,message);
4044 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4046 GetMagickToken(q,&q,token);
4047 (void) FormatMagickString(message,MaxTextExtent,
4048 "stroke-miterlimit:%s;",token);
4049 (void) WriteBlobString(image,message);
4052 if (LocaleCompare("stroke-opacity",keyword) == 0)
4054 GetMagickToken(q,&q,token);
4055 (void) FormatMagickString(message,MaxTextExtent,
4056 "stroke-opacity:%s;",token);
4057 (void) WriteBlobString(image,message);
4060 if (LocaleCompare("stroke-width",keyword) == 0)
4062 GetMagickToken(q,&q,token);
4063 (void) FormatMagickString(message,MaxTextExtent,
4064 "stroke-width:%s;",token);
4065 (void) WriteBlobString(image,message);
4074 if (LocaleCompare("text",keyword) == 0)
4076 primitive_type=TextPrimitive;
4079 if (LocaleCompare("text-antialias",keyword) == 0)
4081 GetMagickToken(q,&q,token);
4082 (void) FormatMagickString(message,MaxTextExtent,
4083 "text-antialias:%s;",token);
4084 (void) WriteBlobString(image,message);
4087 if (LocaleCompare("tspan",keyword) == 0)
4089 primitive_type=TextPrimitive;
4092 if (LocaleCompare("translate",keyword) == 0)
4094 GetMagickToken(q,&q,token);
4095 affine.tx=StringToDouble(token);
4096 GetMagickToken(q,&q,token);
4098 GetMagickToken(q,&q,token);
4099 affine.ty=StringToDouble(token);
4108 if (LocaleCompare("viewbox",keyword) == 0)
4110 GetMagickToken(q,&q,token);
4112 GetMagickToken(q,&q,token);
4113 GetMagickToken(q,&q,token);
4115 GetMagickToken(q,&q,token);
4116 GetMagickToken(q,&q,token);
4118 GetMagickToken(q,&q,token);
4119 GetMagickToken(q,&q,token);
4131 if (status == MagickFalse)
4133 if (primitive_type == UndefinedPrimitive)
4136 Parse the primitive attributes.
4140 for (x=0; *q != '\0'; x++)
4145 if (IsPoint(q) == MagickFalse)
4147 GetMagickToken(q,&q,token);
4148 point.x=StringToDouble(token);
4149 GetMagickToken(q,&q,token);
4151 GetMagickToken(q,&q,token);
4152 point.y=StringToDouble(token);
4153 GetMagickToken(q,(const char **) NULL,token);
4155 GetMagickToken(q,&q,token);
4156 primitive_info[i].primitive=primitive_type;
4157 primitive_info[i].point=point;
4158 primitive_info[i].coordinates=0;
4159 primitive_info[i].method=FloodfillMethod;
4161 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4163 number_points+=6*BezierQuantum+360;
4164 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4165 number_points,sizeof(*primitive_info));
4166 if (primitive_info == (PrimitiveInfo *) NULL)
4168 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4169 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4173 primitive_info[j].primitive=primitive_type;
4174 primitive_info[j].coordinates=x;
4175 primitive_info[j].method=FloodfillMethod;
4176 primitive_info[j].text=(char *) NULL;
4179 AffineToTransform(image,&affine);
4183 switch (primitive_type)
4185 case PointPrimitive:
4188 if (primitive_info[j].coordinates != 1)
4197 if (primitive_info[j].coordinates != 2)
4202 (void) FormatMagickString(message,MaxTextExtent,
4203 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4204 primitive_info[j].point.x,primitive_info[j].point.y,
4205 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4206 (void) WriteBlobString(image,message);
4209 case RectanglePrimitive:
4211 if (primitive_info[j].coordinates != 2)
4216 (void) FormatMagickString(message,MaxTextExtent,
4217 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4218 primitive_info[j].point.x,primitive_info[j].point.y,
4219 primitive_info[j+1].point.x-primitive_info[j].point.x,
4220 primitive_info[j+1].point.y-primitive_info[j].point.y);
4221 (void) WriteBlobString(image,message);
4224 case RoundRectanglePrimitive:
4226 if (primitive_info[j].coordinates != 3)
4231 (void) FormatMagickString(message,MaxTextExtent,
4232 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4233 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4234 primitive_info[j].point.y,primitive_info[j+1].point.x-
4235 primitive_info[j].point.x,primitive_info[j+1].point.y-
4236 primitive_info[j].point.y,primitive_info[j+2].point.x,
4237 primitive_info[j+2].point.y);
4238 (void) WriteBlobString(image,message);
4243 if (primitive_info[j].coordinates != 3)
4250 case EllipsePrimitive:
4252 if (primitive_info[j].coordinates != 3)
4257 (void) FormatMagickString(message,MaxTextExtent,
4258 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4259 primitive_info[j].point.x,primitive_info[j].point.y,
4260 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4261 (void) WriteBlobString(image,message);
4264 case CirclePrimitive:
4270 if (primitive_info[j].coordinates != 2)
4275 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4276 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4277 (void) FormatMagickString(message,MaxTextExtent,
4278 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4279 primitive_info[j].point.x,primitive_info[j].point.y,
4281 (void) WriteBlobString(image,message);
4284 case PolylinePrimitive:
4286 if (primitive_info[j].coordinates < 2)
4291 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4292 (void) WriteBlobString(image,message);
4293 length=strlen(message);
4296 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4297 primitive_info[j].point.x,primitive_info[j].point.y);
4298 length+=strlen(message);
4301 (void) WriteBlobString(image,"\n ");
4302 length=strlen(message)+5;
4304 (void) WriteBlobString(image,message);
4306 (void) WriteBlobString(image,"\"/>\n");
4309 case PolygonPrimitive:
4311 if (primitive_info[j].coordinates < 3)
4316 primitive_info[i]=primitive_info[j];
4317 primitive_info[i].coordinates=0;
4318 primitive_info[j].coordinates++;
4320 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4321 (void) WriteBlobString(image,message);
4322 length=strlen(message);
4325 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4326 primitive_info[j].point.x,primitive_info[j].point.y);
4327 length+=strlen(message);
4330 (void) WriteBlobString(image,"\n ");
4331 length=strlen(message)+5;
4333 (void) WriteBlobString(image,message);
4335 (void) WriteBlobString(image,"\"/>\n");
4338 case BezierPrimitive:
4340 if (primitive_info[j].coordinates < 3)
4352 GetMagickToken(q,&q,token);
4353 number_attributes=1;
4354 for (p=token; *p != '\0'; p++)
4355 if (isalpha((int) *p))
4356 number_attributes++;
4357 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4359 number_points+=6*BezierQuantum*number_attributes;
4360 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4361 number_points,sizeof(*primitive_info));
4362 if (primitive_info == (PrimitiveInfo *) NULL)
4364 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4365 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4370 (void) WriteBlobString(image," <path d=\"");
4371 (void) WriteBlobString(image,token);
4372 (void) WriteBlobString(image,"\"/>\n");
4375 case ColorPrimitive:
4376 case MattePrimitive:
4378 if (primitive_info[j].coordinates != 1)
4383 GetMagickToken(q,&q,token);
4384 if (LocaleCompare("point",token) == 0)
4385 primitive_info[j].method=PointMethod;
4386 if (LocaleCompare("replace",token) == 0)
4387 primitive_info[j].method=ReplaceMethod;
4388 if (LocaleCompare("floodfill",token) == 0)
4389 primitive_info[j].method=FloodfillMethod;
4390 if (LocaleCompare("filltoborder",token) == 0)
4391 primitive_info[j].method=FillToBorderMethod;
4392 if (LocaleCompare("reset",token) == 0)
4393 primitive_info[j].method=ResetMethod;
4401 if (primitive_info[j].coordinates != 1)
4406 GetMagickToken(q,&q,token);
4407 (void) FormatMagickString(message,MaxTextExtent,
4408 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4409 primitive_info[j].point.y);
4410 (void) WriteBlobString(image,message);
4411 for (p=token; *p != '\0'; p++)
4414 case '<': (void) WriteBlobString(image,"<"); break;
4415 case '>': (void) WriteBlobString(image,">"); break;
4416 case '&': (void) WriteBlobString(image,"&"); break;
4417 default: (void) WriteBlobByte(image,*p); break;
4419 (void) WriteBlobString(image,"</text>\n");
4422 case ImagePrimitive:
4424 if (primitive_info[j].coordinates != 2)
4429 GetMagickToken(q,&q,token);
4430 (void) FormatMagickString(message,MaxTextExtent,
4431 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4432 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4433 primitive_info[j].point.y,primitive_info[j+1].point.x,
4434 primitive_info[j+1].point.y,token);
4435 (void) WriteBlobString(image,message);
4439 if (primitive_info == (PrimitiveInfo *) NULL)
4441 primitive_info[i].primitive=UndefinedPrimitive;
4442 if (status == MagickFalse)
4445 (void) WriteBlobString(image,"</svg>\n");
4447 Relinquish resources.
4449 token=DestroyString(token);
4450 if (primitive_info != (PrimitiveInfo *) NULL)
4451 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4452 (void) CloseBlob(image);