2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2011 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;
387 if (style == (const char *) NULL)
388 return((char **) NULL);
389 text=AcquireString(style);
390 (void) SubstituteString(&text,":","\n");
391 (void) SubstituteString(&text,";","\n");
392 tokens=StringToList(text);
393 text=DestroyString(text);
394 for (i=0; tokens[i] != (char *) NULL; i++)
395 StripStyleTokens(tokens[i]);
400 static char **GetTransformTokens(void *context,const char *text,
416 svg_info=(SVGInfo *) context;
418 if (text == (const char *) NULL)
419 return((char **) NULL);
421 Determine the number of arguments.
423 for (p=text; *p != '\0'; p++)
428 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
429 if (tokens == (char **) NULL)
431 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
432 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
433 return((char **) NULL);
436 Convert string to an ASCII list.
440 for (q=p; *q != '\0'; q++)
442 if ((*q != '(') && (*q != ')') && (*q != '\0'))
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
449 tokens[i]=AcquireString(p);
450 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
451 StripString(tokens[i++]);
452 tokens[i]=(char *) NULL;
456 #if defined(__cplusplus) || defined(c_plusplus)
460 static int SVGIsStandalone(void *context)
466 Is this document tagged standalone?
468 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
469 svg_info=(SVGInfo *) context;
470 return(svg_info->document->standalone == 1);
473 static int SVGHasInternalSubset(void *context)
479 Does this document has an internal subset?
481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
482 " SAX.SVGHasInternalSubset()");
483 svg_info=(SVGInfo *) context;
484 return(svg_info->document->intSubset != NULL);
487 static int SVGHasExternalSubset(void *context)
493 Does this document has an external subset?
495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
496 " SAX.SVGHasExternalSubset()");
497 svg_info=(SVGInfo *) context;
498 return(svg_info->document->extSubset != NULL);
501 static void SVGInternalSubset(void *context,const xmlChar *name,
502 const xmlChar *external_id,const xmlChar *system_id)
508 Does this document has an internal subset?
510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
511 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
512 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
513 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
514 svg_info=(SVGInfo *) context;
515 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
518 static xmlParserInputPtr SVGResolveEntity(void *context,
519 const xmlChar *public_id,const xmlChar *system_id)
528 Special entity resolver, better left to the parser, it has more
529 context than the application layer. The default behaviour is to
530 not resolve the entities, in that case the ENTITY_REF nodes are
531 built in the structure (and the parameter values).
533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
534 " SAX.resolveEntity(%s, %s)",
535 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
536 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
537 svg_info=(SVGInfo *) context;
538 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
539 public_id,svg_info->parser);
543 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
549 Get an entity by name.
551 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
553 svg_info=(SVGInfo *) context;
554 return(xmlGetDocEntity(svg_info->document,name));
557 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
563 Get a parameter entity by name.
565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
566 " SAX.getParameterEntity(%s)",name);
567 svg_info=(SVGInfo *) context;
568 return(xmlGetParameterEntity(svg_info->document,name));
571 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
572 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
578 An entity definition has been parsed.
580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
581 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
582 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
583 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
584 svg_info=(SVGInfo *) context;
585 if (svg_info->parser->inSubset == 1)
586 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
589 if (svg_info->parser->inSubset == 2)
590 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
594 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
595 const xmlChar *name,int type,int value,const xmlChar *default_value,
596 xmlEnumerationPtr tree)
609 An attribute definition has been parsed.
611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
612 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
614 svg_info=(SVGInfo *) context;
615 fullname=(xmlChar *) NULL;
616 prefix=(xmlChar *) NULL;
617 parser=svg_info->parser;
618 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
619 if (parser->inSubset == 1)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
624 if (parser->inSubset == 2)
625 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
626 element,fullname,prefix,(xmlAttributeType) type,
627 (xmlAttributeDefault) value,default_value,tree);
628 if (prefix != (xmlChar *) NULL)
630 if (fullname != (xmlChar *) NULL)
634 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
635 xmlElementContentPtr content)
644 An element definition has been parsed.
646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
647 " SAX.elementDecl(%s, %d, ...)",name,type);
648 svg_info=(SVGInfo *) context;
649 parser=svg_info->parser;
650 if (parser->inSubset == 1)
651 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
652 name,(xmlElementTypeVal) type,content);
654 if (parser->inSubset == 2)
655 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
656 name,(xmlElementTypeVal) type,content);
659 static void SVGNotationDeclaration(void *context,const xmlChar *name,
660 const xmlChar *public_id,const xmlChar *system_id)
669 What to do when a notation declaration has been parsed.
671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
672 " SAX.notationDecl(%s, %s, %s)",name,
673 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
674 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
675 svg_info=(SVGInfo *) context;
676 parser=svg_info->parser;
677 if (parser->inSubset == 1)
678 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
679 name,public_id,system_id);
681 if (parser->inSubset == 2)
682 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
683 name,public_id,system_id);
686 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
687 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
693 What to do when an unparsed entity declaration is parsed.
695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
696 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
697 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
698 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
699 svg_info=(SVGInfo *) context;
700 (void) xmlAddDocEntity(svg_info->document,name,
701 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
705 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
711 Receive the document locator at startup, actually xmlDefaultSAXLocator.
714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
715 " SAX.setDocumentLocator()");
716 svg_info=(SVGInfo *) context;
720 static void SVGStartDocument(void *context)
729 Called when the document start being processed.
731 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
732 svg_info=(SVGInfo *) context;
733 GetExceptionInfo(svg_info->exception);
734 parser=svg_info->parser;
735 svg_info->document=xmlNewDoc(parser->version);
736 if (svg_info->document == (xmlDocPtr) NULL)
738 if (parser->encoding == NULL)
739 svg_info->document->encoding=(const xmlChar *) NULL;
741 svg_info->document->encoding=xmlStrdup(parser->encoding);
742 svg_info->document->standalone=parser->standalone;
745 static void SVGEndDocument(void *context)
751 Called when the document end has been detected.
753 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
754 svg_info=(SVGInfo *) context;
755 if (svg_info->offset != (char *) NULL)
756 svg_info->offset=DestroyString(svg_info->offset);
757 if (svg_info->stop_color != (char *) NULL)
758 svg_info->stop_color=DestroyString(svg_info->stop_color);
759 if (svg_info->scale != (double *) NULL)
760 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
761 if (svg_info->text != (char *) NULL)
762 svg_info->text=DestroyString(svg_info->text);
763 if (svg_info->vertices != (char *) NULL)
764 svg_info->vertices=DestroyString(svg_info->vertices);
765 if (svg_info->url != (char *) NULL)
766 svg_info->url=DestroyString(svg_info->url);
767 #if defined(MAGICKCORE_XML_DELEGATE)
768 if (svg_info->document != (xmlDocPtr) NULL)
770 xmlFreeDoc(svg_info->document);
771 svg_info->document=(xmlDocPtr) NULL;
776 static void SVGStartElement(void *context,const xmlChar *name,
777 const xmlChar **attributes)
782 token[MaxTextExtent],
802 Called when an opening tag has been processed.
804 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
806 svg_info=(SVGInfo *) context;
808 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
809 svg_info->n+1UL,sizeof(*svg_info->scale));
810 if (svg_info->scale == (double *) NULL)
812 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
813 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
816 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
817 color=AcquireString("none");
818 units=AcquireString("userSpaceOnUse");
819 value=(const char *) NULL;
820 if (attributes != (const xmlChar **) NULL)
821 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
823 keyword=(const char *) attributes[i];
824 value=(const char *) attributes[i+1];
830 if (LocaleCompare(keyword,"cx") == 0)
832 svg_info->element.cx=
833 GetUserSpaceCoordinateValue(svg_info,1,value);
836 if (LocaleCompare(keyword,"cy") == 0)
838 svg_info->element.cy=
839 GetUserSpaceCoordinateValue(svg_info,-1,value);
847 if (LocaleCompare(keyword,"fx") == 0)
849 svg_info->element.major=
850 GetUserSpaceCoordinateValue(svg_info,1,value);
853 if (LocaleCompare(keyword,"fy") == 0)
855 svg_info->element.minor=
856 GetUserSpaceCoordinateValue(svg_info,-1,value);
864 if (LocaleCompare(keyword,"height") == 0)
866 svg_info->bounds.height=
867 GetUserSpaceCoordinateValue(svg_info,-1,value);
875 if (LocaleCompare(keyword,"id") == 0)
877 (void) CopyMagickString(id,value,MaxTextExtent);
885 if (LocaleCompare(keyword,"r") == 0)
887 svg_info->element.angle=
888 GetUserSpaceCoordinateValue(svg_info,0,value);
896 if (LocaleCompare(keyword,"width") == 0)
898 svg_info->bounds.width=
899 GetUserSpaceCoordinateValue(svg_info,1,value);
907 if (LocaleCompare(keyword,"x") == 0)
909 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
913 if (LocaleCompare(keyword,"x1") == 0)
915 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
919 if (LocaleCompare(keyword,"x2") == 0)
921 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
930 if (LocaleCompare(keyword,"y") == 0)
932 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
936 if (LocaleCompare(keyword,"y1") == 0)
938 svg_info->segment.y1=
939 GetUserSpaceCoordinateValue(svg_info,-1,value);
942 if (LocaleCompare(keyword,"y2") == 0)
944 svg_info->segment.y2=
945 GetUserSpaceCoordinateValue(svg_info,-1,value);
954 if (strchr((char *) name,':') != (char *) NULL)
959 for ( ; *name != ':'; name++) ;
967 if (LocaleCompare((const char *) name,"circle") == 0)
969 MVGPrintf(svg_info->file,"push graphic-context\n");
972 if (LocaleCompare((const char *) name,"clipPath") == 0)
974 MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
982 if (LocaleCompare((const char *) name,"defs") == 0)
984 MVGPrintf(svg_info->file,"push defs\n");
992 if (LocaleCompare((const char *) name,"ellipse") == 0)
994 MVGPrintf(svg_info->file,"push graphic-context\n");
1002 if (LocaleCompare((const char *) name,"g") == 0)
1004 MVGPrintf(svg_info->file,"push graphic-context\n");
1012 if (LocaleCompare((const char *) name,"image") == 0)
1014 MVGPrintf(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"line") == 0)
1024 MVGPrintf(svg_info->file,"push graphic-context\n");
1027 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1029 MVGPrintf(svg_info->file,
1030 "push gradient '%s' linear %g,%g %g,%g\n",id,
1031 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1032 svg_info->segment.y2);
1040 if (LocaleCompare((const char *) name,"path") == 0)
1042 MVGPrintf(svg_info->file,"push graphic-context\n");
1045 if (LocaleCompare((const char *) name,"pattern") == 0)
1047 MVGPrintf(svg_info->file,
1048 "push pattern '%s' %g,%g %g,%g\n",id,
1049 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1050 svg_info->bounds.height);
1053 if (LocaleCompare((const char *) name,"polygon") == 0)
1055 MVGPrintf(svg_info->file,"push graphic-context\n");
1058 if (LocaleCompare((const char *) name,"polyline") == 0)
1060 MVGPrintf(svg_info->file,"push graphic-context\n");
1068 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1070 MVGPrintf(svg_info->file,
1071 "push gradient '%s' radial %g,%g %g,%g %g\n",
1072 id,svg_info->element.cx,svg_info->element.cy,
1073 svg_info->element.major,svg_info->element.minor,
1074 svg_info->element.angle);
1077 if (LocaleCompare((const char *) name,"rect") == 0)
1079 MVGPrintf(svg_info->file,"push graphic-context\n");
1087 if (LocaleCompare((const char *) name,"svg") == 0)
1089 MVGPrintf(svg_info->file,"push graphic-context\n");
1097 if (LocaleCompare((const char *) name,"text") == 0)
1099 MVGPrintf(svg_info->file,"push graphic-context\n");
1102 if (LocaleCompare((const char *) name,"tspan") == 0)
1104 if (*svg_info->text != '\0')
1115 text=EscapeString(svg_info->text,'\'');
1116 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
1117 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1118 svg_info->center.y,text);
1119 text=DestroyString(text);
1120 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1121 draw_info->pointsize=svg_info->pointsize;
1122 draw_info->text=AcquireString(svg_info->text);
1123 (void) ConcatenateString(&draw_info->text," ");
1124 GetTypeMetrics(svg_info->image,draw_info,&metrics);
1125 svg_info->bounds.x+=metrics.width;
1126 draw_info=DestroyDrawInfo(draw_info);
1127 *svg_info->text='\0';
1129 MVGPrintf(svg_info->file,"push graphic-context\n");
1137 if (attributes != (const xmlChar **) NULL)
1138 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1140 keyword=(const char *) attributes[i];
1141 value=(const char *) attributes[i+1];
1142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1143 " %s = %s",keyword,value);
1149 if (LocaleCompare(keyword,"angle") == 0)
1151 MVGPrintf(svg_info->file,"angle %g\n",
1152 GetUserSpaceCoordinateValue(svg_info,0,value));
1160 if (LocaleCompare(keyword,"clip-path") == 0)
1162 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1165 if (LocaleCompare(keyword,"clip-rule") == 0)
1167 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1170 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1172 (void) CloneString(&units,value);
1173 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1176 if (LocaleCompare(keyword,"color") == 0)
1178 (void) CloneString(&color,value);
1181 if (LocaleCompare(keyword,"cx") == 0)
1183 svg_info->element.cx=
1184 GetUserSpaceCoordinateValue(svg_info,1,value);
1187 if (LocaleCompare(keyword,"cy") == 0)
1189 svg_info->element.cy=
1190 GetUserSpaceCoordinateValue(svg_info,-1,value);
1198 if (LocaleCompare(keyword,"d") == 0)
1200 (void) CloneString(&svg_info->vertices,value);
1203 if (LocaleCompare(keyword,"dx") == 0)
1205 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1208 if (LocaleCompare(keyword,"dy") == 0)
1210 svg_info->bounds.y+=
1211 GetUserSpaceCoordinateValue(svg_info,-1,value);
1219 if (LocaleCompare(keyword,"fill") == 0)
1221 if (LocaleCompare(value,"currentColor") == 0)
1223 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1226 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1229 if (LocaleCompare(keyword,"fillcolor") == 0)
1231 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1234 if (LocaleCompare(keyword,"fill-rule") == 0)
1236 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1239 if (LocaleCompare(keyword,"fill-opacity") == 0)
1241 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1244 if (LocaleCompare(keyword,"font-family") == 0)
1246 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1249 if (LocaleCompare(keyword,"font-stretch") == 0)
1251 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1254 if (LocaleCompare(keyword,"font-style") == 0)
1256 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1259 if (LocaleCompare(keyword,"font-size") == 0)
1261 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1262 MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1265 if (LocaleCompare(keyword,"font-weight") == 0)
1267 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1275 if (LocaleCompare(keyword,"gradientTransform") == 0)
1282 GetAffineMatrix(&transform);
1283 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1284 tokens=GetTransformTokens(context,value,&number_tokens);
1285 for (j=0; j < (number_tokens-1); j+=2)
1287 keyword=(char *) tokens[j];
1288 if (keyword == (char *) NULL)
1290 value=(char *) tokens[j+1];
1291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1292 " %s: %s",keyword,value);
1294 GetAffineMatrix(&affine);
1300 if (LocaleCompare(keyword,"matrix") == 0)
1302 p=(const char *) value;
1303 GetMagickToken(p,&p,token);
1304 affine.sx=StringToDouble(value);
1305 GetMagickToken(p,&p,token);
1307 GetMagickToken(p,&p,token);
1308 affine.rx=StringToDouble(token);
1309 GetMagickToken(p,&p,token);
1311 GetMagickToken(p,&p,token);
1312 affine.ry=StringToDouble(token);
1313 GetMagickToken(p,&p,token);
1315 GetMagickToken(p,&p,token);
1316 affine.sy=StringToDouble(token);
1317 GetMagickToken(p,&p,token);
1319 GetMagickToken(p,&p,token);
1320 affine.tx=StringToDouble(token);
1321 GetMagickToken(p,&p,token);
1323 GetMagickToken(p,&p,token);
1324 affine.ty=StringToDouble(token);
1332 if (LocaleCompare(keyword,"rotate") == 0)
1337 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1338 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1339 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1340 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1341 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1349 if (LocaleCompare(keyword,"scale") == 0)
1351 for (p=(const char *) value; *p != '\0'; p++)
1352 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1355 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1356 affine.sy=affine.sx;
1359 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1360 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1363 if (LocaleCompare(keyword,"skewX") == 0)
1365 affine.sx=svg_info->affine.sx;
1366 affine.ry=tan(DegreesToRadians(fmod(
1367 GetUserSpaceCoordinateValue(svg_info,1,value),
1369 affine.sy=svg_info->affine.sy;
1372 if (LocaleCompare(keyword,"skewY") == 0)
1374 affine.sx=svg_info->affine.sx;
1375 affine.rx=tan(DegreesToRadians(fmod(
1376 GetUserSpaceCoordinateValue(svg_info,-1,value),
1378 affine.sy=svg_info->affine.sy;
1386 if (LocaleCompare(keyword,"translate") == 0)
1388 for (p=(const char *) value; *p != '\0'; p++)
1389 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1392 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1393 affine.ty=affine.tx;
1396 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1404 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1405 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1406 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1407 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1408 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
1410 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
1413 MVGPrintf(svg_info->file,
1414 "affine %g %g %g %g %g %g\n",transform.sx,
1415 transform.rx,transform.ry,transform.sy,transform.tx,
1417 for (j=0; tokens[j] != (char *) NULL; j++)
1418 tokens[j]=DestroyString(tokens[j]);
1419 tokens=(char **) RelinquishMagickMemory(tokens);
1422 if (LocaleCompare(keyword,"gradientUnits") == 0)
1424 (void) CloneString(&units,value);
1425 MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1433 if (LocaleCompare(keyword,"height") == 0)
1435 svg_info->bounds.height=
1436 GetUserSpaceCoordinateValue(svg_info,-1,value);
1439 if (LocaleCompare(keyword,"href") == 0)
1441 (void) CloneString(&svg_info->url,value);
1449 if (LocaleCompare(keyword,"major") == 0)
1451 svg_info->element.major=
1452 GetUserSpaceCoordinateValue(svg_info,1,value);
1455 if (LocaleCompare(keyword,"minor") == 0)
1457 svg_info->element.minor=
1458 GetUserSpaceCoordinateValue(svg_info,-1,value);
1466 if (LocaleCompare(keyword,"offset") == 0)
1468 (void) CloneString(&svg_info->offset,value);
1471 if (LocaleCompare(keyword,"opacity") == 0)
1473 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1481 if (LocaleCompare(keyword,"path") == 0)
1483 (void) CloneString(&svg_info->url,value);
1486 if (LocaleCompare(keyword,"points") == 0)
1488 (void) CloneString(&svg_info->vertices,value);
1496 if (LocaleCompare(keyword,"r") == 0)
1498 svg_info->element.major=
1499 GetUserSpaceCoordinateValue(svg_info,1,value);
1500 svg_info->element.minor=
1501 GetUserSpaceCoordinateValue(svg_info,-1,value);
1504 if (LocaleCompare(keyword,"rotate") == 0)
1509 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1510 MVGPrintf(svg_info->file,"translate %g,%g\n",
1511 svg_info->bounds.x,svg_info->bounds.y);
1512 svg_info->bounds.x=0;
1513 svg_info->bounds.y=0;
1514 MVGPrintf(svg_info->file,"rotate %g\n",angle);
1517 if (LocaleCompare(keyword,"rx") == 0)
1519 if (LocaleCompare((const char *) name,"ellipse") == 0)
1520 svg_info->element.major=
1521 GetUserSpaceCoordinateValue(svg_info,1,value);
1524 GetUserSpaceCoordinateValue(svg_info,1,value);
1527 if (LocaleCompare(keyword,"ry") == 0)
1529 if (LocaleCompare((const char *) name,"ellipse") == 0)
1530 svg_info->element.minor=
1531 GetUserSpaceCoordinateValue(svg_info,-1,value);
1534 GetUserSpaceCoordinateValue(svg_info,-1,value);
1542 if (LocaleCompare(keyword,"stop-color") == 0)
1544 (void) CloneString(&svg_info->stop_color,value);
1547 if (LocaleCompare(keyword,"stroke") == 0)
1549 if (LocaleCompare(value,"currentColor") == 0)
1551 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1554 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1557 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1559 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1560 LocaleCompare(value,"true") == 0);
1563 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1565 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1568 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1570 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1573 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1575 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1578 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1580 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1583 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1585 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1588 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1590 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1593 if (LocaleCompare(keyword,"stroke-width") == 0)
1595 MVGPrintf(svg_info->file,"stroke-width %g\n",
1596 GetUserSpaceCoordinateValue(svg_info,1,value));
1599 if (LocaleCompare(keyword,"style") == 0)
1601 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1602 tokens=GetStyleTokens(context,value,&number_tokens);
1603 for (j=0; j < (number_tokens-1); j+=2)
1605 keyword=(char *) tokens[j];
1606 value=(char *) tokens[j+1];
1607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1608 " %s: %s",keyword,value);
1614 if (LocaleCompare(keyword,"clip-path") == 0)
1616 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1619 if (LocaleCompare(keyword,"clip-rule") == 0)
1621 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1624 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1626 (void) CloneString(&units,value);
1627 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1630 if (LocaleCompare(keyword,"color") == 0)
1632 (void) CloneString(&color,value);
1640 if (LocaleCompare(keyword,"fill") == 0)
1642 if (LocaleCompare(value,"currentColor") == 0)
1644 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1647 if (LocaleCompare(value,"#00000000") == 0)
1648 MVGPrintf(svg_info->file,"fill '#000000'\n");
1650 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1653 if (LocaleCompare(keyword,"fillcolor") == 0)
1655 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1658 if (LocaleCompare(keyword,"fill-rule") == 0)
1660 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1663 if (LocaleCompare(keyword,"fill-opacity") == 0)
1665 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1668 if (LocaleCompare(keyword,"font-family") == 0)
1670 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1673 if (LocaleCompare(keyword,"font-stretch") == 0)
1675 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1678 if (LocaleCompare(keyword,"font-style") == 0)
1680 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1683 if (LocaleCompare(keyword,"font-size") == 0)
1685 svg_info->pointsize=GetUserSpaceCoordinateValue(
1687 MVGPrintf(svg_info->file,"font-size %g\n",
1688 svg_info->pointsize);
1691 if (LocaleCompare(keyword,"font-weight") == 0)
1693 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1701 if (LocaleCompare(keyword,"offset") == 0)
1703 MVGPrintf(svg_info->file,"offset %g\n",
1704 GetUserSpaceCoordinateValue(svg_info,1,value));
1707 if (LocaleCompare(keyword,"opacity") == 0)
1709 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1717 if (LocaleCompare(keyword,"stop-color") == 0)
1719 (void) CloneString(&svg_info->stop_color,value);
1722 if (LocaleCompare(keyword,"stroke") == 0)
1724 if (LocaleCompare(value,"currentColor") == 0)
1726 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1729 if (LocaleCompare(value,"#00000000") == 0)
1730 MVGPrintf(svg_info->file,"fill '#000000'\n");
1732 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1735 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1737 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1738 LocaleCompare(value,"true") == 0);
1741 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1743 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1746 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1748 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1752 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1754 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1757 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1759 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1763 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1765 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1769 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1771 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1774 if (LocaleCompare(keyword,"stroke-width") == 0)
1776 MVGPrintf(svg_info->file,"stroke-width %g\n",
1777 GetUserSpaceCoordinateValue(svg_info,1,value));
1785 if (LocaleCompare(keyword,"text-align") == 0)
1787 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1790 if (LocaleCompare(keyword,"text-anchor") == 0)
1792 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1795 if (LocaleCompare(keyword,"text-decoration") == 0)
1797 if (LocaleCompare(value,"underline") == 0)
1798 MVGPrintf(svg_info->file,"decorate underline\n");
1799 if (LocaleCompare(value,"line-through") == 0)
1800 MVGPrintf(svg_info->file,"decorate line-through\n");
1801 if (LocaleCompare(value,"overline") == 0)
1802 MVGPrintf(svg_info->file,"decorate overline\n");
1805 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1807 MVGPrintf(svg_info->file,"text-antialias %d\n",
1808 LocaleCompare(value,"true") == 0);
1817 for (j=0; tokens[j] != (char *) NULL; j++)
1818 tokens[j]=DestroyString(tokens[j]);
1819 tokens=(char **) RelinquishMagickMemory(tokens);
1827 if (LocaleCompare(keyword,"text-align") == 0)
1829 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1832 if (LocaleCompare(keyword,"text-anchor") == 0)
1834 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1837 if (LocaleCompare(keyword,"text-decoration") == 0)
1839 if (LocaleCompare(value,"underline") == 0)
1840 MVGPrintf(svg_info->file,"decorate underline\n");
1841 if (LocaleCompare(value,"line-through") == 0)
1842 MVGPrintf(svg_info->file,"decorate line-through\n");
1843 if (LocaleCompare(value,"overline") == 0)
1844 MVGPrintf(svg_info->file,"decorate overline\n");
1847 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1849 MVGPrintf(svg_info->file,"text-antialias %d\n",
1850 LocaleCompare(value,"true") == 0);
1853 if (LocaleCompare(keyword,"transform") == 0)
1860 GetAffineMatrix(&transform);
1861 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1862 tokens=GetTransformTokens(context,value,&number_tokens);
1863 for (j=0; j < (number_tokens-1); j+=2)
1865 keyword=(char *) tokens[j];
1866 value=(char *) tokens[j+1];
1867 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1868 " %s: %s",keyword,value);
1870 GetAffineMatrix(&affine);
1876 if (LocaleCompare(keyword,"matrix") == 0)
1878 p=(const char *) value;
1879 GetMagickToken(p,&p,token);
1880 affine.sx=StringToDouble(value);
1881 GetMagickToken(p,&p,token);
1883 GetMagickToken(p,&p,token);
1884 affine.rx=StringToDouble(token);
1885 GetMagickToken(p,&p,token);
1887 GetMagickToken(p,&p,token);
1888 affine.ry=StringToDouble(token);
1889 GetMagickToken(p,&p,token);
1891 GetMagickToken(p,&p,token);
1892 affine.sy=StringToDouble(token);
1893 GetMagickToken(p,&p,token);
1895 GetMagickToken(p,&p,token);
1896 affine.tx=StringToDouble(token);
1897 GetMagickToken(p,&p,token);
1899 GetMagickToken(p,&p,token);
1900 affine.ty=StringToDouble(token);
1908 if (LocaleCompare(keyword,"rotate") == 0)
1915 p=(const char *) value;
1916 GetMagickToken(p,&p,token);
1917 angle=StringToDouble(value);
1918 GetMagickToken(p,&p,token);
1920 GetMagickToken(p,&p,token);
1921 x=StringToDouble(token);
1922 GetMagickToken(p,&p,token);
1924 GetMagickToken(p,&p,token);
1925 y=StringToDouble(token);
1926 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1927 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1928 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1929 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1932 svg_info->center.x=x;
1933 svg_info->center.y=y;
1941 if (LocaleCompare(keyword,"scale") == 0)
1943 for (p=(const char *) value; *p != '\0'; p++)
1944 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1947 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1948 affine.sy=affine.sx;
1950 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1952 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1955 if (LocaleCompare(keyword,"skewX") == 0)
1957 affine.sx=svg_info->affine.sx;
1958 affine.ry=tan(DegreesToRadians(fmod(
1959 GetUserSpaceCoordinateValue(svg_info,1,value),
1961 affine.sy=svg_info->affine.sy;
1964 if (LocaleCompare(keyword,"skewY") == 0)
1966 affine.sx=svg_info->affine.sx;
1967 affine.rx=tan(DegreesToRadians(fmod(
1968 GetUserSpaceCoordinateValue(svg_info,-1,value),
1970 affine.sy=svg_info->affine.sy;
1978 if (LocaleCompare(keyword,"translate") == 0)
1980 for (p=(const char *) value; *p != '\0'; p++)
1981 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1984 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1985 affine.ty=affine.tx;
1987 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
1996 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1997 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1998 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1999 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2000 transform.tx=affine.sx*current.tx+affine.ry*current.ty+
2002 transform.ty=affine.rx*current.tx+affine.sy*current.ty+
2005 MVGPrintf(svg_info->file,
2006 "affine %g %g %g %g %g %g\n",transform.sx,
2007 transform.rx,transform.ry,transform.sy,transform.tx,
2009 for (j=0; tokens[j] != (char *) NULL; j++)
2010 tokens[j]=DestroyString(tokens[j]);
2011 tokens=(char **) RelinquishMagickMemory(tokens);
2019 if (LocaleCompare(keyword,"verts") == 0)
2021 (void) CloneString(&svg_info->vertices,value);
2024 if (LocaleCompare(keyword,"viewBox") == 0)
2026 p=(const char *) value;
2027 GetMagickToken(p,&p,token);
2028 svg_info->view_box.x=StringToDouble(token);
2029 GetMagickToken(p,&p,token);
2031 GetMagickToken(p,&p,token);
2032 svg_info->view_box.y=StringToDouble(token);
2033 GetMagickToken(p,&p,token);
2035 GetMagickToken(p,&p,token);
2036 svg_info->view_box.width=StringToDouble(token);
2037 if (svg_info->bounds.width == 0)
2038 svg_info->bounds.width=svg_info->view_box.width;
2039 GetMagickToken(p,&p,token);
2041 GetMagickToken(p,&p,token);
2042 svg_info->view_box.height=StringToDouble(token);
2043 if (svg_info->bounds.height == 0)
2044 svg_info->bounds.height=svg_info->view_box.height;
2052 if (LocaleCompare(keyword,"width") == 0)
2054 svg_info->bounds.width=
2055 GetUserSpaceCoordinateValue(svg_info,1,value);
2063 if (LocaleCompare(keyword,"x") == 0)
2065 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2068 if (LocaleCompare(keyword,"xlink:href") == 0)
2070 (void) CloneString(&svg_info->url,value);
2073 if (LocaleCompare(keyword,"x1") == 0)
2075 svg_info->segment.x1=
2076 GetUserSpaceCoordinateValue(svg_info,1,value);
2079 if (LocaleCompare(keyword,"x2") == 0)
2081 svg_info->segment.x2=
2082 GetUserSpaceCoordinateValue(svg_info,1,value);
2090 if (LocaleCompare(keyword,"y") == 0)
2092 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2095 if (LocaleCompare(keyword,"y1") == 0)
2097 svg_info->segment.y1=
2098 GetUserSpaceCoordinateValue(svg_info,-1,value);
2101 if (LocaleCompare(keyword,"y2") == 0)
2103 svg_info->segment.y2=
2104 GetUserSpaceCoordinateValue(svg_info,-1,value);
2113 if (LocaleCompare((const char *) name,"svg") == 0)
2115 if (svg_info->document->encoding != (const xmlChar *) NULL)
2116 MVGPrintf(svg_info->file,"encoding \"%s\"\n",
2117 (const char *) svg_info->document->encoding);
2118 if (attributes != (const xmlChar **) NULL)
2124 if ((svg_info->view_box.width == 0.0) ||
2125 (svg_info->view_box.height == 0.0))
2126 svg_info->view_box=svg_info->bounds;
2127 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2128 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2129 MVGPrintf(svg_info->file,"viewbox 0 0 %.20g %.20g\n",(double)
2130 svg_info->width,(double) svg_info->height);
2131 sx=(double) svg_info->width/svg_info->view_box.width;
2132 sy=(double) svg_info->height/svg_info->view_box.height;
2133 MVGPrintf(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",sx,sy);
2136 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2137 units=DestroyString(units);
2138 if (color != (char *) NULL)
2139 color=DestroyString(color);
2142 static void SVGEndElement(void *context,const xmlChar *name)
2148 Called when the end of an element has been detected.
2150 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2151 " SAX.endElement(%s)",name);
2152 svg_info=(SVGInfo *) context;
2153 if (strchr((char *) name,':') != (char *) NULL)
2156 Skip over namespace.
2158 for ( ; *name != ':'; name++) ;
2166 if (LocaleCompare((const char *) name,"circle") == 0)
2168 MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",
2169 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2170 svg_info->element.cy+svg_info->element.minor);
2171 MVGPrintf(svg_info->file,"pop graphic-context\n");
2174 if (LocaleCompare((const char *) name,"clipPath") == 0)
2176 MVGPrintf(svg_info->file,"pop clip-path\n");
2184 if (LocaleCompare((const char *) name,"defs") == 0)
2186 MVGPrintf(svg_info->file,"pop defs\n");
2189 if (LocaleCompare((const char *) name,"desc") == 0)
2194 if (*svg_info->text == '\0')
2196 (void) fputc('#',svg_info->file);
2197 for (p=svg_info->text; *p != '\0'; p++)
2199 (void) fputc(*p,svg_info->file);
2201 (void) fputc('#',svg_info->file);
2203 (void) fputc('\n',svg_info->file);
2204 *svg_info->text='\0';
2212 if (LocaleCompare((const char *) name,"ellipse") == 0)
2217 angle=svg_info->element.angle;
2218 MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2219 svg_info->element.cx,svg_info->element.cy,
2220 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2221 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2222 MVGPrintf(svg_info->file,"pop graphic-context\n");
2230 if (LocaleCompare((const char *) name,"g") == 0)
2232 MVGPrintf(svg_info->file,"pop graphic-context\n");
2240 if (LocaleCompare((const char *) name,"image") == 0)
2242 MVGPrintf(svg_info->file,"image Over %g,%g %g,%g '%s'\n",
2243 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2244 svg_info->bounds.height,svg_info->url);
2245 MVGPrintf(svg_info->file,"pop graphic-context\n");
2253 if (LocaleCompare((const char *) name,"line") == 0)
2255 MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",
2256 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2257 svg_info->segment.y2);
2258 MVGPrintf(svg_info->file,"pop graphic-context\n");
2261 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2263 MVGPrintf(svg_info->file,"pop gradient\n");
2271 if (LocaleCompare((const char *) name,"pattern") == 0)
2273 MVGPrintf(svg_info->file,"pop pattern\n");
2276 if (LocaleCompare((const char *) name,"path") == 0)
2278 MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2279 MVGPrintf(svg_info->file,"pop graphic-context\n");
2282 if (LocaleCompare((const char *) name,"polygon") == 0)
2284 MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2285 MVGPrintf(svg_info->file,"pop graphic-context\n");
2288 if (LocaleCompare((const char *) name,"polyline") == 0)
2290 MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2291 MVGPrintf(svg_info->file,"pop graphic-context\n");
2299 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2301 MVGPrintf(svg_info->file,"pop gradient\n");
2304 if (LocaleCompare((const char *) name,"rect") == 0)
2306 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2308 MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2309 svg_info->bounds.x,svg_info->bounds.y,
2310 svg_info->bounds.x+svg_info->bounds.width,
2311 svg_info->bounds.y+svg_info->bounds.height);
2312 MVGPrintf(svg_info->file,"pop graphic-context\n");
2315 if (svg_info->radius.x == 0.0)
2316 svg_info->radius.x=svg_info->radius.y;
2317 if (svg_info->radius.y == 0.0)
2318 svg_info->radius.y=svg_info->radius.x;
2319 MVGPrintf(svg_info->file,
2320 "roundRectangle %g,%g %g,%g %g,%g\n",
2321 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2322 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2323 svg_info->radius.x,svg_info->radius.y);
2324 svg_info->radius.x=0.0;
2325 svg_info->radius.y=0.0;
2326 MVGPrintf(svg_info->file,"pop graphic-context\n");
2334 if (LocaleCompare((const char *) name,"stop") == 0)
2336 MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2340 if (LocaleCompare((const char *) name,"svg") == 0)
2342 MVGPrintf(svg_info->file,"pop graphic-context\n");
2350 if (LocaleCompare((const char *) name,"text") == 0)
2352 if (*svg_info->text != '\0')
2357 text=EscapeString(svg_info->text,'\'');
2358 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",
2359 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
2360 svg_info->center.y,text);
2361 text=DestroyString(text);
2362 *svg_info->text='\0';
2364 MVGPrintf(svg_info->file,"pop graphic-context\n");
2367 if (LocaleCompare((const char *) name,"tspan") == 0)
2369 if (*svg_info->text != '\0')
2380 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;
2489 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2490 const xmlChar *data)
2496 A processing instruction has been parsed.
2498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2499 " SAX.processingInstruction(%s, %s)",target,data);
2500 svg_info=(SVGInfo *) context;
2504 static void SVGComment(void *context,const xmlChar *value)
2510 A comment has been parsed.
2512 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2514 svg_info=(SVGInfo *) context;
2515 if (svg_info->comment != (char *) NULL)
2516 (void) ConcatenateString(&svg_info->comment,"\n");
2517 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2520 static void SVGWarning(void *context,const char *format,...)
2524 reason[MaxTextExtent];
2533 Display and format a warning messages, gives file, line, position and
2536 va_start(operands,format);
2537 svg_info=(SVGInfo *) context;
2538 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2540 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2541 (void) vsprintf(reason,format,operands);
2543 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2545 message=GetExceptionMessage(errno);
2546 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2547 DelegateWarning,reason,"`%s`",message);
2548 message=DestroyString(message);
2552 static void SVGError(void *context,const char *format,...)
2556 reason[MaxTextExtent];
2565 Display and format a error formats, gives file, line, position and
2568 va_start(operands,format);
2569 svg_info=(SVGInfo *) context;
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2572 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2573 (void) vsprintf(reason,format,operands);
2575 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2577 message=GetExceptionMessage(errno);
2578 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2579 reason,"`%s`",message);
2580 message=DestroyString(message);
2584 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2596 Called when a pcdata block has been parsed.
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2600 svg_info=(SVGInfo *) context;
2601 parser=svg_info->parser;
2602 child=xmlGetLastChild(parser->node);
2603 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2605 xmlTextConcat(child,value,length);
2608 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2611 static void SVGExternalSubset(void *context,const xmlChar *name,
2612 const xmlChar *external_id,const xmlChar *system_id)
2627 Does this document has an external subset?
2629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2630 " SAX.externalSubset(%s, %s, %s)",name,
2631 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2632 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2633 svg_info=(SVGInfo *) context;
2634 parser=svg_info->parser;
2635 if (((external_id == NULL) && (system_id == NULL)) ||
2636 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2637 (svg_info->document == 0)))
2639 input=SVGResolveEntity(context,external_id,system_id);
2642 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2643 parser_context=(*parser);
2644 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2645 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2647 parser->errNo=XML_ERR_NO_MEMORY;
2648 parser->input=parser_context.input;
2649 parser->inputNr=parser_context.inputNr;
2650 parser->inputMax=parser_context.inputMax;
2651 parser->inputTab=parser_context.inputTab;
2657 xmlPushInput(parser,input);
2658 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2659 if (input->filename == (char *) NULL)
2660 input->filename=(char *) xmlStrdup(system_id);
2663 input->base=parser->input->cur;
2664 input->cur=parser->input->cur;
2666 xmlParseExternalSubset(parser,external_id,system_id);
2667 while (parser->inputNr > 1)
2668 (void) xmlPopInput(parser);
2669 xmlFreeInputStream(parser->input);
2670 xmlFree(parser->inputTab);
2671 parser->input=parser_context.input;
2672 parser->inputNr=parser_context.inputNr;
2673 parser->inputMax=parser_context.inputMax;
2674 parser->inputTab=parser_context.inputTab;
2677 #if defined(MAGICKCORE_RSVG_DELEGATE)
2678 static void SVGSetImageSize(int *width,int *height,gpointer context)
2683 image=(Image *) context;
2684 *width=(int) (*width*image->x_resolution/72.0);
2685 *height=(int) (*height*image->y_resolution/72.0);
2689 #if defined(__cplusplus) || defined(c_plusplus)
2693 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2696 filename[MaxTextExtent];
2715 message[MaxTextExtent];
2726 assert(image_info != (const ImageInfo *) NULL);
2727 assert(image_info->signature == MagickSignature);
2728 assert(exception != (ExceptionInfo *) NULL);
2729 if (image_info->debug != MagickFalse)
2730 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2731 image_info->filename);
2732 assert(exception->signature == MagickSignature);
2733 image=AcquireImage(image_info);
2734 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2735 if (status == MagickFalse)
2737 image=DestroyImageList(image);
2738 return((Image *) NULL);
2740 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2742 #if defined(MAGICKCORE_RSVG_DELEGATE)
2743 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2750 register unsigned char
2763 register const guchar
2780 register PixelPacket
2786 svg_handle=rsvg_handle_new();
2787 if (svg_handle == (RsvgHandle *) NULL)
2788 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2789 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2790 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2791 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2792 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2793 image->y_resolution);
2794 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2796 error=(GError *) NULL;
2797 (void) rsvg_handle_write(svg_handle,message,n,&error);
2798 if (error != (GError *) NULL)
2799 g_error_free(error);
2801 error=(GError *) NULL;
2802 rsvg_handle_close(svg_handle,&error);
2803 if (error != (GError *) NULL)
2804 g_error_free(error);
2805 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2806 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2807 image->columns=dimension_info.width;
2808 image->rows=dimension_info.height;
2809 pixels=(unsigned char *) NULL;
2811 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2812 rsvg_handle_free(svg_handle);
2813 image->columns=gdk_pixbuf_get_width(pixel_info);
2814 image->rows=gdk_pixbuf_get_height(pixel_info);
2816 image->matte=MagickTrue;
2817 SetImageProperty(image,"svg:base-uri",
2818 rsvg_handle_get_base_uri(svg_handle));
2819 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2820 SetImageProperty(image,"svg:description",
2821 rsvg_handle_get_desc(svg_handle));
2822 if ((image->columns == 0) || (image->rows == 0))
2824 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2825 g_object_unref(G_OBJECT(pixel_info));
2827 g_object_unref(svg_handle);
2828 ThrowReaderException(MissingDelegateError,
2829 "NoDecodeDelegateForThisImageFormat");
2831 if (image_info->ping == MagickFalse)
2833 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2834 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2835 image->rows*sizeof(*pixels));
2836 if (pixels == (unsigned char *) NULL)
2838 g_object_unref(svg_handle);
2839 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2842 (void) SetImageBackgroundColor(image);
2843 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2844 cairo_surface=cairo_image_surface_create_for_data(pixels,
2845 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2846 if (cairo_surface == (cairo_surface_t *) NULL)
2848 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2849 g_object_unref(svg_handle);
2850 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2852 cairo_info=cairo_create(cairo_surface);
2853 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2854 cairo_paint(cairo_info);
2855 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2856 rsvg_handle_render_cairo(svg_handle,cairo_info);
2857 cairo_destroy(cairo_info);
2858 cairo_surface_destroy(cairo_surface);
2859 g_object_unref(svg_handle);
2862 p=gdk_pixbuf_get_pixels(pixel_info);
2864 for (y=0; y < (ssize_t) image->rows; y++)
2866 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2867 if (q == (PixelPacket *) NULL)
2869 for (x=0; x < (ssize_t) image->columns; x++)
2871 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2872 fill_color.blue=ScaleCharToQuantum(*p++);
2873 fill_color.green=ScaleCharToQuantum(*p++);
2874 fill_color.red=ScaleCharToQuantum(*p++);
2876 fill_color.red=ScaleCharToQuantum(*p++);
2877 fill_color.green=ScaleCharToQuantum(*p++);
2878 fill_color.blue=ScaleCharToQuantum(*p++);
2880 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2881 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2886 gamma=1.0-QuantumScale*fill_color.opacity;
2887 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2888 fill_color.blue*=gamma;
2889 fill_color.green*=gamma;
2890 fill_color.red*=gamma;
2893 MagickCompositeOver(&fill_color,fill_color.opacity,q,
2894 (MagickRealType) q->opacity,q);
2897 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2899 if (image->previous == (Image *) NULL)
2901 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2903 if (status == MagickFalse)
2908 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2909 if (pixels != (unsigned char *) NULL)
2910 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2912 g_object_unref(G_OBJECT(pixel_info));
2914 (void) CloseBlob(image);
2915 return(GetFirstImageInList(image));
2922 unique_file=AcquireUniqueFileResource(filename);
2923 if (unique_file != -1)
2924 file=fdopen(unique_file,"w");
2925 if ((unique_file == -1) || (file == (FILE *) NULL))
2927 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2928 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2930 image=DestroyImageList(image);
2931 return((Image *) NULL);
2936 svg_info=AcquireSVGInfo();
2937 if (svg_info == (SVGInfo *) NULL)
2938 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2939 svg_info->file=file;
2940 svg_info->exception=exception;
2941 svg_info->image=image;
2942 svg_info->image_info=image_info;
2943 svg_info->bounds.width=image->columns;
2944 svg_info->bounds.height=image->rows;
2945 if (image_info->size != (char *) NULL)
2946 (void) CloneString(&svg_info->size,image_info->size);
2947 if (image->debug != MagickFalse)
2948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2950 (void) xmlSubstituteEntitiesDefault(1);
2951 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
2952 sax_modules.internalSubset=SVGInternalSubset;
2953 sax_modules.isStandalone=SVGIsStandalone;
2954 sax_modules.hasInternalSubset=SVGHasInternalSubset;
2955 sax_modules.hasExternalSubset=SVGHasExternalSubset;
2956 sax_modules.resolveEntity=SVGResolveEntity;
2957 sax_modules.getEntity=SVGGetEntity;
2958 sax_modules.entityDecl=SVGEntityDeclaration;
2959 sax_modules.notationDecl=SVGNotationDeclaration;
2960 sax_modules.attributeDecl=SVGAttributeDeclaration;
2961 sax_modules.elementDecl=SVGElementDeclaration;
2962 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
2963 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
2964 sax_modules.startDocument=SVGStartDocument;
2965 sax_modules.endDocument=SVGEndDocument;
2966 sax_modules.startElement=SVGStartElement;
2967 sax_modules.endElement=SVGEndElement;
2968 sax_modules.reference=SVGReference;
2969 sax_modules.characters=SVGCharacters;
2970 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
2971 sax_modules.processingInstruction=SVGProcessingInstructions;
2972 sax_modules.comment=SVGComment;
2973 sax_modules.warning=SVGWarning;
2974 sax_modules.error=SVGError;
2975 sax_modules.fatalError=SVGError;
2976 sax_modules.getParameterEntity=SVGGetParameterEntity;
2977 sax_modules.cdataBlock=SVGCDataBlock;
2978 sax_modules.externalSubset=SVGExternalSubset;
2979 sax_handler=(&sax_modules);
2980 n=ReadBlob(image,MaxTextExtent,message);
2983 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2984 message,n,image->filename);
2985 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2987 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2992 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2993 xmlFreeParserCtxt(svg_info->parser);
2994 if (image->debug != MagickFalse)
2995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2997 (void) fclose(file);
2998 (void) CloseBlob(image);
2999 image->columns=svg_info->width;
3000 image->rows=svg_info->height;
3001 if (exception->severity >= ErrorException)
3003 image=DestroyImage(image);
3004 return((Image *) NULL);
3006 if (image_info->ping == MagickFalse)
3014 image=DestroyImage(image);
3015 image=(Image *) NULL;
3016 read_info=CloneImageInfo(image_info);
3017 SetImageInfoBlob(read_info,(void *) NULL,0);
3018 if (read_info->density != (char *) NULL)
3019 read_info->density=DestroyString(read_info->density);
3020 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
3022 image=ReadImage(read_info,exception);
3023 read_info=DestroyImageInfo(read_info);
3024 if (image != (Image *) NULL)
3025 (void) CopyMagickString(image->filename,image_info->filename,
3029 Relinquish resources.
3031 if (image != (Image *) NULL)
3033 if (svg_info->title != (char *) NULL)
3034 (void) SetImageProperty(image,"svg:title",svg_info->title);
3035 if (svg_info->comment != (char *) NULL)
3036 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
3038 svg_info=DestroySVGInfo(svg_info);
3039 (void) RelinquishUniqueFileResource(filename);
3040 return(GetFirstImageInList(image));
3045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049 % R e g i s t e r S V G I m a g e %
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 % RegisterSVGImage() adds attributes for the SVG image format to
3056 % the list of supported formats. The attributes include the image format
3057 % tag, a method to read and/or write the format, whether the format
3058 % supports the saving of more than one frame to the same file or blob,
3059 % whether the format supports native in-memory I/O, and a brief
3060 % description of the format.
3062 % The format of the RegisterSVGImage method is:
3064 % size_t RegisterSVGImage(void)
3067 ModuleExport size_t RegisterSVGImage(void)
3070 version[MaxTextExtent];
3076 #if defined(LIBXML_DOTTED_VERSION)
3077 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3079 #if defined(MAGICKCORE_RSVG_DELEGATE)
3081 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3082 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3084 entry=SetMagickInfo("SVG");
3085 #if defined(MAGICKCORE_XML_DELEGATE)
3086 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3088 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3089 entry->blob_support=MagickFalse;
3090 entry->seekable_stream=MagickFalse;
3091 entry->description=ConstantString("Scalable Vector Graphics");
3092 if (*version != '\0')
3093 entry->version=ConstantString(version);
3094 entry->magick=(IsImageFormatHandler *) IsSVG;
3095 entry->module=ConstantString("SVG");
3096 (void) RegisterMagickInfo(entry);
3097 entry=SetMagickInfo("SVGZ");
3098 #if defined(MAGICKCORE_XML_DELEGATE)
3099 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3101 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3102 entry->blob_support=MagickFalse;
3103 entry->seekable_stream=MagickFalse;
3104 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3105 if (*version != '\0')
3106 entry->version=ConstantString(version);
3107 entry->magick=(IsImageFormatHandler *) IsSVG;
3108 entry->module=ConstantString("SVG");
3109 (void) RegisterMagickInfo(entry);
3110 entry=SetMagickInfo("MSVG");
3111 #if defined(MAGICKCORE_XML_DELEGATE)
3112 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3114 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3115 entry->blob_support=MagickFalse;
3116 entry->seekable_stream=MagickFalse;
3117 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3118 entry->magick=(IsImageFormatHandler *) IsSVG;
3119 entry->module=ConstantString("SVG");
3120 (void) RegisterMagickInfo(entry);
3121 return(MagickImageCoderSignature);
3125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129 % U n r e g i s t e r S V G I m a g e %
3133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3135 % UnregisterSVGImage() removes format registrations made by the
3136 % SVG module from the list of supported formats.
3138 % The format of the UnregisterSVGImage method is:
3140 % UnregisterSVGImage(void)
3143 ModuleExport void UnregisterSVGImage(void)
3145 (void) UnregisterMagickInfo("SVGZ");
3146 (void) UnregisterMagickInfo("SVG");
3147 (void) UnregisterMagickInfo("MSVG");
3148 #if defined(MAGICKCORE_RSVG_DELEGATE)
3154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3158 % W r i t e S V G I m a g e %
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3167 % The format of the WriteSVGImage method is:
3169 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3171 % A description of each parameter follows.
3173 % o image_info: the image info.
3175 % o image: The image.
3179 static void AffineToTransform(Image *image,AffineMatrix *affine)
3182 transform[MaxTextExtent];
3184 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3186 if ((fabs(affine->rx) < MagickEpsilon) &&
3187 (fabs(affine->ry) < MagickEpsilon))
3189 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3190 (fabs(affine->sy-1.0) < MagickEpsilon))
3192 (void) WriteBlobString(image,"\">\n");
3195 (void) FormatMagickString(transform,MaxTextExtent,
3196 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3197 (void) WriteBlobString(image,transform);
3202 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3203 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3204 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3210 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3211 (void) FormatMagickString(transform,MaxTextExtent,
3212 "\" transform=\"rotate(%g)\">\n",theta);
3213 (void) WriteBlobString(image,transform);
3220 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3221 (fabs(affine->rx) < MagickEpsilon) &&
3222 (fabs(affine->ry) < MagickEpsilon) &&
3223 (fabs(affine->sy-1.0) < MagickEpsilon))
3225 (void) FormatMagickString(transform,MaxTextExtent,
3226 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3227 (void) WriteBlobString(image,transform);
3231 (void) FormatMagickString(transform,MaxTextExtent,
3232 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3233 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3234 (void) WriteBlobString(image,transform);
3237 static MagickBooleanType IsPoint(const char *point)
3245 value=strtol(point,&p,10);
3247 return(p != point ? MagickTrue : MagickFalse);
3250 static MagickBooleanType TraceSVGImage(Image *image)
3255 register const PixelPacket
3261 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3266 at_fitting_opts_type
3285 Trace image and write as SVG.
3287 fitting_options=at_fitting_opts_new();
3288 output_options=at_output_opts_new();
3289 type=GetImageType(image,&image->exception);
3291 if ((type == BilevelType) || (type == GrayscaleType))
3293 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3295 for (y=0; y < (ssize_t) image->rows; y++)
3297 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3298 if (p == (const PixelPacket *) NULL)
3300 for (x=0; x < (ssize_t) image->columns; x++)
3302 trace->bitmap[i++]=GetRedPixelComponent(p);
3303 if (number_planes == 3)
3305 trace->bitmap[i++]=GetGreenPixelComponent(p);
3306 trace->bitmap[i++]=GetBluePixelComponent(p);
3311 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3313 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3314 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3319 at_splines_free(splines);
3320 at_bitmap_free(trace);
3321 at_output_opts_free(output_options);
3322 at_fitting_opts_free(fitting_options);
3327 message[MaxTextExtent],
3328 tuple[MaxTextExtent];
3333 register const IndexPacket
3336 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3337 (void) WriteBlobString(image,
3338 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3339 (void) WriteBlobString(image,
3340 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3341 (void) FormatMagickString(message,MaxTextExtent,
3342 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3343 (double) image->rows);
3344 (void) WriteBlobString(image,message);
3345 GetMagickPixelPacket(image,&pixel);
3346 for (y=0; y < (ssize_t) image->rows; y++)
3348 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3349 if (p == (const PixelPacket *) NULL)
3351 indexes=GetVirtualIndexQueue(image);
3352 for (x=0; x < (ssize_t) image->columns; x++)
3354 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3355 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3357 (void) FormatMagickString(message,MaxTextExtent,
3358 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3359 (double) x,(double) y,tuple);
3360 (void) WriteBlobString(image,message);
3364 (void) WriteBlobString(image,"</svg>\n");
3370 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3372 #define BezierQuantum 200
3378 keyword[MaxTextExtent],
3379 message[MaxTextExtent],
3380 name[MaxTextExtent],
3382 type[MaxTextExtent];
3424 Open output image file.
3426 assert(image_info != (const ImageInfo *) NULL);
3427 assert(image_info->signature == MagickSignature);
3428 assert(image != (Image *) NULL);
3429 assert(image->signature == MagickSignature);
3430 if (image->debug != MagickFalse)
3431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3432 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3433 if (status == MagickFalse)
3435 value=GetImageArtifact(image,"SVG");
3436 if (value != (char *) NULL)
3438 (void) WriteBlobString(image,value);
3439 (void) CloseBlob(image);
3442 value=GetImageArtifact(image,"MVG");
3443 if (value == (char *) NULL)
3444 return(TraceSVGImage(image));
3448 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3449 (void) WriteBlobString(image,
3450 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3451 (void) WriteBlobString(image,
3452 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3453 (void) FormatMagickString(message,MaxTextExtent,
3454 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3456 (void) WriteBlobString(image,message);
3458 Allocate primitive info memory.
3461 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3462 sizeof(*primitive_info));
3463 if (primitive_info == (PrimitiveInfo *) NULL)
3464 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3465 GetAffineMatrix(&affine);
3466 token=AcquireString(value);
3470 for (q=(const char *) value; *q != '\0'; )
3473 Interpret graphic primitive.
3475 GetMagickToken(q,&q,keyword);
3476 if (*keyword == '\0')
3478 if (*keyword == '#')
3483 if (active != MagickFalse)
3485 AffineToTransform(image,&affine);
3488 (void) WriteBlobString(image,"<desc>");
3489 (void) WriteBlobString(image,keyword+1);
3490 for ( ; (*q != '\n') && (*q != '\0'); q++)
3493 case '<': (void) WriteBlobString(image,"<"); break;
3494 case '>': (void) WriteBlobString(image,">"); break;
3495 case '&': (void) WriteBlobString(image,"&"); break;
3496 default: (void) WriteBlobByte(image,*q); break;
3498 (void) WriteBlobString(image,"</desc>\n");
3501 primitive_type=UndefinedPrimitive;
3509 if (LocaleCompare("affine",keyword) == 0)
3511 GetMagickToken(q,&q,token);
3512 affine.sx=StringToDouble(token);
3513 GetMagickToken(q,&q,token);
3515 GetMagickToken(q,&q,token);
3516 affine.rx=StringToDouble(token);
3517 GetMagickToken(q,&q,token);
3519 GetMagickToken(q,&q,token);
3520 affine.ry=StringToDouble(token);
3521 GetMagickToken(q,&q,token);
3523 GetMagickToken(q,&q,token);
3524 affine.sy=StringToDouble(token);
3525 GetMagickToken(q,&q,token);
3527 GetMagickToken(q,&q,token);
3528 affine.tx=StringToDouble(token);
3529 GetMagickToken(q,&q,token);
3531 GetMagickToken(q,&q,token);
3532 affine.ty=StringToDouble(token);
3535 if (LocaleCompare("angle",keyword) == 0)
3537 GetMagickToken(q,&q,token);
3538 affine.rx=StringToDouble(token);
3539 affine.ry=StringToDouble(token);
3542 if (LocaleCompare("arc",keyword) == 0)
3544 primitive_type=ArcPrimitive;
3553 if (LocaleCompare("bezier",keyword) == 0)
3555 primitive_type=BezierPrimitive;
3564 if (LocaleCompare("clip-path",keyword) == 0)
3566 GetMagickToken(q,&q,token);
3567 (void) FormatMagickString(message,MaxTextExtent,
3568 "clip-path:url(#%s);",token);
3569 (void) WriteBlobString(image,message);
3572 if (LocaleCompare("clip-rule",keyword) == 0)
3574 GetMagickToken(q,&q,token);
3575 (void) FormatMagickString(message,MaxTextExtent,
3576 "clip-rule:%s;",token);
3577 (void) WriteBlobString(image,message);
3580 if (LocaleCompare("clip-units",keyword) == 0)
3582 GetMagickToken(q,&q,token);
3583 (void) FormatMagickString(message,MaxTextExtent,
3584 "clipPathUnits=%s;",token);
3585 (void) WriteBlobString(image,message);
3588 if (LocaleCompare("circle",keyword) == 0)
3590 primitive_type=CirclePrimitive;
3593 if (LocaleCompare("color",keyword) == 0)
3595 primitive_type=ColorPrimitive;
3604 if (LocaleCompare("decorate",keyword) == 0)
3606 GetMagickToken(q,&q,token);
3607 (void) FormatMagickString(message,MaxTextExtent,
3608 "text-decoration:%s;",token);
3609 (void) WriteBlobString(image,message);
3618 if (LocaleCompare("ellipse",keyword) == 0)
3620 primitive_type=EllipsePrimitive;
3629 if (LocaleCompare("fill",keyword) == 0)
3631 GetMagickToken(q,&q,token);
3632 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3634 (void) WriteBlobString(image,message);
3637 if (LocaleCompare("fill-rule",keyword) == 0)
3639 GetMagickToken(q,&q,token);
3640 (void) FormatMagickString(message,MaxTextExtent,
3641 "fill-rule:%s;",token);
3642 (void) WriteBlobString(image,message);
3645 if (LocaleCompare("fill-opacity",keyword) == 0)
3647 GetMagickToken(q,&q,token);
3648 (void) FormatMagickString(message,MaxTextExtent,
3649 "fill-opacity:%s;",token);
3650 (void) WriteBlobString(image,message);
3653 if (LocaleCompare("font-family",keyword) == 0)
3655 GetMagickToken(q,&q,token);
3656 (void) FormatMagickString(message,MaxTextExtent,
3657 "font-family:%s;",token);
3658 (void) WriteBlobString(image,message);
3661 if (LocaleCompare("font-stretch",keyword) == 0)
3663 GetMagickToken(q,&q,token);
3664 (void) FormatMagickString(message,MaxTextExtent,
3665 "font-stretch:%s;",token);
3666 (void) WriteBlobString(image,message);
3669 if (LocaleCompare("font-style",keyword) == 0)
3671 GetMagickToken(q,&q,token);
3672 (void) FormatMagickString(message,MaxTextExtent,
3673 "font-style:%s;",token);
3674 (void) WriteBlobString(image,message);
3677 if (LocaleCompare("font-size",keyword) == 0)
3679 GetMagickToken(q,&q,token);
3680 (void) FormatMagickString(message,MaxTextExtent,
3681 "font-size:%s;",token);
3682 (void) WriteBlobString(image,message);
3685 if (LocaleCompare("font-weight",keyword) == 0)
3687 GetMagickToken(q,&q,token);
3688 (void) FormatMagickString(message,MaxTextExtent,
3689 "font-weight:%s;",token);
3690 (void) WriteBlobString(image,message);
3699 if (LocaleCompare("gradient-units",keyword) == 0)
3701 GetMagickToken(q,&q,token);
3704 if (LocaleCompare("text-align",keyword) == 0)
3706 GetMagickToken(q,&q,token);
3707 (void) FormatMagickString(message,MaxTextExtent,
3708 "text-align %s ",token);
3709 (void) WriteBlobString(image,message);
3712 if (LocaleCompare("text-anchor",keyword) == 0)
3714 GetMagickToken(q,&q,token);
3715 (void) FormatMagickString(message,MaxTextExtent,
3716 "text-anchor %s ",token);
3717 (void) WriteBlobString(image,message);
3726 if (LocaleCompare("image",keyword) == 0)
3728 GetMagickToken(q,&q,token);
3729 primitive_type=ImagePrimitive;
3738 if (LocaleCompare("line",keyword) == 0)
3740 primitive_type=LinePrimitive;
3749 if (LocaleCompare("matte",keyword) == 0)
3751 primitive_type=MattePrimitive;
3760 if (LocaleCompare("opacity",keyword) == 0)
3762 GetMagickToken(q,&q,token);
3763 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3765 (void) WriteBlobString(image,message);
3774 if (LocaleCompare("path",keyword) == 0)
3776 primitive_type=PathPrimitive;
3779 if (LocaleCompare("point",keyword) == 0)
3781 primitive_type=PointPrimitive;
3784 if (LocaleCompare("polyline",keyword) == 0)
3786 primitive_type=PolylinePrimitive;
3789 if (LocaleCompare("polygon",keyword) == 0)
3791 primitive_type=PolygonPrimitive;
3794 if (LocaleCompare("pop",keyword) == 0)
3796 GetMagickToken(q,&q,token);
3797 if (LocaleCompare("clip-path",token) == 0)
3799 (void) WriteBlobString(image,"</clipPath>\n");
3802 if (LocaleCompare("defs",token) == 0)
3804 (void) WriteBlobString(image,"</defs>\n");
3807 if (LocaleCompare("gradient",token) == 0)
3809 (void) FormatMagickString(message,MaxTextExtent,
3810 "</%sGradient>\n",type);
3811 (void) WriteBlobString(image,message);
3814 if (LocaleCompare("graphic-context",token) == 0)
3818 ThrowWriterException(DrawError,
3819 "UnbalancedGraphicContextPushPop");
3820 (void) WriteBlobString(image,"</g>\n");
3822 if (LocaleCompare("pattern",token) == 0)
3824 (void) WriteBlobString(image,"</pattern>\n");
3827 if (LocaleCompare("defs",token) == 0)
3828 (void) WriteBlobString(image,"</g>\n");
3831 if (LocaleCompare("push",keyword) == 0)
3833 GetMagickToken(q,&q,token);
3834 if (LocaleCompare("clip-path",token) == 0)
3836 GetMagickToken(q,&q,token);
3837 (void) FormatMagickString(message,MaxTextExtent,
3838 "<clipPath id=\"%s\">\n",token);
3839 (void) WriteBlobString(image,message);
3842 if (LocaleCompare("defs",token) == 0)
3844 (void) WriteBlobString(image,"<defs>\n");
3847 if (LocaleCompare("gradient",token) == 0)
3849 GetMagickToken(q,&q,token);
3850 (void) CopyMagickString(name,token,MaxTextExtent);
3851 GetMagickToken(q,&q,token);
3852 (void) CopyMagickString(type,token,MaxTextExtent);
3853 GetMagickToken(q,&q,token);
3854 svg_info.segment.x1=StringToDouble(token);
3855 svg_info.element.cx=StringToDouble(token);
3856 GetMagickToken(q,&q,token);
3858 GetMagickToken(q,&q,token);
3859 svg_info.segment.y1=StringToDouble(token);
3860 svg_info.element.cy=StringToDouble(token);
3861 GetMagickToken(q,&q,token);
3863 GetMagickToken(q,&q,token);
3864 svg_info.segment.x2=StringToDouble(token);
3865 svg_info.element.major=StringToDouble(token);
3866 GetMagickToken(q,&q,token);
3868 GetMagickToken(q,&q,token);
3869 svg_info.segment.y2=StringToDouble(token);
3870 svg_info.element.minor=StringToDouble(token);
3871 (void) FormatMagickString(message,MaxTextExtent,
3872 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3873 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3874 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3875 if (LocaleCompare(type,"radial") == 0)
3877 GetMagickToken(q,&q,token);
3879 GetMagickToken(q,&q,token);
3880 svg_info.element.angle=StringToDouble(token);
3881 (void) FormatMagickString(message,MaxTextExtent,
3882 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3883 "fx=\"%g\" fy=\"%g\">\n",type,name,
3884 svg_info.element.cx,svg_info.element.cy,
3885 svg_info.element.angle,svg_info.element.major,
3886 svg_info.element.minor);
3888 (void) WriteBlobString(image,message);
3891 if (LocaleCompare("graphic-context",token) == 0)
3896 AffineToTransform(image,&affine);
3899 (void) WriteBlobString(image,"<g style=\"");
3902 if (LocaleCompare("pattern",token) == 0)
3904 GetMagickToken(q,&q,token);
3905 (void) CopyMagickString(name,token,MaxTextExtent);
3906 GetMagickToken(q,&q,token);
3907 svg_info.bounds.x=StringToDouble(token);
3908 GetMagickToken(q,&q,token);
3910 GetMagickToken(q,&q,token);
3911 svg_info.bounds.y=StringToDouble(token);
3912 GetMagickToken(q,&q,token);
3914 GetMagickToken(q,&q,token);
3915 svg_info.bounds.width=StringToDouble(token);
3916 GetMagickToken(q,&q,token);
3918 GetMagickToken(q,&q,token);
3919 svg_info.bounds.height=StringToDouble(token);
3920 (void) FormatMagickString(message,MaxTextExtent,
3921 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3922 "height=\"%g\">\n",name,svg_info.bounds.x,
3923 svg_info.bounds.y,svg_info.bounds.width,
3924 svg_info.bounds.height);
3925 (void) WriteBlobString(image,message);
3936 if (LocaleCompare("rectangle",keyword) == 0)
3938 primitive_type=RectanglePrimitive;
3941 if (LocaleCompare("roundRectangle",keyword) == 0)
3943 primitive_type=RoundRectanglePrimitive;
3946 if (LocaleCompare("rotate",keyword) == 0)
3948 GetMagickToken(q,&q,token);
3949 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3951 (void) WriteBlobString(image,message);
3960 if (LocaleCompare("scale",keyword) == 0)
3962 GetMagickToken(q,&q,token);
3963 affine.sx=StringToDouble(token);
3964 GetMagickToken(q,&q,token);
3966 GetMagickToken(q,&q,token);
3967 affine.sy=StringToDouble(token);
3970 if (LocaleCompare("skewX",keyword) == 0)
3972 GetMagickToken(q,&q,token);
3973 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3975 (void) WriteBlobString(image,message);
3978 if (LocaleCompare("skewY",keyword) == 0)
3980 GetMagickToken(q,&q,token);
3981 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3983 (void) WriteBlobString(image,message);
3986 if (LocaleCompare("stop-color",keyword) == 0)
3989 color[MaxTextExtent];
3991 GetMagickToken(q,&q,token);
3992 (void) CopyMagickString(color,token,MaxTextExtent);
3993 GetMagickToken(q,&q,token);
3994 (void) FormatMagickString(message,MaxTextExtent,
3995 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3996 (void) WriteBlobString(image,message);
3999 if (LocaleCompare("stroke",keyword) == 0)
4001 GetMagickToken(q,&q,token);
4002 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
4004 (void) WriteBlobString(image,message);
4007 if (LocaleCompare("stroke-antialias",keyword) == 0)
4009 GetMagickToken(q,&q,token);
4010 (void) FormatMagickString(message,MaxTextExtent,
4011 "stroke-antialias:%s;",token);
4012 (void) WriteBlobString(image,message);
4015 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4023 GetMagickToken(p,&p,token);
4024 for (k=0; IsPoint(token); k++)
4025 GetMagickToken(p,&p,token);
4026 (void) WriteBlobString(image,"stroke-dasharray:");
4027 for (j=0; j < k; j++)
4029 GetMagickToken(q,&q,token);
4030 (void) FormatMagickString(message,MaxTextExtent,"%s ",
4032 (void) WriteBlobString(image,message);
4034 (void) WriteBlobString(image,";");
4037 GetMagickToken(q,&q,token);
4038 (void) FormatMagickString(message,MaxTextExtent,
4039 "stroke-dasharray:%s;",token);
4040 (void) WriteBlobString(image,message);
4043 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4045 GetMagickToken(q,&q,token);
4046 (void) FormatMagickString(message,MaxTextExtent,
4047 "stroke-dashoffset:%s;",token);
4048 (void) WriteBlobString(image,message);
4051 if (LocaleCompare("stroke-linecap",keyword) == 0)
4053 GetMagickToken(q,&q,token);
4054 (void) FormatMagickString(message,MaxTextExtent,
4055 "stroke-linecap:%s;",token);
4056 (void) WriteBlobString(image,message);
4059 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4061 GetMagickToken(q,&q,token);
4062 (void) FormatMagickString(message,MaxTextExtent,
4063 "stroke-linejoin:%s;",token);
4064 (void) WriteBlobString(image,message);
4067 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4069 GetMagickToken(q,&q,token);
4070 (void) FormatMagickString(message,MaxTextExtent,
4071 "stroke-miterlimit:%s;",token);
4072 (void) WriteBlobString(image,message);
4075 if (LocaleCompare("stroke-opacity",keyword) == 0)
4077 GetMagickToken(q,&q,token);
4078 (void) FormatMagickString(message,MaxTextExtent,
4079 "stroke-opacity:%s;",token);
4080 (void) WriteBlobString(image,message);
4083 if (LocaleCompare("stroke-width",keyword) == 0)
4085 GetMagickToken(q,&q,token);
4086 (void) FormatMagickString(message,MaxTextExtent,
4087 "stroke-width:%s;",token);
4088 (void) WriteBlobString(image,message);
4097 if (LocaleCompare("text",keyword) == 0)
4099 primitive_type=TextPrimitive;
4102 if (LocaleCompare("text-antialias",keyword) == 0)
4104 GetMagickToken(q,&q,token);
4105 (void) FormatMagickString(message,MaxTextExtent,
4106 "text-antialias:%s;",token);
4107 (void) WriteBlobString(image,message);
4110 if (LocaleCompare("tspan",keyword) == 0)
4112 primitive_type=TextPrimitive;
4115 if (LocaleCompare("translate",keyword) == 0)
4117 GetMagickToken(q,&q,token);
4118 affine.tx=StringToDouble(token);
4119 GetMagickToken(q,&q,token);
4121 GetMagickToken(q,&q,token);
4122 affine.ty=StringToDouble(token);
4131 if (LocaleCompare("viewbox",keyword) == 0)
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);
4141 GetMagickToken(q,&q,token);
4142 GetMagickToken(q,&q,token);
4154 if (status == MagickFalse)
4156 if (primitive_type == UndefinedPrimitive)
4159 Parse the primitive attributes.
4163 for (x=0; *q != '\0'; x++)
4168 if (IsPoint(q) == MagickFalse)
4170 GetMagickToken(q,&q,token);
4171 point.x=StringToDouble(token);
4172 GetMagickToken(q,&q,token);
4174 GetMagickToken(q,&q,token);
4175 point.y=StringToDouble(token);
4176 GetMagickToken(q,(const char **) NULL,token);
4178 GetMagickToken(q,&q,token);
4179 primitive_info[i].primitive=primitive_type;
4180 primitive_info[i].point=point;
4181 primitive_info[i].coordinates=0;
4182 primitive_info[i].method=FloodfillMethod;
4184 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4186 number_points+=6*BezierQuantum+360;
4187 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4188 number_points,sizeof(*primitive_info));
4189 if (primitive_info == (PrimitiveInfo *) NULL)
4191 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4192 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4196 primitive_info[j].primitive=primitive_type;
4197 primitive_info[j].coordinates=x;
4198 primitive_info[j].method=FloodfillMethod;
4199 primitive_info[j].text=(char *) NULL;
4202 AffineToTransform(image,&affine);
4206 switch (primitive_type)
4208 case PointPrimitive:
4211 if (primitive_info[j].coordinates != 1)
4220 if (primitive_info[j].coordinates != 2)
4225 (void) FormatMagickString(message,MaxTextExtent,
4226 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4227 primitive_info[j].point.x,primitive_info[j].point.y,
4228 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4229 (void) WriteBlobString(image,message);
4232 case RectanglePrimitive:
4234 if (primitive_info[j].coordinates != 2)
4239 (void) FormatMagickString(message,MaxTextExtent,
4240 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4241 primitive_info[j].point.x,primitive_info[j].point.y,
4242 primitive_info[j+1].point.x-primitive_info[j].point.x,
4243 primitive_info[j+1].point.y-primitive_info[j].point.y);
4244 (void) WriteBlobString(image,message);
4247 case RoundRectanglePrimitive:
4249 if (primitive_info[j].coordinates != 3)
4254 (void) FormatMagickString(message,MaxTextExtent,
4255 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4256 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4257 primitive_info[j].point.y,primitive_info[j+1].point.x-
4258 primitive_info[j].point.x,primitive_info[j+1].point.y-
4259 primitive_info[j].point.y,primitive_info[j+2].point.x,
4260 primitive_info[j+2].point.y);
4261 (void) WriteBlobString(image,message);
4266 if (primitive_info[j].coordinates != 3)
4273 case EllipsePrimitive:
4275 if (primitive_info[j].coordinates != 3)
4280 (void) FormatMagickString(message,MaxTextExtent,
4281 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4282 primitive_info[j].point.x,primitive_info[j].point.y,
4283 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4284 (void) WriteBlobString(image,message);
4287 case CirclePrimitive:
4293 if (primitive_info[j].coordinates != 2)
4298 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4299 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4300 (void) FormatMagickString(message,MaxTextExtent,
4301 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4302 primitive_info[j].point.x,primitive_info[j].point.y,
4304 (void) WriteBlobString(image,message);
4307 case PolylinePrimitive:
4309 if (primitive_info[j].coordinates < 2)
4314 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4315 (void) WriteBlobString(image,message);
4316 length=strlen(message);
4319 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4320 primitive_info[j].point.x,primitive_info[j].point.y);
4321 length+=strlen(message);
4324 (void) WriteBlobString(image,"\n ");
4325 length=strlen(message)+5;
4327 (void) WriteBlobString(image,message);
4329 (void) WriteBlobString(image,"\"/>\n");
4332 case PolygonPrimitive:
4334 if (primitive_info[j].coordinates < 3)
4339 primitive_info[i]=primitive_info[j];
4340 primitive_info[i].coordinates=0;
4341 primitive_info[j].coordinates++;
4343 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4344 (void) WriteBlobString(image,message);
4345 length=strlen(message);
4348 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4349 primitive_info[j].point.x,primitive_info[j].point.y);
4350 length+=strlen(message);
4353 (void) WriteBlobString(image,"\n ");
4354 length=strlen(message)+5;
4356 (void) WriteBlobString(image,message);
4358 (void) WriteBlobString(image,"\"/>\n");
4361 case BezierPrimitive:
4363 if (primitive_info[j].coordinates < 3)
4375 GetMagickToken(q,&q,token);
4376 number_attributes=1;
4377 for (p=token; *p != '\0'; p++)
4378 if (isalpha((int) *p))
4379 number_attributes++;
4380 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4382 number_points+=6*BezierQuantum*number_attributes;
4383 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4384 number_points,sizeof(*primitive_info));
4385 if (primitive_info == (PrimitiveInfo *) NULL)
4387 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4388 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4393 (void) WriteBlobString(image," <path d=\"");
4394 (void) WriteBlobString(image,token);
4395 (void) WriteBlobString(image,"\"/>\n");
4398 case ColorPrimitive:
4399 case MattePrimitive:
4401 if (primitive_info[j].coordinates != 1)
4406 GetMagickToken(q,&q,token);
4407 if (LocaleCompare("point",token) == 0)
4408 primitive_info[j].method=PointMethod;
4409 if (LocaleCompare("replace",token) == 0)
4410 primitive_info[j].method=ReplaceMethod;
4411 if (LocaleCompare("floodfill",token) == 0)
4412 primitive_info[j].method=FloodfillMethod;
4413 if (LocaleCompare("filltoborder",token) == 0)
4414 primitive_info[j].method=FillToBorderMethod;
4415 if (LocaleCompare("reset",token) == 0)
4416 primitive_info[j].method=ResetMethod;
4424 if (primitive_info[j].coordinates != 1)
4429 GetMagickToken(q,&q,token);
4430 (void) FormatMagickString(message,MaxTextExtent,
4431 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4432 primitive_info[j].point.y);
4433 (void) WriteBlobString(image,message);
4434 for (p=token; *p != '\0'; p++)
4437 case '<': (void) WriteBlobString(image,"<"); break;
4438 case '>': (void) WriteBlobString(image,">"); break;
4439 case '&': (void) WriteBlobString(image,"&"); break;
4440 default: (void) WriteBlobByte(image,*p); break;
4442 (void) WriteBlobString(image,"</text>\n");
4445 case ImagePrimitive:
4447 if (primitive_info[j].coordinates != 2)
4452 GetMagickToken(q,&q,token);
4453 (void) FormatMagickString(message,MaxTextExtent,
4454 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4455 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4456 primitive_info[j].point.y,primitive_info[j+1].point.x,
4457 primitive_info[j+1].point.y,token);
4458 (void) WriteBlobString(image,message);
4462 if (primitive_info == (PrimitiveInfo *) NULL)
4464 primitive_info[i].primitive=UndefinedPrimitive;
4465 if (status == MagickFalse)
4468 (void) WriteBlobString(image,"</svg>\n");
4470 Relinquish resources.
4472 token=DestroyString(token);
4473 if (primitive_info != (PrimitiveInfo *) NULL)
4474 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4475 (void) CloseBlob(image);