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=(unsigned long) floor(svg_info->bounds.width+0.5);
2118 svg_info->height=(unsigned long) 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,(unsigned long) 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 < (long) 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 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2661 static void SVGSetImageSize(int *width,int *height,gpointer context)
2666 image=(Image *) context;
2667 *width=(int) (*width*image->x_resolution/72.0);
2668 *height=(int) (*height*image->y_resolution/72.0);
2673 #if defined(__cplusplus) || defined(c_plusplus)
2677 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2680 filename[MaxTextExtent];
2699 message[MaxTextExtent];
2710 assert(image_info != (const ImageInfo *) NULL);
2711 assert(image_info->signature == MagickSignature);
2712 assert(exception != (ExceptionInfo *) NULL);
2713 if (image_info->debug != MagickFalse)
2714 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2715 image_info->filename);
2716 assert(exception->signature == MagickSignature);
2717 image=AcquireImage(image_info);
2718 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2719 if (status == MagickFalse)
2721 image=DestroyImageList(image);
2722 return((Image *) NULL);
2724 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2726 #if defined(MAGICKCORE_RSVG_DELEGATE)
2727 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2734 register unsigned char
2747 register const guchar
2764 register PixelPacket
2770 svg_handle=rsvg_handle_new();
2771 if (svg_handle == (RsvgHandle *) NULL)
2772 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2773 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2774 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2775 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2777 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2778 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2779 image->y_resolution);
2780 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2782 error=(GError *) NULL;
2783 (void) rsvg_handle_write(svg_handle,message,n,&error);
2784 if (error != (GError *) NULL)
2785 g_error_free(error);
2787 error=(GError *) NULL;
2788 rsvg_handle_close(svg_handle,&error);
2789 if (error != (GError *) NULL)
2790 g_error_free(error);
2791 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2792 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2793 image->columns=dimension_info.width;
2794 image->rows=dimension_info.height;
2795 pixels=(unsigned char *) NULL;
2797 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2798 rsvg_handle_free(svg_handle);
2799 image->columns=gdk_pixbuf_get_width(pixel_info);
2800 image->rows=gdk_pixbuf_get_height(pixel_info);
2802 image->matte=MagickTrue;
2803 SetImageProperty(image,"svg:base-uri",
2804 rsvg_handle_get_base_uri(svg_handle));
2805 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2806 SetImageProperty(image,"svg:description",
2807 rsvg_handle_get_desc(svg_handle));
2808 if ((image->columns == 0) || (image->rows == 0))
2810 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2811 g_object_unref(G_OBJECT(pixel_info));
2813 g_object_unref(svg_handle);
2814 ThrowReaderException(MissingDelegateError,
2815 "NoDecodeDelegateForThisImageFormat");
2817 if (image_info->ping == MagickFalse)
2819 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2820 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2821 image->rows*sizeof(*pixels));
2822 if (pixels == (unsigned char *) NULL)
2824 g_object_unref(svg_handle);
2825 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2828 (void) SetImageBackgroundColor(image);
2829 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2830 cairo_surface=cairo_image_surface_create_for_data(pixels,
2831 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2832 if (cairo_surface == (cairo_surface_t *) NULL)
2834 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2835 g_object_unref(svg_handle);
2836 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2838 cairo_info=cairo_create(cairo_surface);
2839 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2840 cairo_paint(cairo_info);
2841 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2842 rsvg_handle_render_cairo(svg_handle,cairo_info);
2843 cairo_destroy(cairo_info);
2844 cairo_surface_destroy(cairo_surface);
2845 g_object_unref(svg_handle);
2848 p=gdk_pixbuf_get_pixels(pixel_info);
2850 for (y=0; y < (long) image->rows; y++)
2852 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2853 if (q == (PixelPacket *) NULL)
2855 for (x=0; x < (long) image->columns; x++)
2857 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2858 fill_color.blue=ScaleCharToQuantum(*p++);
2859 fill_color.green=ScaleCharToQuantum(*p++);
2860 fill_color.red=ScaleCharToQuantum(*p++);
2862 fill_color.red=ScaleCharToQuantum(*p++);
2863 fill_color.green=ScaleCharToQuantum(*p++);
2864 fill_color.blue=ScaleCharToQuantum(*p++);
2866 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2867 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2872 gamma=1.0-QuantumScale*fill_color.opacity;
2873 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2874 fill_color.blue*=gamma;
2875 fill_color.green*=gamma;
2876 fill_color.red*=gamma;
2879 MagickCompositeOver(&fill_color,fill_color.opacity,q,
2880 (MagickRealType) q->opacity,q);
2883 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2885 if (image->previous == (Image *) NULL)
2887 status=SetImageProgress(image,LoadImageTag,y,image->rows);
2888 if (status == MagickFalse)
2893 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2894 if (pixels != (unsigned char *) NULL)
2895 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2897 g_object_unref(G_OBJECT(pixel_info));
2899 (void) CloseBlob(image);
2900 return(GetFirstImageInList(image));
2907 unique_file=AcquireUniqueFileResource(filename);
2908 if (unique_file != -1)
2909 file=fdopen(unique_file,"w");
2910 if ((unique_file == -1) || (file == (FILE *) NULL))
2912 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2913 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2915 image=DestroyImageList(image);
2916 return((Image *) NULL);
2921 svg_info=AcquireSVGInfo();
2922 if (svg_info == (SVGInfo *) NULL)
2923 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2924 svg_info->file=file;
2925 svg_info->exception=exception;
2926 svg_info->image=image;
2927 svg_info->image_info=image_info;
2928 svg_info->bounds.width=image->columns;
2929 svg_info->bounds.height=image->rows;
2930 if (image_info->size != (char *) NULL)
2931 (void) CloneString(&svg_info->size,image_info->size);
2932 if (image->debug != MagickFalse)
2933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2935 (void) xmlSubstituteEntitiesDefault(1);
2936 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
2937 sax_modules.internalSubset=SVGInternalSubset;
2938 sax_modules.isStandalone=SVGIsStandalone;
2939 sax_modules.hasInternalSubset=SVGHasInternalSubset;
2940 sax_modules.hasExternalSubset=SVGHasExternalSubset;
2941 sax_modules.resolveEntity=SVGResolveEntity;
2942 sax_modules.getEntity=SVGGetEntity;
2943 sax_modules.entityDecl=SVGEntityDeclaration;
2944 sax_modules.notationDecl=SVGNotationDeclaration;
2945 sax_modules.attributeDecl=SVGAttributeDeclaration;
2946 sax_modules.elementDecl=SVGElementDeclaration;
2947 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
2948 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
2949 sax_modules.startDocument=SVGStartDocument;
2950 sax_modules.endDocument=SVGEndDocument;
2951 sax_modules.startElement=SVGStartElement;
2952 sax_modules.endElement=SVGEndElement;
2953 sax_modules.reference=SVGReference;
2954 sax_modules.characters=SVGCharacters;
2955 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
2956 sax_modules.processingInstruction=SVGProcessingInstructions;
2957 sax_modules.comment=SVGComment;
2958 sax_modules.warning=SVGWarning;
2959 sax_modules.error=SVGError;
2960 sax_modules.fatalError=SVGError;
2961 sax_modules.getParameterEntity=SVGGetParameterEntity;
2962 sax_modules.cdataBlock=SVGCDataBlock;
2963 sax_modules.externalSubset=SVGExternalSubset;
2964 sax_handler=(&sax_modules);
2965 n=ReadBlob(image,MaxTextExtent,message);
2968 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2969 message,n,image->filename);
2970 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2972 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2977 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2978 xmlFreeParserCtxt(svg_info->parser);
2979 if (image->debug != MagickFalse)
2980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2982 (void) fclose(file);
2983 (void) CloseBlob(image);
2984 image->columns=svg_info->width;
2985 image->rows=svg_info->height;
2986 if (exception->severity >= ErrorException)
2988 image=DestroyImage(image);
2989 return((Image *) NULL);
2991 if (image_info->ping == MagickFalse)
2999 image=DestroyImage(image);
3000 image=(Image *) NULL;
3001 read_info=CloneImageInfo(image_info);
3002 SetImageInfoBlob(read_info,(void *) NULL,0);
3003 if (read_info->density != (char *) NULL)
3004 read_info->density=DestroyString(read_info->density);
3005 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
3007 image=ReadImage(read_info,exception);
3008 read_info=DestroyImageInfo(read_info);
3009 if (image != (Image *) NULL)
3010 (void) CopyMagickString(image->filename,image_info->filename,
3014 Relinquish resources.
3016 if (image != (Image *) NULL)
3018 if (svg_info->title != (char *) NULL)
3019 (void) SetImageProperty(image,"svg:title",svg_info->title);
3020 if (svg_info->comment != (char *) NULL)
3021 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3023 svg_info=DestroySVGInfo(svg_info);
3024 (void) RelinquishUniqueFileResource(filename);
3025 return(GetFirstImageInList(image));
3030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3034 % R e g i s t e r S V G I m a g e %
3038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040 % RegisterSVGImage() adds attributes for the SVG image format to
3041 % the list of supported formats. The attributes include the image format
3042 % tag, a method to read and/or write the format, whether the format
3043 % supports the saving of more than one frame to the same file or blob,
3044 % whether the format supports native in-memory I/O, and a brief
3045 % description of the format.
3047 % The format of the RegisterSVGImage method is:
3049 % unsigned long RegisterSVGImage(void)
3052 ModuleExport unsigned long RegisterSVGImage(void)
3055 version[MaxTextExtent];
3061 #if defined(LIBXML_DOTTED_VERSION)
3062 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3064 #if defined(MAGICKCORE_RSVG_DELEGATE)
3066 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3067 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3069 entry=SetMagickInfo("SVG");
3070 #if defined(MAGICKCORE_XML_DELEGATE)
3071 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3073 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3074 entry->blob_support=MagickFalse;
3075 entry->seekable_stream=MagickFalse;
3076 entry->description=ConstantString("Scalable Vector Graphics");
3077 if (*version != '\0')
3078 entry->version=ConstantString(version);
3079 entry->magick=(IsImageFormatHandler *) IsSVG;
3080 entry->module=ConstantString("SVG");
3081 (void) RegisterMagickInfo(entry);
3082 entry=SetMagickInfo("SVGZ");
3083 #if defined(MAGICKCORE_XML_DELEGATE)
3084 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3086 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3087 entry->blob_support=MagickFalse;
3088 entry->seekable_stream=MagickFalse;
3089 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3090 if (*version != '\0')
3091 entry->version=ConstantString(version);
3092 entry->magick=(IsImageFormatHandler *) IsSVG;
3093 entry->module=ConstantString("SVG");
3094 (void) RegisterMagickInfo(entry);
3095 entry=SetMagickInfo("MSVG");
3096 #if defined(MAGICKCORE_XML_DELEGATE)
3097 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3099 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3100 entry->blob_support=MagickFalse;
3101 entry->seekable_stream=MagickFalse;
3102 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3103 entry->magick=(IsImageFormatHandler *) IsSVG;
3104 entry->module=ConstantString("SVG");
3105 (void) RegisterMagickInfo(entry);
3106 return(MagickImageCoderSignature);
3110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3114 % U n r e g i s t e r S V G I m a g e %
3118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3120 % UnregisterSVGImage() removes format registrations made by the
3121 % SVG module from the list of supported formats.
3123 % The format of the UnregisterSVGImage method is:
3125 % UnregisterSVGImage(void)
3128 ModuleExport void UnregisterSVGImage(void)
3130 (void) UnregisterMagickInfo("SVGZ");
3131 (void) UnregisterMagickInfo("SVG");
3132 (void) UnregisterMagickInfo("MSVG");
3133 #if defined(MAGICKCORE_RSVG_DELEGATE)
3139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3143 % W r i t e S V G I m a g e %
3147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3149 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3152 % The format of the WriteSVGImage method is:
3154 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3156 % A description of each parameter follows.
3158 % o image_info: the image info.
3160 % o image: The image.
3164 static void AffineToTransform(Image *image,AffineMatrix *affine)
3167 transform[MaxTextExtent];
3169 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3171 if ((fabs(affine->rx) < MagickEpsilon) &&
3172 (fabs(affine->ry) < MagickEpsilon))
3174 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3175 (fabs(affine->sy-1.0) < MagickEpsilon))
3177 (void) WriteBlobString(image,"\">\n");
3180 (void) FormatMagickString(transform,MaxTextExtent,
3181 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3182 (void) WriteBlobString(image,transform);
3187 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3188 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3189 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3195 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3196 (void) FormatMagickString(transform,MaxTextExtent,
3197 "\" transform=\"rotate(%g)\">\n",theta);
3198 (void) WriteBlobString(image,transform);
3205 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3206 (fabs(affine->rx) < MagickEpsilon) &&
3207 (fabs(affine->ry) < MagickEpsilon) &&
3208 (fabs(affine->sy-1.0) < MagickEpsilon))
3210 (void) FormatMagickString(transform,MaxTextExtent,
3211 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3212 (void) WriteBlobString(image,transform);
3216 (void) FormatMagickString(transform,MaxTextExtent,
3217 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3218 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3219 (void) WriteBlobString(image,transform);
3222 static MagickBooleanType IsPoint(const char *point)
3230 value=strtol(point,&p,10);
3231 return(p != point ? MagickTrue : MagickFalse);
3234 static MagickBooleanType TraceSVGImage(Image *image)
3239 register const PixelPacket
3245 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3250 at_fitting_opts_type
3269 Trace image and write as SVG.
3271 fitting_options=at_fitting_opts_new();
3272 output_options=at_output_opts_new();
3273 type=GetImageType(image,&image->exception);
3275 if ((type == BilevelType) || (type == GrayscaleType))
3277 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3279 for (y=0; y < (long) image->rows; y++)
3281 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3282 if (p == (const PixelPacket *) NULL)
3284 for (x=0; x < (long) image->columns; x++)
3286 trace->bitmap[i++]=GetRedPixelComponent(p);
3287 if (number_planes == 3)
3289 trace->bitmap[i++]=GetGreenPixelComponent(p);
3290 trace->bitmap[i++]=GetBluePixelComponent(p);
3295 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3297 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3298 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3303 at_splines_free(splines);
3304 at_bitmap_free(trace);
3305 at_output_opts_free(output_options);
3306 at_fitting_opts_free(fitting_options);
3311 message[MaxTextExtent],
3312 tuple[MaxTextExtent];
3317 register const IndexPacket
3320 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3321 (void) WriteBlobString(image,
3322 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3323 (void) WriteBlobString(image,
3324 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3325 (void) FormatMagickString(message,MaxTextExtent,
3326 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3327 (void) WriteBlobString(image,message);
3328 GetMagickPixelPacket(image,&pixel);
3329 for (y=0; y < (long) image->rows; y++)
3331 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3332 if (p == (const PixelPacket *) NULL)
3334 indexes=GetVirtualIndexQueue(image);
3335 for (x=0; x < (long) image->columns; x++)
3337 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3338 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3340 (void) FormatMagickString(message,MaxTextExtent,
3341 " <circle cx=\"%ld\" cy=\"%ld\" r=\"1\" fill=\"%s\"/>\n",x,y,tuple);
3342 (void) WriteBlobString(image,message);
3346 (void) WriteBlobString(image,"</svg>\n");
3352 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3354 #define BezierQuantum 200
3360 keyword[MaxTextExtent],
3361 message[MaxTextExtent],
3362 name[MaxTextExtent],
3364 type[MaxTextExtent];
3406 Open output image file.
3408 assert(image_info != (const ImageInfo *) NULL);
3409 assert(image_info->signature == MagickSignature);
3410 assert(image != (Image *) NULL);
3411 assert(image->signature == MagickSignature);
3412 if (image->debug != MagickFalse)
3413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3414 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3415 if (status == MagickFalse)
3417 value=GetImageArtifact(image,"SVG");
3418 if (value != (char *) NULL)
3420 (void) WriteBlobString(image,value);
3421 (void) CloseBlob(image);
3424 value=GetImageArtifact(image,"MVG");
3425 if (value == (char *) NULL)
3426 return(TraceSVGImage(image));
3430 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3431 (void) WriteBlobString(image,
3432 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3433 (void) WriteBlobString(image,
3434 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3435 (void) FormatMagickString(message,MaxTextExtent,
3436 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3437 (void) WriteBlobString(image,message);
3439 Allocate primitive info memory.
3442 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3443 sizeof(*primitive_info));
3444 if (primitive_info == (PrimitiveInfo *) NULL)
3445 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3446 GetAffineMatrix(&affine);
3447 token=AcquireString(value);
3451 for (q=(const char *) value; *q != '\0'; )
3454 Interpret graphic primitive.
3456 GetMagickToken(q,&q,keyword);
3457 if (*keyword == '\0')
3459 if (*keyword == '#')
3464 if (active != MagickFalse)
3466 AffineToTransform(image,&affine);
3469 (void) WriteBlobString(image,"<desc>");
3470 (void) WriteBlobString(image,keyword+1);
3471 for ( ; (*q != '\n') && (*q != '\0'); q++)
3474 case '<': (void) WriteBlobString(image,"<"); break;
3475 case '>': (void) WriteBlobString(image,">"); break;
3476 case '&': (void) WriteBlobString(image,"&"); break;
3477 default: (void) WriteBlobByte(image,*q); break;
3479 (void) WriteBlobString(image,"</desc>\n");
3482 primitive_type=UndefinedPrimitive;
3490 if (LocaleCompare("affine",keyword) == 0)
3492 GetMagickToken(q,&q,token);
3493 affine.sx=StringToDouble(token);
3494 GetMagickToken(q,&q,token);
3496 GetMagickToken(q,&q,token);
3497 affine.rx=StringToDouble(token);
3498 GetMagickToken(q,&q,token);
3500 GetMagickToken(q,&q,token);
3501 affine.ry=StringToDouble(token);
3502 GetMagickToken(q,&q,token);
3504 GetMagickToken(q,&q,token);
3505 affine.sy=StringToDouble(token);
3506 GetMagickToken(q,&q,token);
3508 GetMagickToken(q,&q,token);
3509 affine.tx=StringToDouble(token);
3510 GetMagickToken(q,&q,token);
3512 GetMagickToken(q,&q,token);
3513 affine.ty=StringToDouble(token);
3516 if (LocaleCompare("angle",keyword) == 0)
3518 GetMagickToken(q,&q,token);
3519 affine.rx=StringToDouble(token);
3520 affine.ry=StringToDouble(token);
3523 if (LocaleCompare("arc",keyword) == 0)
3525 primitive_type=ArcPrimitive;
3534 if (LocaleCompare("bezier",keyword) == 0)
3536 primitive_type=BezierPrimitive;
3545 if (LocaleCompare("clip-path",keyword) == 0)
3547 GetMagickToken(q,&q,token);
3548 (void) FormatMagickString(message,MaxTextExtent,
3549 "clip-path:url(#%s);",token);
3550 (void) WriteBlobString(image,message);
3553 if (LocaleCompare("clip-rule",keyword) == 0)
3555 GetMagickToken(q,&q,token);
3556 (void) FormatMagickString(message,MaxTextExtent,
3557 "clip-rule:%s;",token);
3558 (void) WriteBlobString(image,message);
3561 if (LocaleCompare("clip-units",keyword) == 0)
3563 GetMagickToken(q,&q,token);
3564 (void) FormatMagickString(message,MaxTextExtent,
3565 "clipPathUnits=%s;",token);
3566 (void) WriteBlobString(image,message);
3569 if (LocaleCompare("circle",keyword) == 0)
3571 primitive_type=CirclePrimitive;
3574 if (LocaleCompare("color",keyword) == 0)
3576 primitive_type=ColorPrimitive;
3585 if (LocaleCompare("decorate",keyword) == 0)
3587 GetMagickToken(q,&q,token);
3588 (void) FormatMagickString(message,MaxTextExtent,
3589 "text-decoration:%s;",token);
3590 (void) WriteBlobString(image,message);
3599 if (LocaleCompare("ellipse",keyword) == 0)
3601 primitive_type=EllipsePrimitive;
3610 if (LocaleCompare("fill",keyword) == 0)
3612 GetMagickToken(q,&q,token);
3613 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3615 (void) WriteBlobString(image,message);
3618 if (LocaleCompare("fill-rule",keyword) == 0)
3620 GetMagickToken(q,&q,token);
3621 (void) FormatMagickString(message,MaxTextExtent,
3622 "fill-rule:%s;",token);
3623 (void) WriteBlobString(image,message);
3626 if (LocaleCompare("fill-opacity",keyword) == 0)
3628 GetMagickToken(q,&q,token);
3629 (void) FormatMagickString(message,MaxTextExtent,
3630 "fill-opacity:%s;",token);
3631 (void) WriteBlobString(image,message);
3634 if (LocaleCompare("font-family",keyword) == 0)
3636 GetMagickToken(q,&q,token);
3637 (void) FormatMagickString(message,MaxTextExtent,
3638 "font-family:%s;",token);
3639 (void) WriteBlobString(image,message);
3642 if (LocaleCompare("font-stretch",keyword) == 0)
3644 GetMagickToken(q,&q,token);
3645 (void) FormatMagickString(message,MaxTextExtent,
3646 "font-stretch:%s;",token);
3647 (void) WriteBlobString(image,message);
3650 if (LocaleCompare("font-style",keyword) == 0)
3652 GetMagickToken(q,&q,token);
3653 (void) FormatMagickString(message,MaxTextExtent,
3654 "font-style:%s;",token);
3655 (void) WriteBlobString(image,message);
3658 if (LocaleCompare("font-size",keyword) == 0)
3660 GetMagickToken(q,&q,token);
3661 (void) FormatMagickString(message,MaxTextExtent,
3662 "font-size:%s;",token);
3663 (void) WriteBlobString(image,message);
3666 if (LocaleCompare("font-weight",keyword) == 0)
3668 GetMagickToken(q,&q,token);
3669 (void) FormatMagickString(message,MaxTextExtent,
3670 "font-weight:%s;",token);
3671 (void) WriteBlobString(image,message);
3680 if (LocaleCompare("gradient-units",keyword) == 0)
3682 GetMagickToken(q,&q,token);
3685 if (LocaleCompare("text-align",keyword) == 0)
3687 GetMagickToken(q,&q,token);
3688 (void) FormatMagickString(message,MaxTextExtent,
3689 "text-align %s ",token);
3690 (void) WriteBlobString(image,message);
3693 if (LocaleCompare("text-anchor",keyword) == 0)
3695 GetMagickToken(q,&q,token);
3696 (void) FormatMagickString(message,MaxTextExtent,
3697 "text-anchor %s ",token);
3698 (void) WriteBlobString(image,message);
3707 if (LocaleCompare("image",keyword) == 0)
3709 GetMagickToken(q,&q,token);
3710 primitive_type=ImagePrimitive;
3719 if (LocaleCompare("line",keyword) == 0)
3721 primitive_type=LinePrimitive;
3730 if (LocaleCompare("matte",keyword) == 0)
3732 primitive_type=MattePrimitive;
3741 if (LocaleCompare("opacity",keyword) == 0)
3743 GetMagickToken(q,&q,token);
3744 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3746 (void) WriteBlobString(image,message);
3755 if (LocaleCompare("path",keyword) == 0)
3757 primitive_type=PathPrimitive;
3760 if (LocaleCompare("point",keyword) == 0)
3762 primitive_type=PointPrimitive;
3765 if (LocaleCompare("polyline",keyword) == 0)
3767 primitive_type=PolylinePrimitive;
3770 if (LocaleCompare("polygon",keyword) == 0)
3772 primitive_type=PolygonPrimitive;
3775 if (LocaleCompare("pop",keyword) == 0)
3777 GetMagickToken(q,&q,token);
3778 if (LocaleCompare("clip-path",token) == 0)
3780 (void) WriteBlobString(image,"</clipPath>\n");
3783 if (LocaleCompare("defs",token) == 0)
3785 (void) WriteBlobString(image,"</defs>\n");
3788 if (LocaleCompare("gradient",token) == 0)
3790 (void) FormatMagickString(message,MaxTextExtent,
3791 "</%sGradient>\n",type);
3792 (void) WriteBlobString(image,message);
3795 if (LocaleCompare("graphic-context",token) == 0)
3799 ThrowWriterException(DrawError,
3800 "UnbalancedGraphicContextPushPop");
3801 (void) WriteBlobString(image,"</g>\n");
3803 if (LocaleCompare("pattern",token) == 0)
3805 (void) WriteBlobString(image,"</pattern>\n");
3808 if (LocaleCompare("defs",token) == 0)
3809 (void) WriteBlobString(image,"</g>\n");
3812 if (LocaleCompare("push",keyword) == 0)
3814 GetMagickToken(q,&q,token);
3815 if (LocaleCompare("clip-path",token) == 0)
3817 GetMagickToken(q,&q,token);
3818 (void) FormatMagickString(message,MaxTextExtent,
3819 "<clipPath id=\"%s\">\n",token);
3820 (void) WriteBlobString(image,message);
3823 if (LocaleCompare("defs",token) == 0)
3825 (void) WriteBlobString(image,"<defs>\n");
3828 if (LocaleCompare("gradient",token) == 0)
3830 GetMagickToken(q,&q,token);
3831 (void) CopyMagickString(name,token,MaxTextExtent);
3832 GetMagickToken(q,&q,token);
3833 (void) CopyMagickString(type,token,MaxTextExtent);
3834 GetMagickToken(q,&q,token);
3835 svg_info.segment.x1=StringToDouble(token);
3836 svg_info.element.cx=StringToDouble(token);
3837 GetMagickToken(q,&q,token);
3839 GetMagickToken(q,&q,token);
3840 svg_info.segment.y1=StringToDouble(token);
3841 svg_info.element.cy=StringToDouble(token);
3842 GetMagickToken(q,&q,token);
3844 GetMagickToken(q,&q,token);
3845 svg_info.segment.x2=StringToDouble(token);
3846 svg_info.element.major=StringToDouble(token);
3847 GetMagickToken(q,&q,token);
3849 GetMagickToken(q,&q,token);
3850 svg_info.segment.y2=StringToDouble(token);
3851 svg_info.element.minor=StringToDouble(token);
3852 (void) FormatMagickString(message,MaxTextExtent,
3853 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3854 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3855 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3856 if (LocaleCompare(type,"radial") == 0)
3858 GetMagickToken(q,&q,token);
3860 GetMagickToken(q,&q,token);
3861 svg_info.element.angle=StringToDouble(token);
3862 (void) FormatMagickString(message,MaxTextExtent,
3863 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3864 "fx=\"%g\" fy=\"%g\">\n",type,name,
3865 svg_info.element.cx,svg_info.element.cy,
3866 svg_info.element.angle,svg_info.element.major,
3867 svg_info.element.minor);
3869 (void) WriteBlobString(image,message);
3872 if (LocaleCompare("graphic-context",token) == 0)
3877 AffineToTransform(image,&affine);
3880 (void) WriteBlobString(image,"<g style=\"");
3883 if (LocaleCompare("pattern",token) == 0)
3885 GetMagickToken(q,&q,token);
3886 (void) CopyMagickString(name,token,MaxTextExtent);
3887 GetMagickToken(q,&q,token);
3888 svg_info.bounds.x=StringToDouble(token);
3889 GetMagickToken(q,&q,token);
3891 GetMagickToken(q,&q,token);
3892 svg_info.bounds.y=StringToDouble(token);
3893 GetMagickToken(q,&q,token);
3895 GetMagickToken(q,&q,token);
3896 svg_info.bounds.width=StringToDouble(token);
3897 GetMagickToken(q,&q,token);
3899 GetMagickToken(q,&q,token);
3900 svg_info.bounds.height=StringToDouble(token);
3901 (void) FormatMagickString(message,MaxTextExtent,
3902 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3903 "height=\"%g\">\n",name,svg_info.bounds.x,
3904 svg_info.bounds.y,svg_info.bounds.width,
3905 svg_info.bounds.height);
3906 (void) WriteBlobString(image,message);
3917 if (LocaleCompare("rectangle",keyword) == 0)
3919 primitive_type=RectanglePrimitive;
3922 if (LocaleCompare("roundRectangle",keyword) == 0)
3924 primitive_type=RoundRectanglePrimitive;
3927 if (LocaleCompare("rotate",keyword) == 0)
3929 GetMagickToken(q,&q,token);
3930 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3932 (void) WriteBlobString(image,message);
3941 if (LocaleCompare("scale",keyword) == 0)
3943 GetMagickToken(q,&q,token);
3944 affine.sx=StringToDouble(token);
3945 GetMagickToken(q,&q,token);
3947 GetMagickToken(q,&q,token);
3948 affine.sy=StringToDouble(token);
3951 if (LocaleCompare("skewX",keyword) == 0)
3953 GetMagickToken(q,&q,token);
3954 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3956 (void) WriteBlobString(image,message);
3959 if (LocaleCompare("skewY",keyword) == 0)
3961 GetMagickToken(q,&q,token);
3962 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3964 (void) WriteBlobString(image,message);
3967 if (LocaleCompare("stop-color",keyword) == 0)
3970 color[MaxTextExtent];
3972 GetMagickToken(q,&q,token);
3973 (void) CopyMagickString(color,token,MaxTextExtent);
3974 GetMagickToken(q,&q,token);
3975 (void) FormatMagickString(message,MaxTextExtent,
3976 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3977 (void) WriteBlobString(image,message);
3980 if (LocaleCompare("stroke",keyword) == 0)
3982 GetMagickToken(q,&q,token);
3983 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
3985 (void) WriteBlobString(image,message);
3988 if (LocaleCompare("stroke-antialias",keyword) == 0)
3990 GetMagickToken(q,&q,token);
3991 (void) FormatMagickString(message,MaxTextExtent,
3992 "stroke-antialias:%s;",token);
3993 (void) WriteBlobString(image,message);
3996 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4004 GetMagickToken(p,&p,token);
4005 for (k=0; IsPoint(token); k++)
4006 GetMagickToken(p,&p,token);
4007 (void) WriteBlobString(image,"stroke-dasharray:");
4008 for (j=0; j < k; j++)
4010 GetMagickToken(q,&q,token);
4011 (void) FormatMagickString(message,MaxTextExtent,"%s ",
4013 (void) WriteBlobString(image,message);
4015 (void) WriteBlobString(image,";");
4018 GetMagickToken(q,&q,token);
4019 (void) FormatMagickString(message,MaxTextExtent,
4020 "stroke-dasharray:%s;",token);
4021 (void) WriteBlobString(image,message);
4024 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4026 GetMagickToken(q,&q,token);
4027 (void) FormatMagickString(message,MaxTextExtent,
4028 "stroke-dashoffset:%s;",token);
4029 (void) WriteBlobString(image,message);
4032 if (LocaleCompare("stroke-linecap",keyword) == 0)
4034 GetMagickToken(q,&q,token);
4035 (void) FormatMagickString(message,MaxTextExtent,
4036 "stroke-linecap:%s;",token);
4037 (void) WriteBlobString(image,message);
4040 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4042 GetMagickToken(q,&q,token);
4043 (void) FormatMagickString(message,MaxTextExtent,
4044 "stroke-linejoin:%s;",token);
4045 (void) WriteBlobString(image,message);
4048 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4050 GetMagickToken(q,&q,token);
4051 (void) FormatMagickString(message,MaxTextExtent,
4052 "stroke-miterlimit:%s;",token);
4053 (void) WriteBlobString(image,message);
4056 if (LocaleCompare("stroke-opacity",keyword) == 0)
4058 GetMagickToken(q,&q,token);
4059 (void) FormatMagickString(message,MaxTextExtent,
4060 "stroke-opacity:%s;",token);
4061 (void) WriteBlobString(image,message);
4064 if (LocaleCompare("stroke-width",keyword) == 0)
4066 GetMagickToken(q,&q,token);
4067 (void) FormatMagickString(message,MaxTextExtent,
4068 "stroke-width:%s;",token);
4069 (void) WriteBlobString(image,message);
4078 if (LocaleCompare("text",keyword) == 0)
4080 primitive_type=TextPrimitive;
4083 if (LocaleCompare("text-antialias",keyword) == 0)
4085 GetMagickToken(q,&q,token);
4086 (void) FormatMagickString(message,MaxTextExtent,
4087 "text-antialias:%s;",token);
4088 (void) WriteBlobString(image,message);
4091 if (LocaleCompare("tspan",keyword) == 0)
4093 primitive_type=TextPrimitive;
4096 if (LocaleCompare("translate",keyword) == 0)
4098 GetMagickToken(q,&q,token);
4099 affine.tx=StringToDouble(token);
4100 GetMagickToken(q,&q,token);
4102 GetMagickToken(q,&q,token);
4103 affine.ty=StringToDouble(token);
4112 if (LocaleCompare("viewbox",keyword) == 0)
4114 GetMagickToken(q,&q,token);
4116 GetMagickToken(q,&q,token);
4117 GetMagickToken(q,&q,token);
4119 GetMagickToken(q,&q,token);
4120 GetMagickToken(q,&q,token);
4122 GetMagickToken(q,&q,token);
4123 GetMagickToken(q,&q,token);
4135 if (status == MagickFalse)
4137 if (primitive_type == UndefinedPrimitive)
4140 Parse the primitive attributes.
4144 for (x=0; *q != '\0'; x++)
4149 if (IsPoint(q) == MagickFalse)
4151 GetMagickToken(q,&q,token);
4152 point.x=StringToDouble(token);
4153 GetMagickToken(q,&q,token);
4155 GetMagickToken(q,&q,token);
4156 point.y=StringToDouble(token);
4157 GetMagickToken(q,(const char **) NULL,token);
4159 GetMagickToken(q,&q,token);
4160 primitive_info[i].primitive=primitive_type;
4161 primitive_info[i].point=point;
4162 primitive_info[i].coordinates=0;
4163 primitive_info[i].method=FloodfillMethod;
4165 if (i < (long) (number_points-6*BezierQuantum-360))
4167 number_points+=6*BezierQuantum+360;
4168 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4169 number_points,sizeof(*primitive_info));
4170 if (primitive_info == (PrimitiveInfo *) NULL)
4172 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4173 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4177 primitive_info[j].primitive=primitive_type;
4178 primitive_info[j].coordinates=x;
4179 primitive_info[j].method=FloodfillMethod;
4180 primitive_info[j].text=(char *) NULL;
4183 AffineToTransform(image,&affine);
4187 switch (primitive_type)
4189 case PointPrimitive:
4192 if (primitive_info[j].coordinates != 1)
4201 if (primitive_info[j].coordinates != 2)
4206 (void) FormatMagickString(message,MaxTextExtent,
4207 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4208 primitive_info[j].point.x,primitive_info[j].point.y,
4209 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4210 (void) WriteBlobString(image,message);
4213 case RectanglePrimitive:
4215 if (primitive_info[j].coordinates != 2)
4220 (void) FormatMagickString(message,MaxTextExtent,
4221 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4222 primitive_info[j].point.x,primitive_info[j].point.y,
4223 primitive_info[j+1].point.x-primitive_info[j].point.x,
4224 primitive_info[j+1].point.y-primitive_info[j].point.y);
4225 (void) WriteBlobString(image,message);
4228 case RoundRectanglePrimitive:
4230 if (primitive_info[j].coordinates != 3)
4235 (void) FormatMagickString(message,MaxTextExtent,
4236 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4237 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4238 primitive_info[j].point.y,primitive_info[j+1].point.x-
4239 primitive_info[j].point.x,primitive_info[j+1].point.y-
4240 primitive_info[j].point.y,primitive_info[j+2].point.x,
4241 primitive_info[j+2].point.y);
4242 (void) WriteBlobString(image,message);
4247 if (primitive_info[j].coordinates != 3)
4254 case EllipsePrimitive:
4256 if (primitive_info[j].coordinates != 3)
4261 (void) FormatMagickString(message,MaxTextExtent,
4262 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4263 primitive_info[j].point.x,primitive_info[j].point.y,
4264 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4265 (void) WriteBlobString(image,message);
4268 case CirclePrimitive:
4274 if (primitive_info[j].coordinates != 2)
4279 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4280 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4281 (void) FormatMagickString(message,MaxTextExtent,
4282 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4283 primitive_info[j].point.x,primitive_info[j].point.y,
4285 (void) WriteBlobString(image,message);
4288 case PolylinePrimitive:
4290 if (primitive_info[j].coordinates < 2)
4295 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4296 (void) WriteBlobString(image,message);
4297 length=strlen(message);
4300 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4301 primitive_info[j].point.x,primitive_info[j].point.y);
4302 length+=strlen(message);
4305 (void) WriteBlobString(image,"\n ");
4306 length=strlen(message)+5;
4308 (void) WriteBlobString(image,message);
4310 (void) WriteBlobString(image,"\"/>\n");
4313 case PolygonPrimitive:
4315 if (primitive_info[j].coordinates < 3)
4320 primitive_info[i]=primitive_info[j];
4321 primitive_info[i].coordinates=0;
4322 primitive_info[j].coordinates++;
4324 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4325 (void) WriteBlobString(image,message);
4326 length=strlen(message);
4329 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4330 primitive_info[j].point.x,primitive_info[j].point.y);
4331 length+=strlen(message);
4334 (void) WriteBlobString(image,"\n ");
4335 length=strlen(message)+5;
4337 (void) WriteBlobString(image,message);
4339 (void) WriteBlobString(image,"\"/>\n");
4342 case BezierPrimitive:
4344 if (primitive_info[j].coordinates < 3)
4356 GetMagickToken(q,&q,token);
4357 number_attributes=1;
4358 for (p=token; *p != '\0'; p++)
4359 if (isalpha((int) *p))
4360 number_attributes++;
4361 if (i > (long) (number_points-6*BezierQuantum*number_attributes-1))
4363 number_points+=6*BezierQuantum*number_attributes;
4364 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4365 number_points,sizeof(*primitive_info));
4366 if (primitive_info == (PrimitiveInfo *) NULL)
4368 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4369 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4374 (void) WriteBlobString(image," <path d=\"");
4375 (void) WriteBlobString(image,token);
4376 (void) WriteBlobString(image,"\"/>\n");
4379 case ColorPrimitive:
4380 case MattePrimitive:
4382 if (primitive_info[j].coordinates != 1)
4387 GetMagickToken(q,&q,token);
4388 if (LocaleCompare("point",token) == 0)
4389 primitive_info[j].method=PointMethod;
4390 if (LocaleCompare("replace",token) == 0)
4391 primitive_info[j].method=ReplaceMethod;
4392 if (LocaleCompare("floodfill",token) == 0)
4393 primitive_info[j].method=FloodfillMethod;
4394 if (LocaleCompare("filltoborder",token) == 0)
4395 primitive_info[j].method=FillToBorderMethod;
4396 if (LocaleCompare("reset",token) == 0)
4397 primitive_info[j].method=ResetMethod;
4405 if (primitive_info[j].coordinates != 1)
4410 GetMagickToken(q,&q,token);
4411 (void) FormatMagickString(message,MaxTextExtent,
4412 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4413 primitive_info[j].point.y);
4414 (void) WriteBlobString(image,message);
4415 for (p=token; *p != '\0'; p++)
4418 case '<': (void) WriteBlobString(image,"<"); break;
4419 case '>': (void) WriteBlobString(image,">"); break;
4420 case '&': (void) WriteBlobString(image,"&"); break;
4421 default: (void) WriteBlobByte(image,*p); break;
4423 (void) WriteBlobString(image,"</text>\n");
4426 case ImagePrimitive:
4428 if (primitive_info[j].coordinates != 2)
4433 GetMagickToken(q,&q,token);
4434 (void) FormatMagickString(message,MaxTextExtent,
4435 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4436 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4437 primitive_info[j].point.y,primitive_info[j+1].point.x,
4438 primitive_info[j+1].point.y,token);
4439 (void) WriteBlobString(image,message);
4443 if (primitive_info == (PrimitiveInfo *) NULL)
4445 primitive_info[i].primitive=UndefinedPrimitive;
4446 if (status == MagickFalse)
4449 (void) WriteBlobString(image,"</svg>\n");
4451 Relinquish resources.
4453 token=DestroyString(token);
4454 if (primitive_info != (PrimitiveInfo *) NULL)
4455 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4456 (void) CloseBlob(image);