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 *) AcquireMagickMemory(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 *) AcquireMagickMemory(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);
952 if (strchr((char *) name,':') != (char *) NULL)
957 for ( ; *name != ':'; name++) ;
965 if (LocaleCompare((const char *) name,"circle") == 0)
967 MVGPrintf(svg_info->file,"push graphic-context\n");
970 if (LocaleCompare((const char *) name,"clipPath") == 0)
972 MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
980 if (LocaleCompare((const char *) name,"defs") == 0)
982 MVGPrintf(svg_info->file,"push defs\n");
990 if (LocaleCompare((const char *) name,"ellipse") == 0)
992 MVGPrintf(svg_info->file,"push graphic-context\n");
1000 if (LocaleCompare((const char *) name,"g") == 0)
1002 MVGPrintf(svg_info->file,"push graphic-context\n");
1010 if (LocaleCompare((const char *) name,"image") == 0)
1012 MVGPrintf(svg_info->file,"push graphic-context\n");
1020 if (LocaleCompare((const char *) name,"line") == 0)
1022 MVGPrintf(svg_info->file,"push graphic-context\n");
1025 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1027 MVGPrintf(svg_info->file,
1028 "push gradient '%s' linear %g,%g %g,%g\n",id,
1029 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1030 svg_info->segment.y2);
1038 if (LocaleCompare((const char *) name,"path") == 0)
1040 MVGPrintf(svg_info->file,"push graphic-context\n");
1043 if (LocaleCompare((const char *) name,"pattern") == 0)
1045 MVGPrintf(svg_info->file,
1046 "push pattern '%s' %g,%g %g,%g\n",id,
1047 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1048 svg_info->bounds.height);
1051 if (LocaleCompare((const char *) name,"polygon") == 0)
1053 MVGPrintf(svg_info->file,"push graphic-context\n");
1056 if (LocaleCompare((const char *) name,"polyline") == 0)
1058 MVGPrintf(svg_info->file,"push graphic-context\n");
1066 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1068 MVGPrintf(svg_info->file,
1069 "push gradient '%s' radial %g,%g %g,%g %g\n",
1070 id,svg_info->element.cx,svg_info->element.cy,
1071 svg_info->element.major,svg_info->element.minor,
1072 svg_info->element.angle);
1075 if (LocaleCompare((const char *) name,"rect") == 0)
1077 MVGPrintf(svg_info->file,"push graphic-context\n");
1085 if (LocaleCompare((const char *) name,"svg") == 0)
1087 MVGPrintf(svg_info->file,"push graphic-context\n");
1095 if (LocaleCompare((const char *) name,"text") == 0)
1097 MVGPrintf(svg_info->file,"push graphic-context\n");
1100 if (LocaleCompare((const char *) name,"tspan") == 0)
1102 if (*svg_info->text != '\0')
1113 text=EscapeString(svg_info->text,'\'');
1114 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
1115 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1116 svg_info->center.y,text);
1117 text=DestroyString(text);
1118 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1119 draw_info->pointsize=svg_info->pointsize;
1120 draw_info->text=AcquireString(svg_info->text);
1121 (void) ConcatenateString(&draw_info->text," ");
1122 GetTypeMetrics(svg_info->image,draw_info,&metrics);
1123 svg_info->bounds.x+=metrics.width;
1124 draw_info=DestroyDrawInfo(draw_info);
1125 *svg_info->text='\0';
1127 MVGPrintf(svg_info->file,"push graphic-context\n");
1135 if (attributes != (const xmlChar **) NULL)
1136 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1138 keyword=(const char *) attributes[i];
1139 value=(const char *) attributes[i+1];
1140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1141 " %s = %s",keyword,value);
1147 if (LocaleCompare(keyword,"angle") == 0)
1149 MVGPrintf(svg_info->file,"angle %g\n",
1150 GetUserSpaceCoordinateValue(svg_info,0,value));
1158 if (LocaleCompare(keyword,"clip-path") == 0)
1160 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1163 if (LocaleCompare(keyword,"clip-rule") == 0)
1165 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1168 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1170 (void) CloneString(&units,value);
1171 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1174 if (LocaleCompare(keyword,"color") == 0)
1176 (void) CloneString(&color,value);
1179 if (LocaleCompare(keyword,"cx") == 0)
1181 svg_info->element.cx=
1182 GetUserSpaceCoordinateValue(svg_info,1,value);
1185 if (LocaleCompare(keyword,"cy") == 0)
1187 svg_info->element.cy=
1188 GetUserSpaceCoordinateValue(svg_info,-1,value);
1196 if (LocaleCompare(keyword,"d") == 0)
1198 (void) CloneString(&svg_info->vertices,value);
1201 if (LocaleCompare(keyword,"dx") == 0)
1203 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1206 if (LocaleCompare(keyword,"dy") == 0)
1208 svg_info->bounds.y+=
1209 GetUserSpaceCoordinateValue(svg_info,-1,value);
1217 if (LocaleCompare(keyword,"fill") == 0)
1219 if (LocaleCompare(value,"currentColor") == 0)
1221 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1224 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1227 if (LocaleCompare(keyword,"fillcolor") == 0)
1229 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1232 if (LocaleCompare(keyword,"fill-rule") == 0)
1234 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1237 if (LocaleCompare(keyword,"fill-opacity") == 0)
1239 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1242 if (LocaleCompare(keyword,"font-family") == 0)
1244 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1247 if (LocaleCompare(keyword,"font-stretch") == 0)
1249 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1252 if (LocaleCompare(keyword,"font-style") == 0)
1254 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1257 if (LocaleCompare(keyword,"font-size") == 0)
1259 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1260 MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1263 if (LocaleCompare(keyword,"font-weight") == 0)
1265 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1273 if (LocaleCompare(keyword,"gradientTransform") == 0)
1280 GetAffineMatrix(&transform);
1281 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1282 tokens=GetTransformTokens(context,value,&number_tokens);
1283 for (j=0; j < (number_tokens-1); j+=2)
1285 keyword=(char *) tokens[j];
1286 if (keyword == (char *) NULL)
1288 value=(char *) tokens[j+1];
1289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1290 " %s: %s",keyword,value);
1292 GetAffineMatrix(&affine);
1298 if (LocaleCompare(keyword,"matrix") == 0)
1300 p=(const char *) value;
1301 GetMagickToken(p,&p,token);
1302 affine.sx=StringToDouble(value);
1303 GetMagickToken(p,&p,token);
1305 GetMagickToken(p,&p,token);
1306 affine.rx=StringToDouble(token);
1307 GetMagickToken(p,&p,token);
1309 GetMagickToken(p,&p,token);
1310 affine.ry=StringToDouble(token);
1311 GetMagickToken(p,&p,token);
1313 GetMagickToken(p,&p,token);
1314 affine.sy=StringToDouble(token);
1315 GetMagickToken(p,&p,token);
1317 GetMagickToken(p,&p,token);
1318 affine.tx=StringToDouble(token);
1319 GetMagickToken(p,&p,token);
1321 GetMagickToken(p,&p,token);
1322 affine.ty=StringToDouble(token);
1330 if (LocaleCompare(keyword,"rotate") == 0)
1335 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1336 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1337 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1338 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1339 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1347 if (LocaleCompare(keyword,"scale") == 0)
1349 for (p=(const char *) value; *p != '\0'; p++)
1350 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1353 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1354 affine.sy=affine.sx;
1357 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1358 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1361 if (LocaleCompare(keyword,"skewX") == 0)
1363 affine.sx=svg_info->affine.sx;
1364 affine.ry=tan(DegreesToRadians(fmod(
1365 GetUserSpaceCoordinateValue(svg_info,1,value),
1367 affine.sy=svg_info->affine.sy;
1370 if (LocaleCompare(keyword,"skewY") == 0)
1372 affine.sx=svg_info->affine.sx;
1373 affine.rx=tan(DegreesToRadians(fmod(
1374 GetUserSpaceCoordinateValue(svg_info,-1,value),
1376 affine.sy=svg_info->affine.sy;
1384 if (LocaleCompare(keyword,"translate") == 0)
1386 for (p=(const char *) value; *p != '\0'; p++)
1387 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1390 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1391 affine.ty=affine.tx;
1394 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1402 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1403 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1404 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1405 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1406 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
1408 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
1411 MVGPrintf(svg_info->file,
1412 "affine %g %g %g %g %g %g\n",transform.sx,
1413 transform.rx,transform.ry,transform.sy,transform.tx,
1415 for (j=0; tokens[j] != (char *) NULL; j++)
1416 tokens[j]=DestroyString(tokens[j]);
1417 tokens=(char **) RelinquishMagickMemory(tokens);
1420 if (LocaleCompare(keyword,"gradientUnits") == 0)
1422 (void) CloneString(&units,value);
1423 MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1431 if (LocaleCompare(keyword,"height") == 0)
1433 svg_info->bounds.height=
1434 GetUserSpaceCoordinateValue(svg_info,-1,value);
1437 if (LocaleCompare(keyword,"href") == 0)
1439 (void) CloneString(&svg_info->url,value);
1447 if (LocaleCompare(keyword,"major") == 0)
1449 svg_info->element.major=
1450 GetUserSpaceCoordinateValue(svg_info,1,value);
1453 if (LocaleCompare(keyword,"minor") == 0)
1455 svg_info->element.minor=
1456 GetUserSpaceCoordinateValue(svg_info,-1,value);
1464 if (LocaleCompare(keyword,"offset") == 0)
1466 (void) CloneString(&svg_info->offset,value);
1469 if (LocaleCompare(keyword,"opacity") == 0)
1471 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1479 if (LocaleCompare(keyword,"path") == 0)
1481 (void) CloneString(&svg_info->url,value);
1484 if (LocaleCompare(keyword,"points") == 0)
1486 (void) CloneString(&svg_info->vertices,value);
1494 if (LocaleCompare(keyword,"r") == 0)
1496 svg_info->element.major=
1497 GetUserSpaceCoordinateValue(svg_info,1,value);
1498 svg_info->element.minor=
1499 GetUserSpaceCoordinateValue(svg_info,-1,value);
1502 if (LocaleCompare(keyword,"rotate") == 0)
1507 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1508 MVGPrintf(svg_info->file,"translate %g,%g\n",
1509 svg_info->bounds.x,svg_info->bounds.y);
1510 svg_info->bounds.x=0;
1511 svg_info->bounds.y=0;
1512 MVGPrintf(svg_info->file,"rotate %g\n",angle);
1515 if (LocaleCompare(keyword,"rx") == 0)
1517 if (LocaleCompare((const char *) name,"ellipse") == 0)
1518 svg_info->element.major=
1519 GetUserSpaceCoordinateValue(svg_info,1,value);
1522 GetUserSpaceCoordinateValue(svg_info,1,value);
1525 if (LocaleCompare(keyword,"ry") == 0)
1527 if (LocaleCompare((const char *) name,"ellipse") == 0)
1528 svg_info->element.minor=
1529 GetUserSpaceCoordinateValue(svg_info,-1,value);
1532 GetUserSpaceCoordinateValue(svg_info,-1,value);
1540 if (LocaleCompare(keyword,"stop-color") == 0)
1542 (void) CloneString(&svg_info->stop_color,value);
1545 if (LocaleCompare(keyword,"stroke") == 0)
1547 if (LocaleCompare(value,"currentColor") == 0)
1549 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1552 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1555 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1557 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1558 LocaleCompare(value,"true") == 0);
1561 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1563 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1566 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1568 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1571 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1573 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1576 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1578 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1581 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1583 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1586 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1588 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1591 if (LocaleCompare(keyword,"stroke-width") == 0)
1593 MVGPrintf(svg_info->file,"stroke-width %g\n",
1594 GetUserSpaceCoordinateValue(svg_info,1,value));
1597 if (LocaleCompare(keyword,"style") == 0)
1599 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1600 tokens=GetStyleTokens(context,value,&number_tokens);
1601 for (j=0; j < (number_tokens-1); j+=2)
1603 keyword=(char *) tokens[j];
1604 value=(char *) tokens[j+1];
1605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1606 " %s: %s",keyword,value);
1612 if (LocaleCompare(keyword,"clip-path") == 0)
1614 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1617 if (LocaleCompare(keyword,"clip-rule") == 0)
1619 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1622 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1624 (void) CloneString(&units,value);
1625 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1628 if (LocaleCompare(keyword,"color") == 0)
1630 (void) CloneString(&color,value);
1638 if (LocaleCompare(keyword,"fill") == 0)
1640 if (LocaleCompare(value,"currentColor") == 0)
1642 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1645 if (LocaleCompare(value,"#00000000") == 0)
1646 MVGPrintf(svg_info->file,"fill '#000000'\n");
1648 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1651 if (LocaleCompare(keyword,"fillcolor") == 0)
1653 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1656 if (LocaleCompare(keyword,"fill-rule") == 0)
1658 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1661 if (LocaleCompare(keyword,"fill-opacity") == 0)
1663 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1666 if (LocaleCompare(keyword,"font-family") == 0)
1668 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1671 if (LocaleCompare(keyword,"font-stretch") == 0)
1673 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1676 if (LocaleCompare(keyword,"font-style") == 0)
1678 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1681 if (LocaleCompare(keyword,"font-size") == 0)
1683 svg_info->pointsize=GetUserSpaceCoordinateValue(
1685 MVGPrintf(svg_info->file,"font-size %g\n",
1686 svg_info->pointsize);
1689 if (LocaleCompare(keyword,"font-weight") == 0)
1691 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1699 if (LocaleCompare(keyword,"offset") == 0)
1701 MVGPrintf(svg_info->file,"offset %g\n",
1702 GetUserSpaceCoordinateValue(svg_info,1,value));
1705 if (LocaleCompare(keyword,"opacity") == 0)
1707 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1715 if (LocaleCompare(keyword,"stop-color") == 0)
1717 (void) CloneString(&svg_info->stop_color,value);
1720 if (LocaleCompare(keyword,"stroke") == 0)
1722 if (LocaleCompare(value,"currentColor") == 0)
1724 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1727 if (LocaleCompare(value,"#00000000") == 0)
1728 MVGPrintf(svg_info->file,"fill '#000000'\n");
1730 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1733 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1735 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1736 LocaleCompare(value,"true") == 0);
1739 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1741 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1744 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1746 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1750 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1752 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1755 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1757 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1761 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1763 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1767 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1769 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1772 if (LocaleCompare(keyword,"stroke-width") == 0)
1774 MVGPrintf(svg_info->file,"stroke-width %g\n",
1775 GetUserSpaceCoordinateValue(svg_info,1,value));
1783 if (LocaleCompare(keyword,"text-align") == 0)
1785 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1788 if (LocaleCompare(keyword,"text-anchor") == 0)
1790 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1793 if (LocaleCompare(keyword,"text-decoration") == 0)
1795 if (LocaleCompare(value,"underline") == 0)
1796 MVGPrintf(svg_info->file,"decorate underline\n");
1797 if (LocaleCompare(value,"line-through") == 0)
1798 MVGPrintf(svg_info->file,"decorate line-through\n");
1799 if (LocaleCompare(value,"overline") == 0)
1800 MVGPrintf(svg_info->file,"decorate overline\n");
1803 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1805 MVGPrintf(svg_info->file,"text-antialias %d\n",
1806 LocaleCompare(value,"true") == 0);
1815 for (j=0; tokens[j] != (char *) NULL; j++)
1816 tokens[j]=DestroyString(tokens[j]);
1817 tokens=(char **) RelinquishMagickMemory(tokens);
1825 if (LocaleCompare(keyword,"text-align") == 0)
1827 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1830 if (LocaleCompare(keyword,"text-anchor") == 0)
1832 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1835 if (LocaleCompare(keyword,"text-decoration") == 0)
1837 if (LocaleCompare(value,"underline") == 0)
1838 MVGPrintf(svg_info->file,"decorate underline\n");
1839 if (LocaleCompare(value,"line-through") == 0)
1840 MVGPrintf(svg_info->file,"decorate line-through\n");
1841 if (LocaleCompare(value,"overline") == 0)
1842 MVGPrintf(svg_info->file,"decorate overline\n");
1845 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1847 MVGPrintf(svg_info->file,"text-antialias %d\n",
1848 LocaleCompare(value,"true") == 0);
1851 if (LocaleCompare(keyword,"transform") == 0)
1858 GetAffineMatrix(&transform);
1859 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1860 tokens=GetTransformTokens(context,value,&number_tokens);
1861 for (j=0; j < (number_tokens-1); j+=2)
1863 keyword=(char *) tokens[j];
1864 value=(char *) tokens[j+1];
1865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1866 " %s: %s",keyword,value);
1868 GetAffineMatrix(&affine);
1874 if (LocaleCompare(keyword,"matrix") == 0)
1876 p=(const char *) value;
1877 GetMagickToken(p,&p,token);
1878 affine.sx=StringToDouble(value);
1879 GetMagickToken(p,&p,token);
1881 GetMagickToken(p,&p,token);
1882 affine.rx=StringToDouble(token);
1883 GetMagickToken(p,&p,token);
1885 GetMagickToken(p,&p,token);
1886 affine.ry=StringToDouble(token);
1887 GetMagickToken(p,&p,token);
1889 GetMagickToken(p,&p,token);
1890 affine.sy=StringToDouble(token);
1891 GetMagickToken(p,&p,token);
1893 GetMagickToken(p,&p,token);
1894 affine.tx=StringToDouble(token);
1895 GetMagickToken(p,&p,token);
1897 GetMagickToken(p,&p,token);
1898 affine.ty=StringToDouble(token);
1906 if (LocaleCompare(keyword,"rotate") == 0)
1913 p=(const char *) value;
1914 GetMagickToken(p,&p,token);
1915 angle=StringToDouble(value);
1916 GetMagickToken(p,&p,token);
1918 GetMagickToken(p,&p,token);
1919 x=StringToDouble(token);
1920 GetMagickToken(p,&p,token);
1922 GetMagickToken(p,&p,token);
1923 y=StringToDouble(token);
1924 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1925 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1926 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1927 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1930 svg_info->center.x=x;
1931 svg_info->center.y=y;
1939 if (LocaleCompare(keyword,"scale") == 0)
1941 for (p=(const char *) value; *p != '\0'; p++)
1942 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1945 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1946 affine.sy=affine.sx;
1948 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1950 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1953 if (LocaleCompare(keyword,"skewX") == 0)
1955 affine.sx=svg_info->affine.sx;
1956 affine.ry=tan(DegreesToRadians(fmod(
1957 GetUserSpaceCoordinateValue(svg_info,1,value),
1959 affine.sy=svg_info->affine.sy;
1962 if (LocaleCompare(keyword,"skewY") == 0)
1964 affine.sx=svg_info->affine.sx;
1965 affine.rx=tan(DegreesToRadians(fmod(
1966 GetUserSpaceCoordinateValue(svg_info,-1,value),
1968 affine.sy=svg_info->affine.sy;
1976 if (LocaleCompare(keyword,"translate") == 0)
1978 for (p=(const char *) value; *p != '\0'; p++)
1979 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1982 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1983 affine.ty=affine.tx;
1985 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
1994 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1995 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1996 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1997 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1998 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
2000 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
2003 MVGPrintf(svg_info->file,
2004 "affine %g %g %g %g %g %g\n",transform.sx,
2005 transform.rx,transform.ry,transform.sy,transform.tx,
2007 for (j=0; tokens[j] != (char *) NULL; j++)
2008 tokens[j]=DestroyString(tokens[j]);
2009 tokens=(char **) RelinquishMagickMemory(tokens);
2017 if (LocaleCompare(keyword,"verts") == 0)
2019 (void) CloneString(&svg_info->vertices,value);
2022 if (LocaleCompare(keyword,"viewBox") == 0)
2024 p=(const char *) value;
2025 GetMagickToken(p,&p,token);
2026 svg_info->view_box.x=StringToDouble(token);
2027 GetMagickToken(p,&p,token);
2029 GetMagickToken(p,&p,token);
2030 svg_info->view_box.y=StringToDouble(token);
2031 GetMagickToken(p,&p,token);
2033 GetMagickToken(p,&p,token);
2034 svg_info->view_box.width=StringToDouble(token);
2035 if (svg_info->bounds.width == 0)
2036 svg_info->bounds.width=svg_info->view_box.width;
2037 GetMagickToken(p,&p,token);
2039 GetMagickToken(p,&p,token);
2040 svg_info->view_box.height=StringToDouble(token);
2041 if (svg_info->bounds.height == 0)
2042 svg_info->bounds.height=svg_info->view_box.height;
2050 if (LocaleCompare(keyword,"width") == 0)
2052 svg_info->bounds.width=
2053 GetUserSpaceCoordinateValue(svg_info,1,value);
2061 if (LocaleCompare(keyword,"x") == 0)
2063 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2066 if (LocaleCompare(keyword,"xlink:href") == 0)
2068 (void) CloneString(&svg_info->url,value);
2071 if (LocaleCompare(keyword,"x1") == 0)
2073 svg_info->segment.x1=
2074 GetUserSpaceCoordinateValue(svg_info,1,value);
2077 if (LocaleCompare(keyword,"x2") == 0)
2079 svg_info->segment.x2=
2080 GetUserSpaceCoordinateValue(svg_info,1,value);
2088 if (LocaleCompare(keyword,"y") == 0)
2090 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2093 if (LocaleCompare(keyword,"y1") == 0)
2095 svg_info->segment.y1=
2096 GetUserSpaceCoordinateValue(svg_info,-1,value);
2099 if (LocaleCompare(keyword,"y2") == 0)
2101 svg_info->segment.y2=
2102 GetUserSpaceCoordinateValue(svg_info,-1,value);
2111 if (LocaleCompare((const char *) name,"svg") == 0)
2113 if (svg_info->document->encoding != (const xmlChar *) NULL)
2114 MVGPrintf(svg_info->file,"encoding \"%s\"\n",
2115 (const char *) svg_info->document->encoding);
2116 if (attributes != (const xmlChar **) NULL)
2122 if ((svg_info->view_box.width == 0.0) ||
2123 (svg_info->view_box.height == 0.0))
2124 svg_info->view_box=svg_info->bounds;
2125 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2126 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2127 MVGPrintf(svg_info->file,"viewbox 0 0 %.20g %.20g\n",(double)
2128 svg_info->width,(double) svg_info->height);
2129 sx=(double) svg_info->width/svg_info->view_box.width;
2130 sy=(double) svg_info->height/svg_info->view_box.height;
2131 MVGPrintf(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",sx,sy);
2134 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2135 units=DestroyString(units);
2136 if (color != (char *) NULL)
2137 color=DestroyString(color);
2140 static void SVGEndElement(void *context,const xmlChar *name)
2146 Called when the end of an element has been detected.
2148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2149 " SAX.endElement(%s)",name);
2150 svg_info=(SVGInfo *) context;
2151 if (strchr((char *) name,':') != (char *) NULL)
2154 Skip over namespace.
2156 for ( ; *name != ':'; name++) ;
2164 if (LocaleCompare((const char *) name,"circle") == 0)
2166 MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",
2167 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2168 svg_info->element.cy+svg_info->element.minor);
2169 MVGPrintf(svg_info->file,"pop graphic-context\n");
2172 if (LocaleCompare((const char *) name,"clipPath") == 0)
2174 MVGPrintf(svg_info->file,"pop clip-path\n");
2182 if (LocaleCompare((const char *) name,"defs") == 0)
2184 MVGPrintf(svg_info->file,"pop defs\n");
2187 if (LocaleCompare((const char *) name,"desc") == 0)
2192 if (*svg_info->text == '\0')
2194 (void) fputc('#',svg_info->file);
2195 for (p=svg_info->text; *p != '\0'; p++)
2197 (void) fputc(*p,svg_info->file);
2199 (void) fputc('#',svg_info->file);
2201 (void) fputc('\n',svg_info->file);
2202 *svg_info->text='\0';
2210 if (LocaleCompare((const char *) name,"ellipse") == 0)
2215 angle=svg_info->element.angle;
2216 MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2217 svg_info->element.cx,svg_info->element.cy,
2218 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2219 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2220 MVGPrintf(svg_info->file,"pop graphic-context\n");
2228 if (LocaleCompare((const char *) name,"g") == 0)
2230 MVGPrintf(svg_info->file,"pop graphic-context\n");
2238 if (LocaleCompare((const char *) name,"image") == 0)
2240 MVGPrintf(svg_info->file,"image Over %g,%g %g,%g '%s'\n",
2241 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2242 svg_info->bounds.height,svg_info->url);
2243 MVGPrintf(svg_info->file,"pop graphic-context\n");
2251 if (LocaleCompare((const char *) name,"line") == 0)
2253 MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",
2254 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2255 svg_info->segment.y2);
2256 MVGPrintf(svg_info->file,"pop graphic-context\n");
2259 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2261 MVGPrintf(svg_info->file,"pop gradient\n");
2269 if (LocaleCompare((const char *) name,"pattern") == 0)
2271 MVGPrintf(svg_info->file,"pop pattern\n");
2274 if (LocaleCompare((const char *) name,"path") == 0)
2276 MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2277 MVGPrintf(svg_info->file,"pop graphic-context\n");
2280 if (LocaleCompare((const char *) name,"polygon") == 0)
2282 MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2283 MVGPrintf(svg_info->file,"pop graphic-context\n");
2286 if (LocaleCompare((const char *) name,"polyline") == 0)
2288 MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2289 MVGPrintf(svg_info->file,"pop graphic-context\n");
2297 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2299 MVGPrintf(svg_info->file,"pop gradient\n");
2302 if (LocaleCompare((const char *) name,"rect") == 0)
2304 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2306 MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2307 svg_info->bounds.x,svg_info->bounds.y,
2308 svg_info->bounds.x+svg_info->bounds.width,
2309 svg_info->bounds.y+svg_info->bounds.height);
2310 MVGPrintf(svg_info->file,"pop graphic-context\n");
2313 if (svg_info->radius.x == 0.0)
2314 svg_info->radius.x=svg_info->radius.y;
2315 if (svg_info->radius.y == 0.0)
2316 svg_info->radius.y=svg_info->radius.x;
2317 MVGPrintf(svg_info->file,
2318 "roundRectangle %g,%g %g,%g %g,%g\n",
2319 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2320 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2321 svg_info->radius.x,svg_info->radius.y);
2322 svg_info->radius.x=0.0;
2323 svg_info->radius.y=0.0;
2324 MVGPrintf(svg_info->file,"pop graphic-context\n");
2332 if (LocaleCompare((const char *) name,"stop") == 0)
2334 MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2338 if (LocaleCompare((const char *) name,"svg") == 0)
2340 MVGPrintf(svg_info->file,"pop graphic-context\n");
2348 if (LocaleCompare((const char *) name,"text") == 0)
2350 if (*svg_info->text != '\0')
2355 text=EscapeString(svg_info->text,'\'');
2357 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
2358 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
2359 svg_info->center.y,text);
2360 text=DestroyString(text);
2361 *svg_info->text='\0';
2363 MVGPrintf(svg_info->file,"pop graphic-context\n");
2366 if (LocaleCompare((const char *) name,"tspan") == 0)
2368 if (*svg_info->text != '\0')
2379 text=EscapeString(svg_info->text,'\'');
2381 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
2382 svg_info->bounds.x,svg_info->bounds.y,text);
2383 text=DestroyString(text);
2384 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2385 draw_info->pointsize=svg_info->pointsize;
2386 draw_info->text=AcquireString(svg_info->text);
2387 (void) ConcatenateString(&draw_info->text," ");
2388 GetTypeMetrics(svg_info->image,draw_info,&metrics);
2389 svg_info->bounds.x+=metrics.width;
2390 draw_info=DestroyDrawInfo(draw_info);
2391 *svg_info->text='\0';
2393 MVGPrintf(svg_info->file,"pop graphic-context\n");
2396 if (LocaleCompare((const char *) name,"title") == 0)
2398 if (*svg_info->text == '\0')
2400 (void) CloneString(&svg_info->title,svg_info->text);
2401 *svg_info->text='\0';
2409 *svg_info->text='\0';
2410 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2411 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2415 static void SVGCharacters(void *context,const xmlChar *c,int length)
2427 Receiving some characters from the parser.
2429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2430 " SAX.characters(%s,%.20g)",c,(double) length);
2431 svg_info=(SVGInfo *) context;
2432 if (svg_info->text != (char *) NULL)
2433 svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
2434 strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
2437 svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2438 sizeof(*svg_info->text));
2439 if (svg_info->text != (char *) NULL)
2440 *svg_info->text='\0';
2442 if (svg_info->text == (char *) NULL)
2444 p=svg_info->text+strlen(svg_info->text);
2445 for (i=0; i < (ssize_t) length; i++)
2450 static void SVGReference(void *context,const xmlChar *name)
2459 Called when an entity reference is detected.
2461 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2463 svg_info=(SVGInfo *) context;
2464 parser=svg_info->parser;
2465 if (parser == (xmlParserCtxtPtr) NULL)
2467 if (parser->node == (xmlNodePtr) NULL)
2470 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2472 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2475 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2481 Receiving some ignorable whitespaces from the parser.
2483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2484 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2485 svg_info=(SVGInfo *) context;
2488 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2489 const xmlChar *data)
2495 A processing instruction has been parsed.
2497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2498 " SAX.processingInstruction(%s, %s)",target,data);
2499 svg_info=(SVGInfo *) context;
2502 static void SVGComment(void *context,const xmlChar *value)
2508 A comment has been parsed.
2510 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2512 svg_info=(SVGInfo *) context;
2513 if (svg_info->comment != (char *) NULL)
2514 (void) ConcatenateString(&svg_info->comment,"\n");
2515 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2518 static void SVGWarning(void *context,const char *format,...)
2522 reason[MaxTextExtent];
2531 Display and format a warning messages, gives file, line, position and
2534 va_start(operands,format);
2535 svg_info=(SVGInfo *) context;
2536 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2538 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2539 (void) vsprintf(reason,format,operands);
2541 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2543 message=GetExceptionMessage(errno);
2544 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2545 DelegateWarning,reason,"`%s`",message);
2546 message=DestroyString(message);
2550 static void SVGError(void *context,const char *format,...)
2554 reason[MaxTextExtent];
2563 Display and format a error formats, gives file, line, position and
2566 va_start(operands,format);
2567 svg_info=(SVGInfo *) context;
2568 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2570 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2571 (void) vsprintf(reason,format,operands);
2573 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2575 message=GetExceptionMessage(errno);
2576 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2577 reason,"`%s`",message);
2578 message=DestroyString(message);
2582 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2594 Called when a pcdata block has been parsed.
2596 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2598 svg_info=(SVGInfo *) context;
2599 parser=svg_info->parser;
2600 child=xmlGetLastChild(parser->node);
2601 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2603 xmlTextConcat(child,value,length);
2606 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2609 static void SVGExternalSubset(void *context,const xmlChar *name,
2610 const xmlChar *external_id,const xmlChar *system_id)
2625 Does this document has an external subset?
2627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2628 " SAX.externalSubset(%s, %s, %s)",name,
2629 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2630 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2631 svg_info=(SVGInfo *) context;
2632 parser=svg_info->parser;
2633 if (((external_id == NULL) && (system_id == NULL)) ||
2634 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2635 (svg_info->document == 0)))
2637 input=SVGResolveEntity(context,external_id,system_id);
2640 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2641 parser_context=(*parser);
2642 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2643 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2645 parser->errNo=XML_ERR_NO_MEMORY;
2646 parser->input=parser_context.input;
2647 parser->inputNr=parser_context.inputNr;
2648 parser->inputMax=parser_context.inputMax;
2649 parser->inputTab=parser_context.inputTab;
2655 xmlPushInput(parser,input);
2656 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2657 if (input->filename == (char *) NULL)
2658 input->filename=(char *) xmlStrdup(system_id);
2661 input->base=parser->input->cur;
2662 input->cur=parser->input->cur;
2664 xmlParseExternalSubset(parser,external_id,system_id);
2665 while (parser->inputNr > 1)
2666 (void) xmlPopInput(parser);
2667 xmlFreeInputStream(parser->input);
2668 xmlFree(parser->inputTab);
2669 parser->input=parser_context.input;
2670 parser->inputNr=parser_context.inputNr;
2671 parser->inputMax=parser_context.inputMax;
2672 parser->inputTab=parser_context.inputTab;
2675 #if defined(MAGICKCORE_RSVG_DELEGATE)
2676 static void SVGSetImageSize(int *width,int *height,gpointer context)
2681 image=(Image *) context;
2682 *width=(int) (*width*image->x_resolution/72.0);
2683 *height=(int) (*height*image->y_resolution/72.0);
2687 #if defined(__cplusplus) || defined(c_plusplus)
2691 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2694 filename[MaxTextExtent];
2713 message[MaxTextExtent];
2724 assert(image_info != (const ImageInfo *) NULL);
2725 assert(image_info->signature == MagickSignature);
2726 assert(exception != (ExceptionInfo *) NULL);
2727 if (image_info->debug != MagickFalse)
2728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2729 image_info->filename);
2730 assert(exception->signature == MagickSignature);
2731 image=AcquireImage(image_info);
2732 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2733 if (status == MagickFalse)
2735 image=DestroyImageList(image);
2736 return((Image *) NULL);
2738 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2740 #if defined(MAGICKCORE_RSVG_DELEGATE)
2741 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2748 register unsigned char
2761 register const guchar
2778 register PixelPacket
2784 svg_handle=rsvg_handle_new();
2785 if (svg_handle == (RsvgHandle *) NULL)
2786 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2787 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2788 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2789 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2790 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2791 image->y_resolution);
2792 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2794 error=(GError *) NULL;
2795 (void) rsvg_handle_write(svg_handle,message,n,&error);
2796 if (error != (GError *) NULL)
2797 g_error_free(error);
2799 error=(GError *) NULL;
2800 rsvg_handle_close(svg_handle,&error);
2801 if (error != (GError *) NULL)
2802 g_error_free(error);
2803 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2804 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2805 image->columns=dimension_info.width;
2806 image->rows=dimension_info.height;
2807 pixels=(unsigned char *) NULL;
2809 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2810 rsvg_handle_free(svg_handle);
2811 image->columns=gdk_pixbuf_get_width(pixel_info);
2812 image->rows=gdk_pixbuf_get_height(pixel_info);
2814 image->matte=MagickTrue;
2815 SetImageProperty(image,"svg:base-uri",
2816 rsvg_handle_get_base_uri(svg_handle));
2817 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2818 SetImageProperty(image,"svg:description",
2819 rsvg_handle_get_desc(svg_handle));
2820 if ((image->columns == 0) || (image->rows == 0))
2822 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2823 g_object_unref(G_OBJECT(pixel_info));
2825 g_object_unref(svg_handle);
2826 ThrowReaderException(MissingDelegateError,
2827 "NoDecodeDelegateForThisImageFormat");
2829 if (image_info->ping == MagickFalse)
2831 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2832 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2833 image->rows*sizeof(*pixels));
2834 if (pixels == (unsigned char *) NULL)
2836 g_object_unref(svg_handle);
2837 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2840 (void) SetImageBackgroundColor(image);
2841 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2842 cairo_surface=cairo_image_surface_create_for_data(pixels,
2843 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2844 if (cairo_surface == (cairo_surface_t *) NULL)
2846 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2847 g_object_unref(svg_handle);
2848 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2850 cairo_info=cairo_create(cairo_surface);
2851 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2852 cairo_paint(cairo_info);
2853 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2854 rsvg_handle_render_cairo(svg_handle,cairo_info);
2855 cairo_destroy(cairo_info);
2856 cairo_surface_destroy(cairo_surface);
2857 g_object_unref(svg_handle);
2860 p=gdk_pixbuf_get_pixels(pixel_info);
2862 for (y=0; y < (ssize_t) image->rows; y++)
2864 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2865 if (q == (PixelPacket *) NULL)
2867 for (x=0; x < (ssize_t) image->columns; x++)
2869 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2870 fill_color.blue=ScaleCharToQuantum(*p++);
2871 fill_color.green=ScaleCharToQuantum(*p++);
2872 fill_color.red=ScaleCharToQuantum(*p++);
2874 fill_color.red=ScaleCharToQuantum(*p++);
2875 fill_color.green=ScaleCharToQuantum(*p++);
2876 fill_color.blue=ScaleCharToQuantum(*p++);
2878 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2879 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2884 gamma=1.0-QuantumScale*fill_color.opacity;
2885 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2886 fill_color.blue*=gamma;
2887 fill_color.green*=gamma;
2888 fill_color.red*=gamma;
2891 MagickCompositeOver(&fill_color,fill_color.opacity,q,
2892 (MagickRealType) q->opacity,q);
2895 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2897 if (image->previous == (Image *) NULL)
2899 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2901 if (status == MagickFalse)
2906 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2907 if (pixels != (unsigned char *) NULL)
2908 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2910 g_object_unref(G_OBJECT(pixel_info));
2912 (void) CloseBlob(image);
2913 return(GetFirstImageInList(image));
2920 unique_file=AcquireUniqueFileResource(filename);
2921 if (unique_file != -1)
2922 file=fdopen(unique_file,"w");
2923 if ((unique_file == -1) || (file == (FILE *) NULL))
2925 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2926 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2928 image=DestroyImageList(image);
2929 return((Image *) NULL);
2934 svg_info=AcquireSVGInfo();
2935 if (svg_info == (SVGInfo *) NULL)
2936 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2937 svg_info->file=file;
2938 svg_info->exception=exception;
2939 svg_info->image=image;
2940 svg_info->image_info=image_info;
2941 svg_info->bounds.width=image->columns;
2942 svg_info->bounds.height=image->rows;
2943 if (image_info->size != (char *) NULL)
2944 (void) CloneString(&svg_info->size,image_info->size);
2945 if (image->debug != MagickFalse)
2946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2948 (void) xmlSubstituteEntitiesDefault(1);
2949 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
2950 sax_modules.internalSubset=SVGInternalSubset;
2951 sax_modules.isStandalone=SVGIsStandalone;
2952 sax_modules.hasInternalSubset=SVGHasInternalSubset;
2953 sax_modules.hasExternalSubset=SVGHasExternalSubset;
2954 sax_modules.resolveEntity=SVGResolveEntity;
2955 sax_modules.getEntity=SVGGetEntity;
2956 sax_modules.entityDecl=SVGEntityDeclaration;
2957 sax_modules.notationDecl=SVGNotationDeclaration;
2958 sax_modules.attributeDecl=SVGAttributeDeclaration;
2959 sax_modules.elementDecl=SVGElementDeclaration;
2960 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
2961 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
2962 sax_modules.startDocument=SVGStartDocument;
2963 sax_modules.endDocument=SVGEndDocument;
2964 sax_modules.startElement=SVGStartElement;
2965 sax_modules.endElement=SVGEndElement;
2966 sax_modules.reference=SVGReference;
2967 sax_modules.characters=SVGCharacters;
2968 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
2969 sax_modules.processingInstruction=SVGProcessingInstructions;
2970 sax_modules.comment=SVGComment;
2971 sax_modules.warning=SVGWarning;
2972 sax_modules.error=SVGError;
2973 sax_modules.fatalError=SVGError;
2974 sax_modules.getParameterEntity=SVGGetParameterEntity;
2975 sax_modules.cdataBlock=SVGCDataBlock;
2976 sax_modules.externalSubset=SVGExternalSubset;
2977 sax_handler=(&sax_modules);
2978 n=ReadBlob(image,MaxTextExtent,message);
2981 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2982 message,n,image->filename);
2983 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2985 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2990 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2991 xmlFreeParserCtxt(svg_info->parser);
2992 if (image->debug != MagickFalse)
2993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2995 (void) fclose(file);
2996 (void) CloseBlob(image);
2997 image->columns=svg_info->width;
2998 image->rows=svg_info->height;
2999 if (exception->severity >= ErrorException)
3001 image=DestroyImage(image);
3002 return((Image *) NULL);
3004 if (image_info->ping == MagickFalse)
3012 image=DestroyImage(image);
3013 image=(Image *) NULL;
3014 read_info=CloneImageInfo(image_info);
3015 SetImageInfoBlob(read_info,(void *) NULL,0);
3016 if (read_info->density != (char *) NULL)
3017 read_info->density=DestroyString(read_info->density);
3018 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
3020 image=ReadImage(read_info,exception);
3021 read_info=DestroyImageInfo(read_info);
3022 if (image != (Image *) NULL)
3023 (void) CopyMagickString(image->filename,image_info->filename,
3027 Relinquish resources.
3029 if (image != (Image *) NULL)
3031 if (svg_info->title != (char *) NULL)
3032 (void) SetImageProperty(image,"svg:title",svg_info->title);
3033 if (svg_info->comment != (char *) NULL)
3034 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3036 svg_info=DestroySVGInfo(svg_info);
3037 (void) RelinquishUniqueFileResource(filename);
3038 return(GetFirstImageInList(image));
3043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047 % R e g i s t e r S V G I m a g e %
3051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 % RegisterSVGImage() adds attributes for the SVG image format to
3054 % the list of supported formats. The attributes include the image format
3055 % tag, a method to read and/or write the format, whether the format
3056 % supports the saving of more than one frame to the same file or blob,
3057 % whether the format supports native in-memory I/O, and a brief
3058 % description of the format.
3060 % The format of the RegisterSVGImage method is:
3062 % size_t RegisterSVGImage(void)
3065 ModuleExport size_t RegisterSVGImage(void)
3068 version[MaxTextExtent];
3074 #if defined(LIBXML_DOTTED_VERSION)
3075 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3077 #if defined(MAGICKCORE_RSVG_DELEGATE)
3079 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3080 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3082 entry=SetMagickInfo("SVG");
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("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("SVGZ");
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("Compressed Scalable Vector Graphics");
3103 if (*version != '\0')
3104 entry->version=ConstantString(version);
3105 entry->magick=(IsImageFormatHandler *) IsSVG;
3106 entry->module=ConstantString("SVG");
3107 (void) RegisterMagickInfo(entry);
3108 entry=SetMagickInfo("MSVG");
3109 #if defined(MAGICKCORE_XML_DELEGATE)
3110 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3112 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3113 entry->blob_support=MagickFalse;
3114 entry->seekable_stream=MagickFalse;
3115 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3116 entry->magick=(IsImageFormatHandler *) IsSVG;
3117 entry->module=ConstantString("SVG");
3118 (void) RegisterMagickInfo(entry);
3119 return(MagickImageCoderSignature);
3123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3127 % U n r e g i s t e r S V G I m a g e %
3131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3133 % UnregisterSVGImage() removes format registrations made by the
3134 % SVG module from the list of supported formats.
3136 % The format of the UnregisterSVGImage method is:
3138 % UnregisterSVGImage(void)
3141 ModuleExport void UnregisterSVGImage(void)
3143 (void) UnregisterMagickInfo("SVGZ");
3144 (void) UnregisterMagickInfo("SVG");
3145 (void) UnregisterMagickInfo("MSVG");
3146 #if defined(MAGICKCORE_RSVG_DELEGATE)
3152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3156 % W r i t e S V G I m a g e %
3160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3165 % The format of the WriteSVGImage method is:
3167 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3169 % A description of each parameter follows.
3171 % o image_info: the image info.
3173 % o image: The image.
3177 static void AffineToTransform(Image *image,AffineMatrix *affine)
3180 transform[MaxTextExtent];
3182 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3184 if ((fabs(affine->rx) < MagickEpsilon) &&
3185 (fabs(affine->ry) < MagickEpsilon))
3187 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3188 (fabs(affine->sy-1.0) < MagickEpsilon))
3190 (void) WriteBlobString(image,"\">\n");
3193 (void) FormatMagickString(transform,MaxTextExtent,
3194 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3195 (void) WriteBlobString(image,transform);
3200 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3201 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3202 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3208 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3209 (void) FormatMagickString(transform,MaxTextExtent,
3210 "\" transform=\"rotate(%g)\">\n",theta);
3211 (void) WriteBlobString(image,transform);
3218 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3219 (fabs(affine->rx) < MagickEpsilon) &&
3220 (fabs(affine->ry) < MagickEpsilon) &&
3221 (fabs(affine->sy-1.0) < MagickEpsilon))
3223 (void) FormatMagickString(transform,MaxTextExtent,
3224 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3225 (void) WriteBlobString(image,transform);
3229 (void) FormatMagickString(transform,MaxTextExtent,
3230 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3231 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3232 (void) WriteBlobString(image,transform);
3235 static MagickBooleanType IsPoint(const char *point)
3243 value=strtol(point,&p,10);
3244 return(p != point ? MagickTrue : MagickFalse);
3247 static MagickBooleanType TraceSVGImage(Image *image)
3252 register const PixelPacket
3258 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3263 at_fitting_opts_type
3282 Trace image and write as SVG.
3284 fitting_options=at_fitting_opts_new();
3285 output_options=at_output_opts_new();
3286 type=GetImageType(image,&image->exception);
3288 if ((type == BilevelType) || (type == GrayscaleType))
3290 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3292 for (y=0; y < (ssize_t) image->rows; y++)
3294 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3295 if (p == (const PixelPacket *) NULL)
3297 for (x=0; x < (ssize_t) image->columns; x++)
3299 trace->bitmap[i++]=GetRedPixelComponent(p);
3300 if (number_planes == 3)
3302 trace->bitmap[i++]=GetGreenPixelComponent(p);
3303 trace->bitmap[i++]=GetBluePixelComponent(p);
3308 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3310 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3311 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3316 at_splines_free(splines);
3317 at_bitmap_free(trace);
3318 at_output_opts_free(output_options);
3319 at_fitting_opts_free(fitting_options);
3324 message[MaxTextExtent],
3325 tuple[MaxTextExtent];
3330 register const IndexPacket
3333 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3334 (void) WriteBlobString(image,
3335 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3336 (void) WriteBlobString(image,
3337 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3338 (void) FormatMagickString(message,MaxTextExtent,
3339 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3340 (double) image->rows);
3341 (void) WriteBlobString(image,message);
3342 GetMagickPixelPacket(image,&pixel);
3343 for (y=0; y < (ssize_t) image->rows; y++)
3345 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3346 if (p == (const PixelPacket *) NULL)
3348 indexes=GetVirtualIndexQueue(image);
3349 for (x=0; x < (ssize_t) image->columns; x++)
3351 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3352 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3354 (void) FormatMagickString(message,MaxTextExtent,
3355 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3356 (double) x,(double) y,tuple);
3357 (void) WriteBlobString(image,message);
3361 (void) WriteBlobString(image,"</svg>\n");
3367 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3369 #define BezierQuantum 200
3375 keyword[MaxTextExtent],
3376 message[MaxTextExtent],
3377 name[MaxTextExtent],
3379 type[MaxTextExtent];
3421 Open output image file.
3423 assert(image_info != (const ImageInfo *) NULL);
3424 assert(image_info->signature == MagickSignature);
3425 assert(image != (Image *) NULL);
3426 assert(image->signature == MagickSignature);
3427 if (image->debug != MagickFalse)
3428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3429 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3430 if (status == MagickFalse)
3432 value=GetImageArtifact(image,"SVG");
3433 if (value != (char *) NULL)
3435 (void) WriteBlobString(image,value);
3436 (void) CloseBlob(image);
3439 value=GetImageArtifact(image,"MVG");
3440 if (value == (char *) NULL)
3441 return(TraceSVGImage(image));
3445 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3446 (void) WriteBlobString(image,
3447 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3448 (void) WriteBlobString(image,
3449 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3450 (void) FormatMagickString(message,MaxTextExtent,
3451 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3453 (void) WriteBlobString(image,message);
3455 Allocate primitive info memory.
3458 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3459 sizeof(*primitive_info));
3460 if (primitive_info == (PrimitiveInfo *) NULL)
3461 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3462 GetAffineMatrix(&affine);
3463 token=AcquireString(value);
3467 for (q=(const char *) value; *q != '\0'; )
3470 Interpret graphic primitive.
3472 GetMagickToken(q,&q,keyword);
3473 if (*keyword == '\0')
3475 if (*keyword == '#')
3480 if (active != MagickFalse)
3482 AffineToTransform(image,&affine);
3485 (void) WriteBlobString(image,"<desc>");
3486 (void) WriteBlobString(image,keyword+1);
3487 for ( ; (*q != '\n') && (*q != '\0'); q++)
3490 case '<': (void) WriteBlobString(image,"<"); break;
3491 case '>': (void) WriteBlobString(image,">"); break;
3492 case '&': (void) WriteBlobString(image,"&"); break;
3493 default: (void) WriteBlobByte(image,*q); break;
3495 (void) WriteBlobString(image,"</desc>\n");
3498 primitive_type=UndefinedPrimitive;
3506 if (LocaleCompare("affine",keyword) == 0)
3508 GetMagickToken(q,&q,token);
3509 affine.sx=StringToDouble(token);
3510 GetMagickToken(q,&q,token);
3512 GetMagickToken(q,&q,token);
3513 affine.rx=StringToDouble(token);
3514 GetMagickToken(q,&q,token);
3516 GetMagickToken(q,&q,token);
3517 affine.ry=StringToDouble(token);
3518 GetMagickToken(q,&q,token);
3520 GetMagickToken(q,&q,token);
3521 affine.sy=StringToDouble(token);
3522 GetMagickToken(q,&q,token);
3524 GetMagickToken(q,&q,token);
3525 affine.tx=StringToDouble(token);
3526 GetMagickToken(q,&q,token);
3528 GetMagickToken(q,&q,token);
3529 affine.ty=StringToDouble(token);
3532 if (LocaleCompare("angle",keyword) == 0)
3534 GetMagickToken(q,&q,token);
3535 affine.rx=StringToDouble(token);
3536 affine.ry=StringToDouble(token);
3539 if (LocaleCompare("arc",keyword) == 0)
3541 primitive_type=ArcPrimitive;
3550 if (LocaleCompare("bezier",keyword) == 0)
3552 primitive_type=BezierPrimitive;
3561 if (LocaleCompare("clip-path",keyword) == 0)
3563 GetMagickToken(q,&q,token);
3564 (void) FormatMagickString(message,MaxTextExtent,
3565 "clip-path:url(#%s);",token);
3566 (void) WriteBlobString(image,message);
3569 if (LocaleCompare("clip-rule",keyword) == 0)
3571 GetMagickToken(q,&q,token);
3572 (void) FormatMagickString(message,MaxTextExtent,
3573 "clip-rule:%s;",token);
3574 (void) WriteBlobString(image,message);
3577 if (LocaleCompare("clip-units",keyword) == 0)
3579 GetMagickToken(q,&q,token);
3580 (void) FormatMagickString(message,MaxTextExtent,
3581 "clipPathUnits=%s;",token);
3582 (void) WriteBlobString(image,message);
3585 if (LocaleCompare("circle",keyword) == 0)
3587 primitive_type=CirclePrimitive;
3590 if (LocaleCompare("color",keyword) == 0)
3592 primitive_type=ColorPrimitive;
3601 if (LocaleCompare("decorate",keyword) == 0)
3603 GetMagickToken(q,&q,token);
3604 (void) FormatMagickString(message,MaxTextExtent,
3605 "text-decoration:%s;",token);
3606 (void) WriteBlobString(image,message);
3615 if (LocaleCompare("ellipse",keyword) == 0)
3617 primitive_type=EllipsePrimitive;
3626 if (LocaleCompare("fill",keyword) == 0)
3628 GetMagickToken(q,&q,token);
3629 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3631 (void) WriteBlobString(image,message);
3634 if (LocaleCompare("fill-rule",keyword) == 0)
3636 GetMagickToken(q,&q,token);
3637 (void) FormatMagickString(message,MaxTextExtent,
3638 "fill-rule:%s;",token);
3639 (void) WriteBlobString(image,message);
3642 if (LocaleCompare("fill-opacity",keyword) == 0)
3644 GetMagickToken(q,&q,token);
3645 (void) FormatMagickString(message,MaxTextExtent,
3646 "fill-opacity:%s;",token);
3647 (void) WriteBlobString(image,message);
3650 if (LocaleCompare("font-family",keyword) == 0)
3652 GetMagickToken(q,&q,token);
3653 (void) FormatMagickString(message,MaxTextExtent,
3654 "font-family:%s;",token);
3655 (void) WriteBlobString(image,message);
3658 if (LocaleCompare("font-stretch",keyword) == 0)
3660 GetMagickToken(q,&q,token);
3661 (void) FormatMagickString(message,MaxTextExtent,
3662 "font-stretch:%s;",token);
3663 (void) WriteBlobString(image,message);
3666 if (LocaleCompare("font-style",keyword) == 0)
3668 GetMagickToken(q,&q,token);
3669 (void) FormatMagickString(message,MaxTextExtent,
3670 "font-style:%s;",token);
3671 (void) WriteBlobString(image,message);
3674 if (LocaleCompare("font-size",keyword) == 0)
3676 GetMagickToken(q,&q,token);
3677 (void) FormatMagickString(message,MaxTextExtent,
3678 "font-size:%s;",token);
3679 (void) WriteBlobString(image,message);
3682 if (LocaleCompare("font-weight",keyword) == 0)
3684 GetMagickToken(q,&q,token);
3685 (void) FormatMagickString(message,MaxTextExtent,
3686 "font-weight:%s;",token);
3687 (void) WriteBlobString(image,message);
3696 if (LocaleCompare("gradient-units",keyword) == 0)
3698 GetMagickToken(q,&q,token);
3701 if (LocaleCompare("text-align",keyword) == 0)
3703 GetMagickToken(q,&q,token);
3704 (void) FormatMagickString(message,MaxTextExtent,
3705 "text-align %s ",token);
3706 (void) WriteBlobString(image,message);
3709 if (LocaleCompare("text-anchor",keyword) == 0)
3711 GetMagickToken(q,&q,token);
3712 (void) FormatMagickString(message,MaxTextExtent,
3713 "text-anchor %s ",token);
3714 (void) WriteBlobString(image,message);
3723 if (LocaleCompare("image",keyword) == 0)
3725 GetMagickToken(q,&q,token);
3726 primitive_type=ImagePrimitive;
3735 if (LocaleCompare("line",keyword) == 0)
3737 primitive_type=LinePrimitive;
3746 if (LocaleCompare("matte",keyword) == 0)
3748 primitive_type=MattePrimitive;
3757 if (LocaleCompare("opacity",keyword) == 0)
3759 GetMagickToken(q,&q,token);
3760 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3762 (void) WriteBlobString(image,message);
3771 if (LocaleCompare("path",keyword) == 0)
3773 primitive_type=PathPrimitive;
3776 if (LocaleCompare("point",keyword) == 0)
3778 primitive_type=PointPrimitive;
3781 if (LocaleCompare("polyline",keyword) == 0)
3783 primitive_type=PolylinePrimitive;
3786 if (LocaleCompare("polygon",keyword) == 0)
3788 primitive_type=PolygonPrimitive;
3791 if (LocaleCompare("pop",keyword) == 0)
3793 GetMagickToken(q,&q,token);
3794 if (LocaleCompare("clip-path",token) == 0)
3796 (void) WriteBlobString(image,"</clipPath>\n");
3799 if (LocaleCompare("defs",token) == 0)
3801 (void) WriteBlobString(image,"</defs>\n");
3804 if (LocaleCompare("gradient",token) == 0)
3806 (void) FormatMagickString(message,MaxTextExtent,
3807 "</%sGradient>\n",type);
3808 (void) WriteBlobString(image,message);
3811 if (LocaleCompare("graphic-context",token) == 0)
3815 ThrowWriterException(DrawError,
3816 "UnbalancedGraphicContextPushPop");
3817 (void) WriteBlobString(image,"</g>\n");
3819 if (LocaleCompare("pattern",token) == 0)
3821 (void) WriteBlobString(image,"</pattern>\n");
3824 if (LocaleCompare("defs",token) == 0)
3825 (void) WriteBlobString(image,"</g>\n");
3828 if (LocaleCompare("push",keyword) == 0)
3830 GetMagickToken(q,&q,token);
3831 if (LocaleCompare("clip-path",token) == 0)
3833 GetMagickToken(q,&q,token);
3834 (void) FormatMagickString(message,MaxTextExtent,
3835 "<clipPath id=\"%s\">\n",token);
3836 (void) WriteBlobString(image,message);
3839 if (LocaleCompare("defs",token) == 0)
3841 (void) WriteBlobString(image,"<defs>\n");
3844 if (LocaleCompare("gradient",token) == 0)
3846 GetMagickToken(q,&q,token);
3847 (void) CopyMagickString(name,token,MaxTextExtent);
3848 GetMagickToken(q,&q,token);
3849 (void) CopyMagickString(type,token,MaxTextExtent);
3850 GetMagickToken(q,&q,token);
3851 svg_info.segment.x1=StringToDouble(token);
3852 svg_info.element.cx=StringToDouble(token);
3853 GetMagickToken(q,&q,token);
3855 GetMagickToken(q,&q,token);
3856 svg_info.segment.y1=StringToDouble(token);
3857 svg_info.element.cy=StringToDouble(token);
3858 GetMagickToken(q,&q,token);
3860 GetMagickToken(q,&q,token);
3861 svg_info.segment.x2=StringToDouble(token);
3862 svg_info.element.major=StringToDouble(token);
3863 GetMagickToken(q,&q,token);
3865 GetMagickToken(q,&q,token);
3866 svg_info.segment.y2=StringToDouble(token);
3867 svg_info.element.minor=StringToDouble(token);
3868 (void) FormatMagickString(message,MaxTextExtent,
3869 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3870 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3871 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3872 if (LocaleCompare(type,"radial") == 0)
3874 GetMagickToken(q,&q,token);
3876 GetMagickToken(q,&q,token);
3877 svg_info.element.angle=StringToDouble(token);
3878 (void) FormatMagickString(message,MaxTextExtent,
3879 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3880 "fx=\"%g\" fy=\"%g\">\n",type,name,
3881 svg_info.element.cx,svg_info.element.cy,
3882 svg_info.element.angle,svg_info.element.major,
3883 svg_info.element.minor);
3885 (void) WriteBlobString(image,message);
3888 if (LocaleCompare("graphic-context",token) == 0)
3893 AffineToTransform(image,&affine);
3896 (void) WriteBlobString(image,"<g style=\"");
3899 if (LocaleCompare("pattern",token) == 0)
3901 GetMagickToken(q,&q,token);
3902 (void) CopyMagickString(name,token,MaxTextExtent);
3903 GetMagickToken(q,&q,token);
3904 svg_info.bounds.x=StringToDouble(token);
3905 GetMagickToken(q,&q,token);
3907 GetMagickToken(q,&q,token);
3908 svg_info.bounds.y=StringToDouble(token);
3909 GetMagickToken(q,&q,token);
3911 GetMagickToken(q,&q,token);
3912 svg_info.bounds.width=StringToDouble(token);
3913 GetMagickToken(q,&q,token);
3915 GetMagickToken(q,&q,token);
3916 svg_info.bounds.height=StringToDouble(token);
3917 (void) FormatMagickString(message,MaxTextExtent,
3918 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3919 "height=\"%g\">\n",name,svg_info.bounds.x,
3920 svg_info.bounds.y,svg_info.bounds.width,
3921 svg_info.bounds.height);
3922 (void) WriteBlobString(image,message);
3933 if (LocaleCompare("rectangle",keyword) == 0)
3935 primitive_type=RectanglePrimitive;
3938 if (LocaleCompare("roundRectangle",keyword) == 0)
3940 primitive_type=RoundRectanglePrimitive;
3943 if (LocaleCompare("rotate",keyword) == 0)
3945 GetMagickToken(q,&q,token);
3946 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3948 (void) WriteBlobString(image,message);
3957 if (LocaleCompare("scale",keyword) == 0)
3959 GetMagickToken(q,&q,token);
3960 affine.sx=StringToDouble(token);
3961 GetMagickToken(q,&q,token);
3963 GetMagickToken(q,&q,token);
3964 affine.sy=StringToDouble(token);
3967 if (LocaleCompare("skewX",keyword) == 0)
3969 GetMagickToken(q,&q,token);
3970 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3972 (void) WriteBlobString(image,message);
3975 if (LocaleCompare("skewY",keyword) == 0)
3977 GetMagickToken(q,&q,token);
3978 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3980 (void) WriteBlobString(image,message);
3983 if (LocaleCompare("stop-color",keyword) == 0)
3986 color[MaxTextExtent];
3988 GetMagickToken(q,&q,token);
3989 (void) CopyMagickString(color,token,MaxTextExtent);
3990 GetMagickToken(q,&q,token);
3991 (void) FormatMagickString(message,MaxTextExtent,
3992 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3993 (void) WriteBlobString(image,message);
3996 if (LocaleCompare("stroke",keyword) == 0)
3998 GetMagickToken(q,&q,token);
3999 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
4001 (void) WriteBlobString(image,message);
4004 if (LocaleCompare("stroke-antialias",keyword) == 0)
4006 GetMagickToken(q,&q,token);
4007 (void) FormatMagickString(message,MaxTextExtent,
4008 "stroke-antialias:%s;",token);
4009 (void) WriteBlobString(image,message);
4012 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4020 GetMagickToken(p,&p,token);
4021 for (k=0; IsPoint(token); k++)
4022 GetMagickToken(p,&p,token);
4023 (void) WriteBlobString(image,"stroke-dasharray:");
4024 for (j=0; j < k; j++)
4026 GetMagickToken(q,&q,token);
4027 (void) FormatMagickString(message,MaxTextExtent,"%s ",
4029 (void) WriteBlobString(image,message);
4031 (void) WriteBlobString(image,";");
4034 GetMagickToken(q,&q,token);
4035 (void) FormatMagickString(message,MaxTextExtent,
4036 "stroke-dasharray:%s;",token);
4037 (void) WriteBlobString(image,message);
4040 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4042 GetMagickToken(q,&q,token);
4043 (void) FormatMagickString(message,MaxTextExtent,
4044 "stroke-dashoffset:%s;",token);
4045 (void) WriteBlobString(image,message);
4048 if (LocaleCompare("stroke-linecap",keyword) == 0)
4050 GetMagickToken(q,&q,token);
4051 (void) FormatMagickString(message,MaxTextExtent,
4052 "stroke-linecap:%s;",token);
4053 (void) WriteBlobString(image,message);
4056 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4058 GetMagickToken(q,&q,token);
4059 (void) FormatMagickString(message,MaxTextExtent,
4060 "stroke-linejoin:%s;",token);
4061 (void) WriteBlobString(image,message);
4064 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4066 GetMagickToken(q,&q,token);
4067 (void) FormatMagickString(message,MaxTextExtent,
4068 "stroke-miterlimit:%s;",token);
4069 (void) WriteBlobString(image,message);
4072 if (LocaleCompare("stroke-opacity",keyword) == 0)
4074 GetMagickToken(q,&q,token);
4075 (void) FormatMagickString(message,MaxTextExtent,
4076 "stroke-opacity:%s;",token);
4077 (void) WriteBlobString(image,message);
4080 if (LocaleCompare("stroke-width",keyword) == 0)
4082 GetMagickToken(q,&q,token);
4083 (void) FormatMagickString(message,MaxTextExtent,
4084 "stroke-width:%s;",token);
4085 (void) WriteBlobString(image,message);
4094 if (LocaleCompare("text",keyword) == 0)
4096 primitive_type=TextPrimitive;
4099 if (LocaleCompare("text-antialias",keyword) == 0)
4101 GetMagickToken(q,&q,token);
4102 (void) FormatMagickString(message,MaxTextExtent,
4103 "text-antialias:%s;",token);
4104 (void) WriteBlobString(image,message);
4107 if (LocaleCompare("tspan",keyword) == 0)
4109 primitive_type=TextPrimitive;
4112 if (LocaleCompare("translate",keyword) == 0)
4114 GetMagickToken(q,&q,token);
4115 affine.tx=StringToDouble(token);
4116 GetMagickToken(q,&q,token);
4118 GetMagickToken(q,&q,token);
4119 affine.ty=StringToDouble(token);
4128 if (LocaleCompare("viewbox",keyword) == 0)
4130 GetMagickToken(q,&q,token);
4132 GetMagickToken(q,&q,token);
4133 GetMagickToken(q,&q,token);
4135 GetMagickToken(q,&q,token);
4136 GetMagickToken(q,&q,token);
4138 GetMagickToken(q,&q,token);
4139 GetMagickToken(q,&q,token);
4151 if (status == MagickFalse)
4153 if (primitive_type == UndefinedPrimitive)
4156 Parse the primitive attributes.
4160 for (x=0; *q != '\0'; x++)
4165 if (IsPoint(q) == MagickFalse)
4167 GetMagickToken(q,&q,token);
4168 point.x=StringToDouble(token);
4169 GetMagickToken(q,&q,token);
4171 GetMagickToken(q,&q,token);
4172 point.y=StringToDouble(token);
4173 GetMagickToken(q,(const char **) NULL,token);
4175 GetMagickToken(q,&q,token);
4176 primitive_info[i].primitive=primitive_type;
4177 primitive_info[i].point=point;
4178 primitive_info[i].coordinates=0;
4179 primitive_info[i].method=FloodfillMethod;
4181 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4183 number_points+=6*BezierQuantum+360;
4184 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4185 number_points,sizeof(*primitive_info));
4186 if (primitive_info == (PrimitiveInfo *) NULL)
4188 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4189 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4193 primitive_info[j].primitive=primitive_type;
4194 primitive_info[j].coordinates=x;
4195 primitive_info[j].method=FloodfillMethod;
4196 primitive_info[j].text=(char *) NULL;
4199 AffineToTransform(image,&affine);
4203 switch (primitive_type)
4205 case PointPrimitive:
4208 if (primitive_info[j].coordinates != 1)
4217 if (primitive_info[j].coordinates != 2)
4222 (void) FormatMagickString(message,MaxTextExtent,
4223 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4224 primitive_info[j].point.x,primitive_info[j].point.y,
4225 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4226 (void) WriteBlobString(image,message);
4229 case RectanglePrimitive:
4231 if (primitive_info[j].coordinates != 2)
4236 (void) FormatMagickString(message,MaxTextExtent,
4237 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4238 primitive_info[j].point.x,primitive_info[j].point.y,
4239 primitive_info[j+1].point.x-primitive_info[j].point.x,
4240 primitive_info[j+1].point.y-primitive_info[j].point.y);
4241 (void) WriteBlobString(image,message);
4244 case RoundRectanglePrimitive:
4246 if (primitive_info[j].coordinates != 3)
4251 (void) FormatMagickString(message,MaxTextExtent,
4252 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4253 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4254 primitive_info[j].point.y,primitive_info[j+1].point.x-
4255 primitive_info[j].point.x,primitive_info[j+1].point.y-
4256 primitive_info[j].point.y,primitive_info[j+2].point.x,
4257 primitive_info[j+2].point.y);
4258 (void) WriteBlobString(image,message);
4263 if (primitive_info[j].coordinates != 3)
4270 case EllipsePrimitive:
4272 if (primitive_info[j].coordinates != 3)
4277 (void) FormatMagickString(message,MaxTextExtent,
4278 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4279 primitive_info[j].point.x,primitive_info[j].point.y,
4280 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4281 (void) WriteBlobString(image,message);
4284 case CirclePrimitive:
4290 if (primitive_info[j].coordinates != 2)
4295 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4296 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4297 (void) FormatMagickString(message,MaxTextExtent,
4298 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4299 primitive_info[j].point.x,primitive_info[j].point.y,
4301 (void) WriteBlobString(image,message);
4304 case PolylinePrimitive:
4306 if (primitive_info[j].coordinates < 2)
4311 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4312 (void) WriteBlobString(image,message);
4313 length=strlen(message);
4316 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4317 primitive_info[j].point.x,primitive_info[j].point.y);
4318 length+=strlen(message);
4321 (void) WriteBlobString(image,"\n ");
4322 length=strlen(message)+5;
4324 (void) WriteBlobString(image,message);
4326 (void) WriteBlobString(image,"\"/>\n");
4329 case PolygonPrimitive:
4331 if (primitive_info[j].coordinates < 3)
4336 primitive_info[i]=primitive_info[j];
4337 primitive_info[i].coordinates=0;
4338 primitive_info[j].coordinates++;
4340 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4341 (void) WriteBlobString(image,message);
4342 length=strlen(message);
4345 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4346 primitive_info[j].point.x,primitive_info[j].point.y);
4347 length+=strlen(message);
4350 (void) WriteBlobString(image,"\n ");
4351 length=strlen(message)+5;
4353 (void) WriteBlobString(image,message);
4355 (void) WriteBlobString(image,"\"/>\n");
4358 case BezierPrimitive:
4360 if (primitive_info[j].coordinates < 3)
4372 GetMagickToken(q,&q,token);
4373 number_attributes=1;
4374 for (p=token; *p != '\0'; p++)
4375 if (isalpha((int) *p))
4376 number_attributes++;
4377 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4379 number_points+=6*BezierQuantum*number_attributes;
4380 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4381 number_points,sizeof(*primitive_info));
4382 if (primitive_info == (PrimitiveInfo *) NULL)
4384 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4385 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4390 (void) WriteBlobString(image," <path d=\"");
4391 (void) WriteBlobString(image,token);
4392 (void) WriteBlobString(image,"\"/>\n");
4395 case ColorPrimitive:
4396 case MattePrimitive:
4398 if (primitive_info[j].coordinates != 1)
4403 GetMagickToken(q,&q,token);
4404 if (LocaleCompare("point",token) == 0)
4405 primitive_info[j].method=PointMethod;
4406 if (LocaleCompare("replace",token) == 0)
4407 primitive_info[j].method=ReplaceMethod;
4408 if (LocaleCompare("floodfill",token) == 0)
4409 primitive_info[j].method=FloodfillMethod;
4410 if (LocaleCompare("filltoborder",token) == 0)
4411 primitive_info[j].method=FillToBorderMethod;
4412 if (LocaleCompare("reset",token) == 0)
4413 primitive_info[j].method=ResetMethod;
4421 if (primitive_info[j].coordinates != 1)
4426 GetMagickToken(q,&q,token);
4427 (void) FormatMagickString(message,MaxTextExtent,
4428 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4429 primitive_info[j].point.y);
4430 (void) WriteBlobString(image,message);
4431 for (p=token; *p != '\0'; p++)
4434 case '<': (void) WriteBlobString(image,"<"); break;
4435 case '>': (void) WriteBlobString(image,">"); break;
4436 case '&': (void) WriteBlobString(image,"&"); break;
4437 default: (void) WriteBlobByte(image,*p); break;
4439 (void) WriteBlobString(image,"</text>\n");
4442 case ImagePrimitive:
4444 if (primitive_info[j].coordinates != 2)
4449 GetMagickToken(q,&q,token);
4450 (void) FormatMagickString(message,MaxTextExtent,
4451 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4452 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4453 primitive_info[j].point.y,primitive_info[j+1].point.x,
4454 primitive_info[j+1].point.y,token);
4455 (void) WriteBlobString(image,message);
4459 if (primitive_info == (PrimitiveInfo *) NULL)
4461 primitive_info[i].primitive=UndefinedPrimitive;
4462 if (status == MagickFalse)
4465 (void) WriteBlobString(image,"</svg>\n");
4467 Relinquish resources.
4469 token=DestroyString(token);
4470 if (primitive_info != (PrimitiveInfo *) NULL)
4471 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4472 (void) CloseBlob(image);