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 "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/draw.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/gem.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/log.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/quantum-private.h"
66 #include "MagickCore/pixel-accessor.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/string_.h"
71 #include "MagickCore/string-private.h"
72 #include "MagickCore/token.h"
73 #include "MagickCore/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"
101 Typedef declarations.
103 typedef struct _BoundingBox
112 typedef struct _ElementInfo
122 typedef struct _SVGInfo
176 #if defined(MAGICKCORE_XML_DELEGATE)
186 Forward declarations.
188 static MagickBooleanType
189 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 % IsSVG()() returns MagickTrue if the image format type, identified by the
203 % magick string, is SVG.
205 % The format of the IsSVG method is:
207 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
209 % A description of each parameter follows:
211 % o magick: compare image format pattern against these bytes.
213 % o length: Specifies the length of the magick string.
216 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
220 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
225 #if defined(MAGICKCORE_XML_DELEGATE)
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 % R e a d S V G I m a g e %
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
238 % allocates the memory necessary for the new Image structure and returns a
239 % pointer to the new image.
241 % The format of the ReadSVGImage method is:
243 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
245 % A description of each parameter follows:
247 % o image_info: the image info.
249 % o exception: return any errors or warnings in this structure.
253 static SVGInfo *AcquireSVGInfo(void)
258 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
259 if (svg_info == (SVGInfo *) NULL)
260 return((SVGInfo *) NULL);
261 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
262 svg_info->text=AcquireString("");
263 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
264 if (svg_info->scale == (double *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 GetAffineMatrix(&svg_info->affine);
267 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
271 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
273 if (svg_info->text != (char *) NULL)
274 svg_info->text=DestroyString(svg_info->text);
275 if (svg_info->scale != (double *) NULL)
276 svg_info->scale=(double *) (svg_info->scale);
277 if (svg_info->title != (char *) NULL)
278 svg_info->title=DestroyString(svg_info->title);
279 if (svg_info->comment != (char *) NULL)
280 svg_info->comment=DestroyString(svg_info->comment);
281 return((SVGInfo *) RelinquishMagickMemory(svg_info));
284 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
288 token[MaxTextExtent];
296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
297 assert(string != (const char *) NULL);
298 p=(const char *) string;
299 GetMagickToken(p,&p,token);
300 value=StringToDouble(token,(char **) NULL);
301 if (strchr(token,'%') != (char *) NULL)
309 if (svg_info->view_box.width == 0.0)
311 return(svg_info->view_box.width*value/100.0);
315 if (svg_info->view_box.height == 0.0)
317 return(svg_info->view_box.height*value/100.0);
319 alpha=value-svg_info->view_box.width;
320 beta=value-svg_info->view_box.height;
321 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
323 GetMagickToken(p,&p,token);
324 if (LocaleNCompare(token,"cm",2) == 0)
325 return(DefaultResolution*svg_info->scale[0]/2.54*value);
326 if (LocaleNCompare(token,"em",2) == 0)
327 return(svg_info->pointsize*value);
328 if (LocaleNCompare(token,"ex",2) == 0)
329 return(svg_info->pointsize*value/2.0);
330 if (LocaleNCompare(token,"in",2) == 0)
331 return(DefaultResolution*svg_info->scale[0]*value);
332 if (LocaleNCompare(token,"mm",2) == 0)
333 return(DefaultResolution*svg_info->scale[0]/25.4*value);
334 if (LocaleNCompare(token,"pc",2) == 0)
335 return(DefaultResolution*svg_info->scale[0]/6.0*value);
336 if (LocaleNCompare(token,"pt",2) == 0)
337 return(svg_info->scale[0]*value);
338 if (LocaleNCompare(token,"px",2) == 0)
343 static void StripStyleTokens(char *message)
352 assert(message != (char *) NULL);
353 if (*message == '\0')
355 length=strlen(message);
357 while (isspace((int) ((unsigned char) *p)) != 0)
360 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
362 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
364 StripString(message);
367 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
379 svg_info=(SVGInfo *) context;
382 if (style == (const char *) NULL)
383 return((char **) NULL);
384 text=AcquireString(style);
385 (void) SubstituteString(&text,":","\n");
386 (void) SubstituteString(&text,";","\n");
387 tokens=StringToList(text);
388 text=DestroyString(text);
389 for (i=0; tokens[i] != (char *) NULL; i++)
390 StripStyleTokens(tokens[i]);
395 static char **GetTransformTokens(void *context,const char *text,
411 svg_info=(SVGInfo *) context;
413 if (text == (const char *) NULL)
414 return((char **) NULL);
416 Determine the number of arguments.
418 for (p=text; *p != '\0'; p++)
423 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
424 if (tokens == (char **) NULL)
426 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
427 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
428 return((char **) NULL);
431 Convert string to an ASCII list.
435 for (q=p; *q != '\0'; q++)
437 if ((*q != '(') && (*q != ')') && (*q != '\0'))
439 tokens[i]=AcquireString(p);
440 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
441 StripString(tokens[i++]);
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
447 tokens[i]=(char *) NULL;
451 #if defined(__cplusplus) || defined(c_plusplus)
455 static int SVGIsStandalone(void *context)
461 Is this document tagged standalone?
463 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
464 svg_info=(SVGInfo *) context;
465 return(svg_info->document->standalone == 1);
468 static int SVGHasInternalSubset(void *context)
474 Does this document has an internal subset?
476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
477 " SAX.SVGHasInternalSubset()");
478 svg_info=(SVGInfo *) context;
479 return(svg_info->document->intSubset != NULL);
482 static int SVGHasExternalSubset(void *context)
488 Does this document has an external subset?
490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
491 " SAX.SVGHasExternalSubset()");
492 svg_info=(SVGInfo *) context;
493 return(svg_info->document->extSubset != NULL);
496 static void SVGInternalSubset(void *context,const xmlChar *name,
497 const xmlChar *external_id,const xmlChar *system_id)
503 Does this document has an internal subset?
505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
506 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
507 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
508 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
509 svg_info=(SVGInfo *) context;
510 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
513 static xmlParserInputPtr SVGResolveEntity(void *context,
514 const xmlChar *public_id,const xmlChar *system_id)
523 Special entity resolver, better left to the parser, it has more
524 context than the application layer. The default behaviour is to
525 not resolve the entities, in that case the ENTITY_REF nodes are
526 built in the structure (and the parameter values).
528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
529 " SAX.resolveEntity(%s, %s)",
530 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
531 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
532 svg_info=(SVGInfo *) context;
533 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
534 public_id,svg_info->parser);
538 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
544 Get an entity by name.
546 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
548 svg_info=(SVGInfo *) context;
549 return(xmlGetDocEntity(svg_info->document,name));
552 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
558 Get a parameter entity by name.
560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
561 " SAX.getParameterEntity(%s)",name);
562 svg_info=(SVGInfo *) context;
563 return(xmlGetParameterEntity(svg_info->document,name));
566 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
567 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
573 An entity definition has been parsed.
575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
576 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
577 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
578 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
579 svg_info=(SVGInfo *) context;
580 if (svg_info->parser->inSubset == 1)
581 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
584 if (svg_info->parser->inSubset == 2)
585 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
589 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
590 const xmlChar *name,int type,int value,const xmlChar *default_value,
591 xmlEnumerationPtr tree)
604 An attribute definition has been parsed.
606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
607 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
609 svg_info=(SVGInfo *) context;
610 fullname=(xmlChar *) NULL;
611 prefix=(xmlChar *) NULL;
612 parser=svg_info->parser;
613 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
614 if (parser->inSubset == 1)
615 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
616 element,fullname,prefix,(xmlAttributeType) type,
617 (xmlAttributeDefault) value,default_value,tree);
619 if (parser->inSubset == 2)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
623 if (prefix != (xmlChar *) NULL)
625 if (fullname != (xmlChar *) NULL)
629 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
630 xmlElementContentPtr content)
639 An element definition has been parsed.
641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
642 " SAX.elementDecl(%s, %d, ...)",name,type);
643 svg_info=(SVGInfo *) context;
644 parser=svg_info->parser;
645 if (parser->inSubset == 1)
646 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
647 name,(xmlElementTypeVal) type,content);
649 if (parser->inSubset == 2)
650 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
651 name,(xmlElementTypeVal) type,content);
654 static void SVGNotationDeclaration(void *context,const xmlChar *name,
655 const xmlChar *public_id,const xmlChar *system_id)
664 What to do when a notation declaration has been parsed.
666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
667 " SAX.notationDecl(%s, %s, %s)",name,
668 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
669 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
670 svg_info=(SVGInfo *) context;
671 parser=svg_info->parser;
672 if (parser->inSubset == 1)
673 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
674 name,public_id,system_id);
676 if (parser->inSubset == 2)
677 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
678 name,public_id,system_id);
681 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
682 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
688 What to do when an unparsed entity declaration is parsed.
690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
691 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
692 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
693 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
694 svg_info=(SVGInfo *) context;
695 (void) xmlAddDocEntity(svg_info->document,name,
696 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
700 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
706 Receive the document locator at startup, actually xmlDefaultSAXLocator.
709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
710 " SAX.setDocumentLocator()");
711 svg_info=(SVGInfo *) context;
715 static void SVGStartDocument(void *context)
724 Called when the document start being processed.
726 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
727 svg_info=(SVGInfo *) context;
728 GetExceptionInfo(svg_info->exception);
729 parser=svg_info->parser;
730 svg_info->document=xmlNewDoc(parser->version);
731 if (svg_info->document == (xmlDocPtr) NULL)
733 if (parser->encoding == NULL)
734 svg_info->document->encoding=(const xmlChar *) NULL;
736 svg_info->document->encoding=xmlStrdup(parser->encoding);
737 svg_info->document->standalone=parser->standalone;
740 static void SVGEndDocument(void *context)
746 Called when the document end has been detected.
748 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
749 svg_info=(SVGInfo *) context;
750 if (svg_info->offset != (char *) NULL)
751 svg_info->offset=DestroyString(svg_info->offset);
752 if (svg_info->stop_color != (char *) NULL)
753 svg_info->stop_color=DestroyString(svg_info->stop_color);
754 if (svg_info->scale != (double *) NULL)
755 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
756 if (svg_info->text != (char *) NULL)
757 svg_info->text=DestroyString(svg_info->text);
758 if (svg_info->vertices != (char *) NULL)
759 svg_info->vertices=DestroyString(svg_info->vertices);
760 if (svg_info->url != (char *) NULL)
761 svg_info->url=DestroyString(svg_info->url);
762 #if defined(MAGICKCORE_XML_DELEGATE)
763 if (svg_info->document != (xmlDocPtr) NULL)
765 xmlFreeDoc(svg_info->document);
766 svg_info->document=(xmlDocPtr) NULL;
771 static void SVGStartElement(void *context,const xmlChar *name,
772 const xmlChar **attributes)
777 token[MaxTextExtent],
797 Called when an opening tag has been processed.
799 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
801 svg_info=(SVGInfo *) context;
803 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
804 svg_info->n+1UL,sizeof(*svg_info->scale));
805 if (svg_info->scale == (double *) NULL)
807 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
808 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
811 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
812 color=AcquireString("none");
813 units=AcquireString("userSpaceOnUse");
814 value=(const char *) NULL;
815 if (attributes != (const xmlChar **) NULL)
816 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
818 keyword=(const char *) attributes[i];
819 value=(const char *) attributes[i+1];
825 if (LocaleCompare(keyword,"cx") == 0)
827 svg_info->element.cx=
828 GetUserSpaceCoordinateValue(svg_info,1,value);
831 if (LocaleCompare(keyword,"cy") == 0)
833 svg_info->element.cy=
834 GetUserSpaceCoordinateValue(svg_info,-1,value);
842 if (LocaleCompare(keyword,"fx") == 0)
844 svg_info->element.major=
845 GetUserSpaceCoordinateValue(svg_info,1,value);
848 if (LocaleCompare(keyword,"fy") == 0)
850 svg_info->element.minor=
851 GetUserSpaceCoordinateValue(svg_info,-1,value);
859 if (LocaleCompare(keyword,"height") == 0)
861 svg_info->bounds.height=
862 GetUserSpaceCoordinateValue(svg_info,-1,value);
870 if (LocaleCompare(keyword,"id") == 0)
872 (void) CopyMagickString(id,value,MaxTextExtent);
880 if (LocaleCompare(keyword,"r") == 0)
882 svg_info->element.angle=
883 GetUserSpaceCoordinateValue(svg_info,0,value);
891 if (LocaleCompare(keyword,"width") == 0)
893 svg_info->bounds.width=
894 GetUserSpaceCoordinateValue(svg_info,1,value);
902 if (LocaleCompare(keyword,"x") == 0)
904 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
908 if (LocaleCompare(keyword,"x1") == 0)
910 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
914 if (LocaleCompare(keyword,"x2") == 0)
916 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
925 if (LocaleCompare(keyword,"y") == 0)
927 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
931 if (LocaleCompare(keyword,"y1") == 0)
933 svg_info->segment.y1=
934 GetUserSpaceCoordinateValue(svg_info,-1,value);
937 if (LocaleCompare(keyword,"y2") == 0)
939 svg_info->segment.y2=
940 GetUserSpaceCoordinateValue(svg_info,-1,value);
949 if (strchr((char *) name,':') != (char *) NULL)
954 for ( ; *name != ':'; name++) ;
962 if (LocaleCompare((const char *) name,"circle") == 0)
964 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
967 if (LocaleCompare((const char *) name,"clipPath") == 0)
969 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
977 if (LocaleCompare((const char *) name,"defs") == 0)
979 (void) FormatLocaleFile(svg_info->file,"push defs\n");
987 if (LocaleCompare((const char *) name,"ellipse") == 0)
989 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
997 if (LocaleCompare((const char *) name,"g") == 0)
999 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1007 if (LocaleCompare((const char *) name,"image") == 0)
1009 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1017 if (LocaleCompare((const char *) name,"line") == 0)
1019 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1024 (void) FormatLocaleFile(svg_info->file,
1025 "push gradient '%s' linear %g,%g %g,%g\n",id,
1026 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1027 svg_info->segment.y2);
1035 if (LocaleCompare((const char *) name,"path") == 0)
1037 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1040 if (LocaleCompare((const char *) name,"pattern") == 0)
1042 (void) FormatLocaleFile(svg_info->file,
1043 "push pattern '%s' %g,%g %g,%g\n",id,
1044 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1045 svg_info->bounds.height);
1048 if (LocaleCompare((const char *) name,"polygon") == 0)
1050 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1053 if (LocaleCompare((const char *) name,"polyline") == 0)
1055 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1063 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1065 (void) FormatLocaleFile(svg_info->file,
1066 "push gradient '%s' radial %g,%g %g,%g %g\n",
1067 id,svg_info->element.cx,svg_info->element.cy,
1068 svg_info->element.major,svg_info->element.minor,
1069 svg_info->element.angle);
1072 if (LocaleCompare((const char *) name,"rect") == 0)
1074 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1082 if (LocaleCompare((const char *) name,"svg") == 0)
1084 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1092 if (LocaleCompare((const char *) name,"text") == 0)
1094 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1097 if (LocaleCompare((const char *) name,"tspan") == 0)
1099 if (*svg_info->text != '\0')
1110 text=EscapeString(svg_info->text,'\'');
1111 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1112 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1113 svg_info->center.y,text);
1114 text=DestroyString(text);
1115 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1116 draw_info->pointsize=svg_info->pointsize;
1117 draw_info->text=AcquireString(svg_info->text);
1118 (void) ConcatenateString(&draw_info->text," ");
1119 (void) GetTypeMetrics(svg_info->image,draw_info,
1120 &metrics,svg_info->exception);
1121 svg_info->bounds.x+=metrics.width;
1122 draw_info=DestroyDrawInfo(draw_info);
1123 *svg_info->text='\0';
1125 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1133 if (attributes != (const xmlChar **) NULL)
1134 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1136 keyword=(const char *) attributes[i];
1137 value=(const char *) attributes[i+1];
1138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1139 " %s = %s",keyword,value);
1145 if (LocaleCompare(keyword,"angle") == 0)
1147 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1148 GetUserSpaceCoordinateValue(svg_info,0,value));
1156 if (LocaleCompare(keyword,"clip-path") == 0)
1158 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1161 if (LocaleCompare(keyword,"clip-rule") == 0)
1163 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1166 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1168 (void) CloneString(&units,value);
1169 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1172 if (LocaleCompare(keyword,"color") == 0)
1174 (void) CloneString(&color,value);
1177 if (LocaleCompare(keyword,"cx") == 0)
1179 svg_info->element.cx=
1180 GetUserSpaceCoordinateValue(svg_info,1,value);
1183 if (LocaleCompare(keyword,"cy") == 0)
1185 svg_info->element.cy=
1186 GetUserSpaceCoordinateValue(svg_info,-1,value);
1194 if (LocaleCompare(keyword,"d") == 0)
1196 (void) CloneString(&svg_info->vertices,value);
1199 if (LocaleCompare(keyword,"dx") == 0)
1201 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1204 if (LocaleCompare(keyword,"dy") == 0)
1206 svg_info->bounds.y+=
1207 GetUserSpaceCoordinateValue(svg_info,-1,value);
1215 if (LocaleCompare(keyword,"fill") == 0)
1217 if (LocaleCompare(value,"currentColor") == 0)
1219 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1222 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1225 if (LocaleCompare(keyword,"fillcolor") == 0)
1227 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1230 if (LocaleCompare(keyword,"fill-rule") == 0)
1232 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1235 if (LocaleCompare(keyword,"fill-opacity") == 0)
1237 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1241 if (LocaleCompare(keyword,"font-family") == 0)
1243 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1247 if (LocaleCompare(keyword,"font-stretch") == 0)
1249 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1253 if (LocaleCompare(keyword,"font-style") == 0)
1255 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1258 if (LocaleCompare(keyword,"font-size") == 0)
1260 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1261 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1262 svg_info->pointsize);
1265 if (LocaleCompare(keyword,"font-weight") == 0)
1267 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1276 if (LocaleCompare(keyword,"gradientTransform") == 0)
1283 GetAffineMatrix(&transform);
1284 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1285 tokens=GetTransformTokens(context,value,&number_tokens);
1286 for (j=0; j < (number_tokens-1); j+=2)
1288 keyword=(char *) tokens[j];
1289 if (keyword == (char *) NULL)
1291 value=(char *) tokens[j+1];
1292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1293 " %s: %s",keyword,value);
1295 GetAffineMatrix(&affine);
1301 if (LocaleCompare(keyword,"matrix") == 0)
1303 p=(const char *) value;
1304 GetMagickToken(p,&p,token);
1305 affine.sx=StringToDouble(value,(char **) NULL);
1306 GetMagickToken(p,&p,token);
1308 GetMagickToken(p,&p,token);
1309 affine.rx=StringToDouble(token,(char **) NULL);
1310 GetMagickToken(p,&p,token);
1312 GetMagickToken(p,&p,token);
1313 affine.ry=StringToDouble(token,(char **) NULL);
1314 GetMagickToken(p,&p,token);
1316 GetMagickToken(p,&p,token);
1317 affine.sy=StringToDouble(token,(char **) NULL);
1318 GetMagickToken(p,&p,token);
1320 GetMagickToken(p,&p,token);
1321 affine.tx=StringToDouble(token,(char **) NULL);
1322 GetMagickToken(p,&p,token);
1324 GetMagickToken(p,&p,token);
1325 affine.ty=StringToDouble(token,(char **) NULL);
1333 if (LocaleCompare(keyword,"rotate") == 0)
1338 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1339 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1340 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1341 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1342 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1350 if (LocaleCompare(keyword,"scale") == 0)
1352 for (p=(const char *) value; *p != '\0'; p++)
1353 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1356 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1357 affine.sy=affine.sx;
1360 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1361 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1364 if (LocaleCompare(keyword,"skewX") == 0)
1366 affine.sx=svg_info->affine.sx;
1367 affine.ry=tan(DegreesToRadians(fmod(
1368 GetUserSpaceCoordinateValue(svg_info,1,value),
1370 affine.sy=svg_info->affine.sy;
1373 if (LocaleCompare(keyword,"skewY") == 0)
1375 affine.sx=svg_info->affine.sx;
1376 affine.rx=tan(DegreesToRadians(fmod(
1377 GetUserSpaceCoordinateValue(svg_info,-1,value),
1379 affine.sy=svg_info->affine.sy;
1387 if (LocaleCompare(keyword,"translate") == 0)
1389 for (p=(const char *) value; *p != '\0'; p++)
1390 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1393 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1394 affine.ty=affine.tx;
1397 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1405 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1406 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1407 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1408 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1409 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1411 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1414 (void) FormatLocaleFile(svg_info->file,
1415 "affine %g %g %g %g %g %g\n",transform.sx,
1416 transform.rx,transform.ry,transform.sy,transform.tx,
1418 for (j=0; tokens[j] != (char *) NULL; j++)
1419 tokens[j]=DestroyString(tokens[j]);
1420 tokens=(char **) RelinquishMagickMemory(tokens);
1423 if (LocaleCompare(keyword,"gradientUnits") == 0)
1425 (void) CloneString(&units,value);
1426 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1435 if (LocaleCompare(keyword,"height") == 0)
1437 svg_info->bounds.height=
1438 GetUserSpaceCoordinateValue(svg_info,-1,value);
1441 if (LocaleCompare(keyword,"href") == 0)
1443 (void) CloneString(&svg_info->url,value);
1451 if (LocaleCompare(keyword,"major") == 0)
1453 svg_info->element.major=
1454 GetUserSpaceCoordinateValue(svg_info,1,value);
1457 if (LocaleCompare(keyword,"minor") == 0)
1459 svg_info->element.minor=
1460 GetUserSpaceCoordinateValue(svg_info,-1,value);
1468 if (LocaleCompare(keyword,"offset") == 0)
1470 (void) CloneString(&svg_info->offset,value);
1473 if (LocaleCompare(keyword,"opacity") == 0)
1475 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1483 if (LocaleCompare(keyword,"path") == 0)
1485 (void) CloneString(&svg_info->url,value);
1488 if (LocaleCompare(keyword,"points") == 0)
1490 (void) CloneString(&svg_info->vertices,value);
1498 if (LocaleCompare(keyword,"r") == 0)
1500 svg_info->element.major=
1501 GetUserSpaceCoordinateValue(svg_info,1,value);
1502 svg_info->element.minor=
1503 GetUserSpaceCoordinateValue(svg_info,-1,value);
1506 if (LocaleCompare(keyword,"rotate") == 0)
1511 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1512 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1513 svg_info->bounds.x,svg_info->bounds.y);
1514 svg_info->bounds.x=0;
1515 svg_info->bounds.y=0;
1516 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1519 if (LocaleCompare(keyword,"rx") == 0)
1521 if (LocaleCompare((const char *) name,"ellipse") == 0)
1522 svg_info->element.major=
1523 GetUserSpaceCoordinateValue(svg_info,1,value);
1526 GetUserSpaceCoordinateValue(svg_info,1,value);
1529 if (LocaleCompare(keyword,"ry") == 0)
1531 if (LocaleCompare((const char *) name,"ellipse") == 0)
1532 svg_info->element.minor=
1533 GetUserSpaceCoordinateValue(svg_info,-1,value);
1536 GetUserSpaceCoordinateValue(svg_info,-1,value);
1544 if (LocaleCompare(keyword,"stop-color") == 0)
1546 (void) CloneString(&svg_info->stop_color,value);
1549 if (LocaleCompare(keyword,"stroke") == 0)
1551 if (LocaleCompare(value,"currentColor") == 0)
1553 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1556 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1559 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1561 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1562 LocaleCompare(value,"true") == 0);
1565 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1567 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1571 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1573 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1577 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1579 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1583 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1585 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1589 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1591 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1595 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1597 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1601 if (LocaleCompare(keyword,"stroke-width") == 0)
1603 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1604 GetUserSpaceCoordinateValue(svg_info,1,value));
1607 if (LocaleCompare(keyword,"style") == 0)
1609 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1610 tokens=GetStyleTokens(context,value,&number_tokens);
1611 for (j=0; j < (number_tokens-1); j+=2)
1613 keyword=(char *) tokens[j];
1614 value=(char *) tokens[j+1];
1615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1616 " %s: %s",keyword,value);
1622 if (LocaleCompare(keyword,"clip-path") == 0)
1624 (void) FormatLocaleFile(svg_info->file,
1625 "clip-path '%s'\n",value);
1628 if (LocaleCompare(keyword,"clip-rule") == 0)
1630 (void) FormatLocaleFile(svg_info->file,
1631 "clip-rule '%s'\n",value);
1634 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1636 (void) CloneString(&units,value);
1637 (void) FormatLocaleFile(svg_info->file,
1638 "clip-units '%s'\n",value);
1641 if (LocaleCompare(keyword,"color") == 0)
1643 (void) CloneString(&color,value);
1651 if (LocaleCompare(keyword,"fill") == 0)
1653 if (LocaleCompare(value,"currentColor") == 0)
1655 (void) FormatLocaleFile(svg_info->file,
1656 "fill '%s'\n",color);
1659 if (LocaleCompare(value,"#00000000") == 0)
1660 (void) FormatLocaleFile(svg_info->file,
1661 "fill '#000000'\n");
1663 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1667 if (LocaleCompare(keyword,"fillcolor") == 0)
1669 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1673 if (LocaleCompare(keyword,"fill-rule") == 0)
1675 (void) FormatLocaleFile(svg_info->file,
1676 "fill-rule '%s'\n",value);
1679 if (LocaleCompare(keyword,"fill-opacity") == 0)
1681 (void) FormatLocaleFile(svg_info->file,
1682 "fill-opacity '%s'\n",value);
1685 if (LocaleCompare(keyword,"font-family") == 0)
1687 (void) FormatLocaleFile(svg_info->file,
1688 "font-family '%s'\n",value);
1691 if (LocaleCompare(keyword,"font-stretch") == 0)
1693 (void) FormatLocaleFile(svg_info->file,
1694 "font-stretch '%s'\n",value);
1697 if (LocaleCompare(keyword,"font-style") == 0)
1699 (void) FormatLocaleFile(svg_info->file,
1700 "font-style '%s'\n",value);
1703 if (LocaleCompare(keyword,"font-size") == 0)
1705 svg_info->pointsize=GetUserSpaceCoordinateValue(
1707 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1708 svg_info->pointsize);
1711 if (LocaleCompare(keyword,"font-weight") == 0)
1713 (void) FormatLocaleFile(svg_info->file,
1714 "font-weight '%s'\n",value);
1722 if (LocaleCompare(keyword,"offset") == 0)
1724 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1725 GetUserSpaceCoordinateValue(svg_info,1,value));
1728 if (LocaleCompare(keyword,"opacity") == 0)
1730 (void) FormatLocaleFile(svg_info->file,
1731 "opacity '%s'\n",value);
1739 if (LocaleCompare(keyword,"stop-color") == 0)
1741 (void) CloneString(&svg_info->stop_color,value);
1744 if (LocaleCompare(keyword,"stroke") == 0)
1746 if (LocaleCompare(value,"currentColor") == 0)
1748 (void) FormatLocaleFile(svg_info->file,
1749 "stroke '%s'\n",color);
1752 if (LocaleCompare(value,"#00000000") == 0)
1753 (void) FormatLocaleFile(svg_info->file,
1754 "fill '#000000'\n");
1756 (void) FormatLocaleFile(svg_info->file,
1757 "stroke '%s'\n",value);
1760 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1762 (void) FormatLocaleFile(svg_info->file,
1763 "stroke-antialias %d\n",
1764 LocaleCompare(value,"true") == 0);
1767 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1769 (void) FormatLocaleFile(svg_info->file,
1770 "stroke-dasharray %s\n",value);
1773 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1775 (void) FormatLocaleFile(svg_info->file,
1776 "stroke-dashoffset %s\n",
1780 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1782 (void) FormatLocaleFile(svg_info->file,
1783 "stroke-linecap '%s'\n",value);
1786 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1788 (void) FormatLocaleFile(svg_info->file,
1789 "stroke-linejoin '%s'\n",
1793 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1795 (void) FormatLocaleFile(svg_info->file,
1796 "stroke-miterlimit '%s'\n",
1800 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1802 (void) FormatLocaleFile(svg_info->file,
1803 "stroke-opacity '%s'\n",value);
1806 if (LocaleCompare(keyword,"stroke-width") == 0)
1808 (void) FormatLocaleFile(svg_info->file,
1809 "stroke-width %g\n",
1810 GetUserSpaceCoordinateValue(svg_info,1,value));
1818 if (LocaleCompare(keyword,"text-align") == 0)
1820 (void) FormatLocaleFile(svg_info->file,
1821 "text-align '%s'\n",value);
1824 if (LocaleCompare(keyword,"text-anchor") == 0)
1826 (void) FormatLocaleFile(svg_info->file,
1827 "text-anchor '%s'\n",value);
1830 if (LocaleCompare(keyword,"text-decoration") == 0)
1832 if (LocaleCompare(value,"underline") == 0)
1833 (void) FormatLocaleFile(svg_info->file,
1834 "decorate underline\n");
1835 if (LocaleCompare(value,"line-through") == 0)
1836 (void) FormatLocaleFile(svg_info->file,
1837 "decorate line-through\n");
1838 if (LocaleCompare(value,"overline") == 0)
1839 (void) FormatLocaleFile(svg_info->file,
1840 "decorate overline\n");
1843 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1845 (void) FormatLocaleFile(svg_info->file,
1846 "text-antialias %d\n",
1847 LocaleCompare(value,"true") == 0);
1856 for (j=0; tokens[j] != (char *) NULL; j++)
1857 tokens[j]=DestroyString(tokens[j]);
1858 tokens=(char **) RelinquishMagickMemory(tokens);
1866 if (LocaleCompare(keyword,"text-align") == 0)
1868 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1872 if (LocaleCompare(keyword,"text-anchor") == 0)
1874 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1878 if (LocaleCompare(keyword,"text-decoration") == 0)
1880 if (LocaleCompare(value,"underline") == 0)
1881 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1882 if (LocaleCompare(value,"line-through") == 0)
1883 (void) FormatLocaleFile(svg_info->file,
1884 "decorate line-through\n");
1885 if (LocaleCompare(value,"overline") == 0)
1886 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1889 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1891 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1892 LocaleCompare(value,"true") == 0);
1895 if (LocaleCompare(keyword,"transform") == 0)
1902 GetAffineMatrix(&transform);
1903 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1904 tokens=GetTransformTokens(context,value,&number_tokens);
1905 for (j=0; j < (number_tokens-1); j+=2)
1907 keyword=(char *) tokens[j];
1908 value=(char *) tokens[j+1];
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1910 " %s: %s",keyword,value);
1912 GetAffineMatrix(&affine);
1918 if (LocaleCompare(keyword,"matrix") == 0)
1920 p=(const char *) value;
1921 GetMagickToken(p,&p,token);
1922 affine.sx=StringToDouble(value,(char **) NULL);
1923 GetMagickToken(p,&p,token);
1925 GetMagickToken(p,&p,token);
1926 affine.rx=StringToDouble(token,(char **) NULL);
1927 GetMagickToken(p,&p,token);
1929 GetMagickToken(p,&p,token);
1930 affine.ry=StringToDouble(token,(char **) NULL);
1931 GetMagickToken(p,&p,token);
1933 GetMagickToken(p,&p,token);
1934 affine.sy=StringToDouble(token,(char **) NULL);
1935 GetMagickToken(p,&p,token);
1937 GetMagickToken(p,&p,token);
1938 affine.tx=StringToDouble(token,(char **) NULL);
1939 GetMagickToken(p,&p,token);
1941 GetMagickToken(p,&p,token);
1942 affine.ty=StringToDouble(token,(char **) NULL);
1950 if (LocaleCompare(keyword,"rotate") == 0)
1957 p=(const char *) value;
1958 GetMagickToken(p,&p,token);
1959 angle=StringToDouble(value,(char **) NULL);
1960 GetMagickToken(p,&p,token);
1962 GetMagickToken(p,&p,token);
1963 x=StringToDouble(token,(char **) NULL);
1964 GetMagickToken(p,&p,token);
1966 GetMagickToken(p,&p,token);
1967 y=StringToDouble(token,(char **) NULL);
1968 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1969 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1970 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1971 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1974 svg_info->center.x=x;
1975 svg_info->center.y=y;
1983 if (LocaleCompare(keyword,"scale") == 0)
1985 for (p=(const char *) value; *p != '\0'; p++)
1986 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1989 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1990 affine.sy=affine.sx;
1992 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1994 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1997 if (LocaleCompare(keyword,"skewX") == 0)
1999 affine.sx=svg_info->affine.sx;
2000 affine.ry=tan(DegreesToRadians(fmod(
2001 GetUserSpaceCoordinateValue(svg_info,1,value),
2003 affine.sy=svg_info->affine.sy;
2006 if (LocaleCompare(keyword,"skewY") == 0)
2008 affine.sx=svg_info->affine.sx;
2009 affine.rx=tan(DegreesToRadians(fmod(
2010 GetUserSpaceCoordinateValue(svg_info,-1,value),
2012 affine.sy=svg_info->affine.sy;
2020 if (LocaleCompare(keyword,"translate") == 0)
2022 for (p=(const char *) value; *p != '\0'; p++)
2023 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2026 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2027 affine.ty=affine.tx;
2029 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2038 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2039 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2040 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2041 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2042 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2044 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2047 (void) FormatLocaleFile(svg_info->file,
2048 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2049 transform.ry,transform.sy,transform.tx,transform.ty);
2050 for (j=0; tokens[j] != (char *) NULL; j++)
2051 tokens[j]=DestroyString(tokens[j]);
2052 tokens=(char **) RelinquishMagickMemory(tokens);
2060 if (LocaleCompare(keyword,"verts") == 0)
2062 (void) CloneString(&svg_info->vertices,value);
2065 if (LocaleCompare(keyword,"viewBox") == 0)
2067 p=(const char *) value;
2068 GetMagickToken(p,&p,token);
2069 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2070 GetMagickToken(p,&p,token);
2072 GetMagickToken(p,&p,token);
2073 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2074 GetMagickToken(p,&p,token);
2076 GetMagickToken(p,&p,token);
2077 svg_info->view_box.width=StringToDouble(token,
2079 if (svg_info->bounds.width == 0)
2080 svg_info->bounds.width=svg_info->view_box.width;
2081 GetMagickToken(p,&p,token);
2083 GetMagickToken(p,&p,token);
2084 svg_info->view_box.height=StringToDouble(token,
2086 if (svg_info->bounds.height == 0)
2087 svg_info->bounds.height=svg_info->view_box.height;
2095 if (LocaleCompare(keyword,"width") == 0)
2097 svg_info->bounds.width=
2098 GetUserSpaceCoordinateValue(svg_info,1,value);
2106 if (LocaleCompare(keyword,"x") == 0)
2108 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2111 if (LocaleCompare(keyword,"xlink:href") == 0)
2113 (void) CloneString(&svg_info->url,value);
2116 if (LocaleCompare(keyword,"x1") == 0)
2118 svg_info->segment.x1=
2119 GetUserSpaceCoordinateValue(svg_info,1,value);
2122 if (LocaleCompare(keyword,"x2") == 0)
2124 svg_info->segment.x2=
2125 GetUserSpaceCoordinateValue(svg_info,1,value);
2133 if (LocaleCompare(keyword,"y") == 0)
2135 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2138 if (LocaleCompare(keyword,"y1") == 0)
2140 svg_info->segment.y1=
2141 GetUserSpaceCoordinateValue(svg_info,-1,value);
2144 if (LocaleCompare(keyword,"y2") == 0)
2146 svg_info->segment.y2=
2147 GetUserSpaceCoordinateValue(svg_info,-1,value);
2156 if (LocaleCompare((const char *) name,"svg") == 0)
2158 if (svg_info->document->encoding != (const xmlChar *) NULL)
2159 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2160 (const char *) svg_info->document->encoding);
2161 if (attributes != (const xmlChar **) NULL)
2167 if ((svg_info->view_box.width == 0.0) ||
2168 (svg_info->view_box.height == 0.0))
2169 svg_info->view_box=svg_info->bounds;
2170 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2171 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2172 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2173 (double) svg_info->width,(double) svg_info->height);
2174 sx=(double) svg_info->width/svg_info->view_box.width;
2175 sy=(double) svg_info->height/svg_info->view_box.height;
2176 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",
2180 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2181 units=DestroyString(units);
2182 if (color != (char *) NULL)
2183 color=DestroyString(color);
2186 static void SVGEndElement(void *context,const xmlChar *name)
2192 Called when the end of an element has been detected.
2194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2195 " SAX.endElement(%s)",name);
2196 svg_info=(SVGInfo *) context;
2197 if (strchr((char *) name,':') != (char *) NULL)
2200 Skip over namespace.
2202 for ( ; *name != ':'; name++) ;
2210 if (LocaleCompare((const char *) name,"circle") == 0)
2212 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2213 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2214 svg_info->element.cy+svg_info->element.minor);
2215 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2218 if (LocaleCompare((const char *) name,"clipPath") == 0)
2220 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2228 if (LocaleCompare((const char *) name,"defs") == 0)
2230 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2233 if (LocaleCompare((const char *) name,"desc") == 0)
2238 if (*svg_info->text == '\0')
2240 (void) fputc('#',svg_info->file);
2241 for (p=svg_info->text; *p != '\0'; p++)
2243 (void) fputc(*p,svg_info->file);
2245 (void) fputc('#',svg_info->file);
2247 (void) fputc('\n',svg_info->file);
2248 *svg_info->text='\0';
2256 if (LocaleCompare((const char *) name,"ellipse") == 0)
2261 angle=svg_info->element.angle;
2262 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2263 svg_info->element.cx,svg_info->element.cy,
2264 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2265 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2266 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2274 if (LocaleCompare((const char *) name,"g") == 0)
2276 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2284 if (LocaleCompare((const char *) name,"image") == 0)
2286 (void) FormatLocaleFile(svg_info->file,
2287 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2288 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2290 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2298 if (LocaleCompare((const char *) name,"line") == 0)
2300 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2301 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2302 svg_info->segment.y2);
2303 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2306 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2308 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2316 if (LocaleCompare((const char *) name,"pattern") == 0)
2318 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2321 if (LocaleCompare((const char *) name,"path") == 0)
2323 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2324 svg_info->vertices);
2325 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2328 if (LocaleCompare((const char *) name,"polygon") == 0)
2330 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2331 svg_info->vertices);
2332 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2335 if (LocaleCompare((const char *) name,"polyline") == 0)
2337 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2338 svg_info->vertices);
2339 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2347 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2349 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2352 if (LocaleCompare((const char *) name,"rect") == 0)
2354 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2356 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2357 svg_info->bounds.x,svg_info->bounds.y,
2358 svg_info->bounds.x+svg_info->bounds.width,
2359 svg_info->bounds.y+svg_info->bounds.height);
2360 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2363 if (svg_info->radius.x == 0.0)
2364 svg_info->radius.x=svg_info->radius.y;
2365 if (svg_info->radius.y == 0.0)
2366 svg_info->radius.y=svg_info->radius.x;
2367 (void) FormatLocaleFile(svg_info->file,
2368 "roundRectangle %g,%g %g,%g %g,%g\n",
2369 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2370 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2371 svg_info->radius.x,svg_info->radius.y);
2372 svg_info->radius.x=0.0;
2373 svg_info->radius.y=0.0;
2374 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2382 if (LocaleCompare((const char *) name,"stop") == 0)
2384 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2385 svg_info->stop_color,svg_info->offset);
2388 if (LocaleCompare((const char *) name,"svg") == 0)
2390 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2398 if (LocaleCompare((const char *) name,"text") == 0)
2400 if (*svg_info->text != '\0')
2405 text=EscapeString(svg_info->text,'\'');
2406 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2407 svg_info->bounds.x,svg_info->bounds.y,text);
2408 text=DestroyString(text);
2409 *svg_info->text='\0';
2411 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2414 if (LocaleCompare((const char *) name,"tspan") == 0)
2416 if (*svg_info->text != '\0')
2427 text=EscapeString(svg_info->text,'\'');
2428 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2429 svg_info->bounds.x,svg_info->bounds.y,text);
2430 text=DestroyString(text);
2431 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2432 draw_info->pointsize=svg_info->pointsize;
2433 draw_info->text=AcquireString(svg_info->text);
2434 (void) ConcatenateString(&draw_info->text," ");
2435 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2436 svg_info->exception);
2437 svg_info->bounds.x+=metrics.width;
2438 draw_info=DestroyDrawInfo(draw_info);
2439 *svg_info->text='\0';
2441 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2444 if (LocaleCompare((const char *) name,"title") == 0)
2446 if (*svg_info->text == '\0')
2448 (void) CloneString(&svg_info->title,svg_info->text);
2449 *svg_info->text='\0';
2457 *svg_info->text='\0';
2458 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2459 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2463 static void SVGCharacters(void *context,const xmlChar *c,int length)
2478 Receiving some characters from the parser.
2480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2481 " SAX.characters(%s,%.20g)",c,(double) length);
2482 svg_info=(SVGInfo *) context;
2483 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2484 if (text == (char *) NULL)
2487 for (i=0; i < (ssize_t) length; i++)
2491 if (svg_info->text == (char *) NULL)
2492 svg_info->text=text;
2495 (void) ConcatenateString(&svg_info->text,text);
2496 text=DestroyString(text);
2500 static void SVGReference(void *context,const xmlChar *name)
2509 Called when an entity reference is detected.
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2513 svg_info=(SVGInfo *) context;
2514 parser=svg_info->parser;
2515 if (parser == (xmlParserCtxtPtr) NULL)
2517 if (parser->node == (xmlNodePtr) NULL)
2520 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2522 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2525 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2531 Receiving some ignorable whitespaces from the parser.
2533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2534 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2535 svg_info=(SVGInfo *) context;
2539 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2540 const xmlChar *data)
2546 A processing instruction has been parsed.
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 " SAX.processingInstruction(%s, %s)",target,data);
2550 svg_info=(SVGInfo *) context;
2554 static void SVGComment(void *context,const xmlChar *value)
2560 A comment has been parsed.
2562 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2564 svg_info=(SVGInfo *) context;
2565 if (svg_info->comment != (char *) NULL)
2566 (void) ConcatenateString(&svg_info->comment,"\n");
2567 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2570 static void SVGWarning(void *context,const char *format,...)
2574 reason[MaxTextExtent];
2583 Display and format a warning messages, gives file, line, position and
2586 va_start(operands,format);
2587 svg_info=(SVGInfo *) context;
2588 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2590 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2591 (void) vsprintf(reason,format,operands);
2593 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2595 message=GetExceptionMessage(errno);
2596 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2597 DelegateWarning,reason,"`%s`",message);
2598 message=DestroyString(message);
2602 static void SVGError(void *context,const char *format,...)
2606 reason[MaxTextExtent];
2615 Display and format a error formats, gives file, line, position and
2618 va_start(operands,format);
2619 svg_info=(SVGInfo *) context;
2620 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2622 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2623 (void) vsprintf(reason,format,operands);
2625 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2627 message=GetExceptionMessage(errno);
2628 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2629 reason,"`%s`",message);
2630 message=DestroyString(message);
2634 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2646 Called when a pcdata block has been parsed.
2648 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2650 svg_info=(SVGInfo *) context;
2651 parser=svg_info->parser;
2652 child=xmlGetLastChild(parser->node);
2653 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2655 xmlTextConcat(child,value,length);
2658 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2661 static void SVGExternalSubset(void *context,const xmlChar *name,
2662 const xmlChar *external_id,const xmlChar *system_id)
2677 Does this document has an external subset?
2679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2680 " SAX.externalSubset(%s, %s, %s)",name,
2681 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2682 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2683 svg_info=(SVGInfo *) context;
2684 parser=svg_info->parser;
2685 if (((external_id == NULL) && (system_id == NULL)) ||
2686 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2687 (svg_info->document == 0)))
2689 input=SVGResolveEntity(context,external_id,system_id);
2692 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2693 parser_context=(*parser);
2694 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2695 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2697 parser->errNo=XML_ERR_NO_MEMORY;
2698 parser->input=parser_context.input;
2699 parser->inputNr=parser_context.inputNr;
2700 parser->inputMax=parser_context.inputMax;
2701 parser->inputTab=parser_context.inputTab;
2707 xmlPushInput(parser,input);
2708 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2709 if (input->filename == (char *) NULL)
2710 input->filename=(char *) xmlStrdup(system_id);
2713 input->base=parser->input->cur;
2714 input->cur=parser->input->cur;
2716 xmlParseExternalSubset(parser,external_id,system_id);
2717 while (parser->inputNr > 1)
2718 (void) xmlPopInput(parser);
2719 xmlFreeInputStream(parser->input);
2720 xmlFree(parser->inputTab);
2721 parser->input=parser_context.input;
2722 parser->inputNr=parser_context.inputNr;
2723 parser->inputMax=parser_context.inputMax;
2724 parser->inputTab=parser_context.inputTab;
2727 #if defined(MAGICKCORE_RSVG_DELEGATE)
2728 static void SVGSetImageSize(int *width,int *height,gpointer context)
2733 image=(Image *) context;
2734 *width=(int) (*width*image->resolution.x/72.0);
2735 *height=(int) (*height*image->resolution.y/72.0);
2739 #if defined(__cplusplus) || defined(c_plusplus)
2743 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2746 filename[MaxTextExtent];
2765 message[MaxTextExtent];
2776 assert(image_info != (const ImageInfo *) NULL);
2777 assert(image_info->signature == MagickSignature);
2778 assert(exception != (ExceptionInfo *) NULL);
2779 if (image_info->debug != MagickFalse)
2780 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2781 image_info->filename);
2782 assert(exception->signature == MagickSignature);
2783 image=AcquireImage(image_info,exception);
2784 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2785 if (status == MagickFalse)
2787 image=DestroyImageList(image);
2788 return((Image *) NULL);
2790 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2792 #if defined(MAGICKCORE_RSVG_DELEGATE)
2793 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2800 register unsigned char
2813 register const guchar
2836 svg_handle=rsvg_handle_new();
2837 if (svg_handle == (RsvgHandle *) NULL)
2838 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2839 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2840 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2841 if ((image->resolution.x != 72.0) && (image->resolution.y != 72.0))
2842 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2843 image->resolution.y);
2844 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2846 error=(GError *) NULL;
2847 (void) rsvg_handle_write(svg_handle,message,n,&error);
2848 if (error != (GError *) NULL)
2849 g_error_free(error);
2851 error=(GError *) NULL;
2852 rsvg_handle_close(svg_handle,&error);
2853 if (error != (GError *) NULL)
2854 g_error_free(error);
2855 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2856 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2857 image->columns=dimension_info.width;
2858 image->rows=dimension_info.height;
2859 pixels=(unsigned char *) NULL;
2861 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2862 rsvg_handle_free(svg_handle);
2863 image->columns=gdk_pixbuf_get_width(pixel_info);
2864 image->rows=gdk_pixbuf_get_height(pixel_info);
2866 image->matte=MagickTrue;
2867 SetImageProperty(image,"svg:base-uri",
2868 rsvg_handle_get_base_uri(svg_handle),exception);
2869 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle),
2871 SetImageProperty(image,"svg:description",
2872 rsvg_handle_get_desc(svg_handle),exception);
2873 if ((image->columns == 0) || (image->rows == 0))
2875 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2876 g_object_unref(G_OBJECT(pixel_info));
2878 g_object_unref(svg_handle);
2879 ThrowReaderException(MissingDelegateError,
2880 "NoDecodeDelegateForThisImageFormat");
2882 if (image_info->ping == MagickFalse)
2884 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2885 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2886 image->rows*sizeof(*pixels));
2887 if (pixels == (unsigned char *) NULL)
2889 g_object_unref(svg_handle);
2890 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2893 (void) SetImageBackgroundColor(image,exception);
2894 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2895 cairo_surface=cairo_image_surface_create_for_data(pixels,
2896 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2897 if (cairo_surface == (cairo_surface_t *) NULL)
2899 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2900 g_object_unref(svg_handle);
2901 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2903 cairo_info=cairo_create(cairo_surface);
2904 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2905 cairo_paint(cairo_info);
2906 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2907 rsvg_handle_render_cairo(svg_handle,cairo_info);
2908 cairo_destroy(cairo_info);
2909 cairo_surface_destroy(cairo_surface);
2910 g_object_unref(svg_handle);
2913 p=gdk_pixbuf_get_pixels(pixel_info);
2915 GetPixelInfo(image,&fill_color);
2916 for (y=0; y < (ssize_t) image->rows; y++)
2918 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2919 if (q == (Quantum *) NULL)
2921 for (x=0; x < (ssize_t) image->columns; x++)
2923 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2924 fill_color.blue=ScaleCharToQuantum(*p++);
2925 fill_color.green=ScaleCharToQuantum(*p++);
2926 fill_color.red=ScaleCharToQuantum(*p++);
2928 fill_color.red=ScaleCharToQuantum(*p++);
2929 fill_color.green=ScaleCharToQuantum(*p++);
2930 fill_color.blue=ScaleCharToQuantum(*p++);
2932 fill_color.alpha=ScaleCharToQuantum(*p++);
2933 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2938 gamma=1.0-QuantumScale*fill_color.alpha;
2939 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2940 fill_color.blue*=gamma;
2941 fill_color.green*=gamma;
2942 fill_color.red*=gamma;
2945 CompositePixelOver(image,&fill_color,fill_color.alpha,q,
2946 (MagickRealType) GetPixelAlpha(image,q),q);
2947 q+=GetPixelChannels(image);
2949 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2951 if (image->previous == (Image *) NULL)
2953 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2955 if (status == MagickFalse)
2960 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2961 if (pixels != (unsigned char *) NULL)
2962 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2964 g_object_unref(G_OBJECT(pixel_info));
2966 (void) CloseBlob(image);
2967 return(GetFirstImageInList(image));
2974 unique_file=AcquireUniqueFileResource(filename);
2975 if (unique_file != -1)
2976 file=fdopen(unique_file,"w");
2977 if ((unique_file == -1) || (file == (FILE *) NULL))
2979 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2980 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2982 image=DestroyImageList(image);
2983 return((Image *) NULL);
2988 svg_info=AcquireSVGInfo();
2989 if (svg_info == (SVGInfo *) NULL)
2990 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2991 svg_info->file=file;
2992 svg_info->exception=exception;
2993 svg_info->image=image;
2994 svg_info->image_info=image_info;
2995 svg_info->bounds.width=image->columns;
2996 svg_info->bounds.height=image->rows;
2997 if (image_info->size != (char *) NULL)
2998 (void) CloneString(&svg_info->size,image_info->size);
2999 if (image->debug != MagickFalse)
3000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3002 (void) xmlSubstituteEntitiesDefault(1);
3003 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3004 sax_modules.internalSubset=SVGInternalSubset;
3005 sax_modules.isStandalone=SVGIsStandalone;
3006 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3007 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3008 sax_modules.resolveEntity=SVGResolveEntity;
3009 sax_modules.getEntity=SVGGetEntity;
3010 sax_modules.entityDecl=SVGEntityDeclaration;
3011 sax_modules.notationDecl=SVGNotationDeclaration;
3012 sax_modules.attributeDecl=SVGAttributeDeclaration;
3013 sax_modules.elementDecl=SVGElementDeclaration;
3014 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3015 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3016 sax_modules.startDocument=SVGStartDocument;
3017 sax_modules.endDocument=SVGEndDocument;
3018 sax_modules.startElement=SVGStartElement;
3019 sax_modules.endElement=SVGEndElement;
3020 sax_modules.reference=SVGReference;
3021 sax_modules.characters=SVGCharacters;
3022 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3023 sax_modules.processingInstruction=SVGProcessingInstructions;
3024 sax_modules.comment=SVGComment;
3025 sax_modules.warning=SVGWarning;
3026 sax_modules.error=SVGError;
3027 sax_modules.fatalError=SVGError;
3028 sax_modules.getParameterEntity=SVGGetParameterEntity;
3029 sax_modules.cdataBlock=SVGCDataBlock;
3030 sax_modules.externalSubset=SVGExternalSubset;
3031 sax_handler=(&sax_modules);
3032 n=ReadBlob(image,MaxTextExtent,message);
3035 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3036 message,n,image->filename);
3037 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3039 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3044 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3045 xmlFreeParserCtxt(svg_info->parser);
3046 if (image->debug != MagickFalse)
3047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3049 (void) fclose(file);
3050 (void) CloseBlob(image);
3051 image->columns=svg_info->width;
3052 image->rows=svg_info->height;
3053 if (exception->severity >= ErrorException)
3055 image=DestroyImage(image);
3056 return((Image *) NULL);
3058 if (image_info->ping == MagickFalse)
3066 image=DestroyImage(image);
3067 image=(Image *) NULL;
3068 read_info=CloneImageInfo(image_info);
3069 SetImageInfoBlob(read_info,(void *) NULL,0);
3070 if (read_info->density != (char *) NULL)
3071 read_info->density=DestroyString(read_info->density);
3072 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3074 image=ReadImage(read_info,exception);
3075 read_info=DestroyImageInfo(read_info);
3076 if (image != (Image *) NULL)
3077 (void) CopyMagickString(image->filename,image_info->filename,
3081 Relinquish resources.
3083 if (image != (Image *) NULL)
3085 if (svg_info->title != (char *) NULL)
3086 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3087 if (svg_info->comment != (char *) NULL)
3088 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3091 svg_info=DestroySVGInfo(svg_info);
3092 (void) RelinquishUniqueFileResource(filename);
3093 return(GetFirstImageInList(image));
3098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 % R e g i s t e r S V G I m a g e %
3106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108 % RegisterSVGImage() adds attributes for the SVG image format to
3109 % the list of supported formats. The attributes include the image format
3110 % tag, a method to read and/or write the format, whether the format
3111 % supports the saving of more than one frame to the same file or blob,
3112 % whether the format supports native in-memory I/O, and a brief
3113 % description of the format.
3115 % The format of the RegisterSVGImage method is:
3117 % size_t RegisterSVGImage(void)
3120 ModuleExport size_t RegisterSVGImage(void)
3123 version[MaxTextExtent];
3129 #if defined(LIBXML_DOTTED_VERSION)
3130 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3132 #if defined(MAGICKCORE_RSVG_DELEGATE)
3134 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3135 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3137 entry=SetMagickInfo("SVG");
3138 #if defined(MAGICKCORE_XML_DELEGATE)
3139 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3141 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3142 entry->blob_support=MagickFalse;
3143 entry->seekable_stream=MagickFalse;
3144 entry->description=ConstantString("Scalable Vector Graphics");
3145 if (*version != '\0')
3146 entry->version=ConstantString(version);
3147 entry->magick=(IsImageFormatHandler *) IsSVG;
3148 entry->module=ConstantString("SVG");
3149 (void) RegisterMagickInfo(entry);
3150 entry=SetMagickInfo("SVGZ");
3151 #if defined(MAGICKCORE_XML_DELEGATE)
3152 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3154 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3155 entry->blob_support=MagickFalse;
3156 entry->seekable_stream=MagickFalse;
3157 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3158 if (*version != '\0')
3159 entry->version=ConstantString(version);
3160 entry->magick=(IsImageFormatHandler *) IsSVG;
3161 entry->module=ConstantString("SVG");
3162 (void) RegisterMagickInfo(entry);
3163 entry=SetMagickInfo("MSVG");
3164 #if defined(MAGICKCORE_XML_DELEGATE)
3165 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3167 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3168 entry->blob_support=MagickFalse;
3169 entry->seekable_stream=MagickFalse;
3170 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3171 entry->magick=(IsImageFormatHandler *) IsSVG;
3172 entry->module=ConstantString("SVG");
3173 (void) RegisterMagickInfo(entry);
3174 return(MagickImageCoderSignature);
3178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3182 % U n r e g i s t e r S V G I m a g e %
3186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3188 % UnregisterSVGImage() removes format registrations made by the
3189 % SVG module from the list of supported formats.
3191 % The format of the UnregisterSVGImage method is:
3193 % UnregisterSVGImage(void)
3196 ModuleExport void UnregisterSVGImage(void)
3198 (void) UnregisterMagickInfo("SVGZ");
3199 (void) UnregisterMagickInfo("SVG");
3200 (void) UnregisterMagickInfo("MSVG");
3201 #if defined(MAGICKCORE_RSVG_DELEGATE)
3207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3211 % W r i t e S V G I m a g e %
3215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3217 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3220 % The format of the WriteSVGImage method is:
3222 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3223 % Image *image,ExceptionInfo *exception)
3225 % A description of each parameter follows.
3227 % o image_info: the image info.
3229 % o image: The image.
3231 % o exception: return any errors or warnings in this structure.
3235 static void AffineToTransform(Image *image,AffineMatrix *affine)
3238 transform[MaxTextExtent];
3240 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3242 if ((fabs(affine->rx) < MagickEpsilon) &&
3243 (fabs(affine->ry) < MagickEpsilon))
3245 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3246 (fabs(affine->sy-1.0) < MagickEpsilon))
3248 (void) WriteBlobString(image,"\">\n");
3251 (void) FormatLocaleString(transform,MaxTextExtent,
3252 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3253 (void) WriteBlobString(image,transform);
3258 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3259 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3260 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3266 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3267 (void) FormatLocaleString(transform,MaxTextExtent,
3268 "\" transform=\"rotate(%g)\">\n",theta);
3269 (void) WriteBlobString(image,transform);
3276 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3277 (fabs(affine->rx) < MagickEpsilon) &&
3278 (fabs(affine->ry) < MagickEpsilon) &&
3279 (fabs(affine->sy-1.0) < MagickEpsilon))
3281 (void) FormatLocaleString(transform,MaxTextExtent,
3282 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3283 (void) WriteBlobString(image,transform);
3287 (void) FormatLocaleString(transform,MaxTextExtent,
3288 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3289 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3290 (void) WriteBlobString(image,transform);
3293 static MagickBooleanType IsPoint(const char *point)
3301 value=strtol(point,&p,10);
3303 return(p != point ? MagickTrue : MagickFalse);
3306 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3311 register const Quantum
3317 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3322 at_fitting_opts_type
3341 Trace image and write as SVG.
3343 fitting_options=at_fitting_opts_new();
3344 output_options=at_output_opts_new();
3345 type=GetImageType(image,exception);
3347 if ((type == BilevelType) || (type == GrayscaleType))
3349 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3351 for (y=0; y < (ssize_t) image->rows; y++)
3353 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3354 if (p == (const Quantum *) NULL)
3356 for (x=0; x < (ssize_t) image->columns; x++)
3358 trace->bitmap[i++]=GetPixelRed(image,p);
3359 if (number_planes == 3)
3361 trace->bitmap[i++]=GetPixelGreen(image,p);
3362 trace->bitmap[i++]=GetPixelBlue(image,p);
3364 p+=GetPixelChannels(image);
3367 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3369 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3370 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3375 at_splines_free(splines);
3376 at_bitmap_free(trace);
3377 at_output_opts_free(output_options);
3378 at_fitting_opts_free(fitting_options);
3383 message[MaxTextExtent],
3384 tuple[MaxTextExtent];
3389 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3390 (void) WriteBlobString(image,
3391 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3392 (void) WriteBlobString(image,
3393 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3394 (void) FormatLocaleString(message,MaxTextExtent,
3395 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3396 (double) image->rows);
3397 (void) WriteBlobString(image,message);
3398 GetPixelInfo(image,&pixel);
3399 for (y=0; y < (ssize_t) image->rows; y++)
3401 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3402 if (p == (const Quantum *) NULL)
3404 for (x=0; x < (ssize_t) image->columns; x++)
3406 SetPixelInfo(image,p,&pixel);
3407 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3408 (void) FormatLocaleString(message,MaxTextExtent,
3409 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3410 (double) x,(double) y,tuple);
3411 (void) WriteBlobString(image,message);
3412 p+=GetPixelChannels(image);
3415 (void) WriteBlobString(image,"</svg>\n");
3421 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3422 ExceptionInfo *exception)
3424 #define BezierQuantum 200
3430 keyword[MaxTextExtent],
3431 message[MaxTextExtent],
3432 name[MaxTextExtent],
3434 type[MaxTextExtent];
3476 Open output image file.
3478 assert(image_info != (const ImageInfo *) NULL);
3479 assert(image_info->signature == MagickSignature);
3480 assert(image != (Image *) NULL);
3481 assert(image->signature == MagickSignature);
3482 if (image->debug != MagickFalse)
3483 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3484 assert(exception != (ExceptionInfo *) NULL);
3485 assert(exception->signature == MagickSignature);
3486 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3487 if (status == MagickFalse)
3489 value=GetImageArtifact(image,"SVG");
3490 if (value != (char *) NULL)
3492 (void) WriteBlobString(image,value);
3493 (void) CloseBlob(image);
3496 value=GetImageArtifact(image,"MVG");
3497 if (value == (char *) NULL)
3498 return(TraceSVGImage(image,exception));
3502 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3503 (void) WriteBlobString(image,
3504 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3505 (void) WriteBlobString(image,
3506 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3507 (void) FormatLocaleString(message,MaxTextExtent,
3508 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3510 (void) WriteBlobString(image,message);
3512 Allocate primitive info memory.
3515 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3516 sizeof(*primitive_info));
3517 if (primitive_info == (PrimitiveInfo *) NULL)
3518 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3519 GetAffineMatrix(&affine);
3520 token=AcquireString(value);
3524 for (q=(const char *) value; *q != '\0'; )
3527 Interpret graphic primitive.
3529 GetMagickToken(q,&q,keyword);
3530 if (*keyword == '\0')
3532 if (*keyword == '#')
3537 if (active != MagickFalse)
3539 AffineToTransform(image,&affine);
3542 (void) WriteBlobString(image,"<desc>");
3543 (void) WriteBlobString(image,keyword+1);
3544 for ( ; (*q != '\n') && (*q != '\0'); q++)
3547 case '<': (void) WriteBlobString(image,"<"); break;
3548 case '>': (void) WriteBlobString(image,">"); break;
3549 case '&': (void) WriteBlobString(image,"&"); break;
3550 default: (void) WriteBlobByte(image,*q); break;
3552 (void) WriteBlobString(image,"</desc>\n");
3555 primitive_type=UndefinedPrimitive;
3563 if (LocaleCompare("affine",keyword) == 0)
3565 GetMagickToken(q,&q,token);
3566 affine.sx=StringToDouble(token,(char **) NULL);
3567 GetMagickToken(q,&q,token);
3569 GetMagickToken(q,&q,token);
3570 affine.rx=StringToDouble(token,(char **) NULL);
3571 GetMagickToken(q,&q,token);
3573 GetMagickToken(q,&q,token);
3574 affine.ry=StringToDouble(token,(char **) NULL);
3575 GetMagickToken(q,&q,token);
3577 GetMagickToken(q,&q,token);
3578 affine.sy=StringToDouble(token,(char **) NULL);
3579 GetMagickToken(q,&q,token);
3581 GetMagickToken(q,&q,token);
3582 affine.tx=StringToDouble(token,(char **) NULL);
3583 GetMagickToken(q,&q,token);
3585 GetMagickToken(q,&q,token);
3586 affine.ty=StringToDouble(token,(char **) NULL);
3589 if (LocaleCompare("angle",keyword) == 0)
3591 GetMagickToken(q,&q,token);
3592 affine.rx=StringToDouble(token,(char **) NULL);
3593 affine.ry=StringToDouble(token,(char **) NULL);
3596 if (LocaleCompare("arc",keyword) == 0)
3598 primitive_type=ArcPrimitive;
3607 if (LocaleCompare("bezier",keyword) == 0)
3609 primitive_type=BezierPrimitive;
3618 if (LocaleCompare("clip-path",keyword) == 0)
3620 GetMagickToken(q,&q,token);
3621 (void) FormatLocaleString(message,MaxTextExtent,
3622 "clip-path:url(#%s);",token);
3623 (void) WriteBlobString(image,message);
3626 if (LocaleCompare("clip-rule",keyword) == 0)
3628 GetMagickToken(q,&q,token);
3629 (void) FormatLocaleString(message,MaxTextExtent,
3630 "clip-rule:%s;",token);
3631 (void) WriteBlobString(image,message);
3634 if (LocaleCompare("clip-units",keyword) == 0)
3636 GetMagickToken(q,&q,token);
3637 (void) FormatLocaleString(message,MaxTextExtent,
3638 "clipPathUnits=%s;",token);
3639 (void) WriteBlobString(image,message);
3642 if (LocaleCompare("circle",keyword) == 0)
3644 primitive_type=CirclePrimitive;
3647 if (LocaleCompare("color",keyword) == 0)
3649 primitive_type=ColorPrimitive;
3658 if (LocaleCompare("decorate",keyword) == 0)
3660 GetMagickToken(q,&q,token);
3661 (void) FormatLocaleString(message,MaxTextExtent,
3662 "text-decoration:%s;",token);
3663 (void) WriteBlobString(image,message);
3672 if (LocaleCompare("ellipse",keyword) == 0)
3674 primitive_type=EllipsePrimitive;
3683 if (LocaleCompare("fill",keyword) == 0)
3685 GetMagickToken(q,&q,token);
3686 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3688 (void) WriteBlobString(image,message);
3691 if (LocaleCompare("fill-rule",keyword) == 0)
3693 GetMagickToken(q,&q,token);
3694 (void) FormatLocaleString(message,MaxTextExtent,
3695 "fill-rule:%s;",token);
3696 (void) WriteBlobString(image,message);
3699 if (LocaleCompare("fill-opacity",keyword) == 0)
3701 GetMagickToken(q,&q,token);
3702 (void) FormatLocaleString(message,MaxTextExtent,
3703 "fill-opacity:%s;",token);
3704 (void) WriteBlobString(image,message);
3707 if (LocaleCompare("font-family",keyword) == 0)
3709 GetMagickToken(q,&q,token);
3710 (void) FormatLocaleString(message,MaxTextExtent,
3711 "font-family:%s;",token);
3712 (void) WriteBlobString(image,message);
3715 if (LocaleCompare("font-stretch",keyword) == 0)
3717 GetMagickToken(q,&q,token);
3718 (void) FormatLocaleString(message,MaxTextExtent,
3719 "font-stretch:%s;",token);
3720 (void) WriteBlobString(image,message);
3723 if (LocaleCompare("font-style",keyword) == 0)
3725 GetMagickToken(q,&q,token);
3726 (void) FormatLocaleString(message,MaxTextExtent,
3727 "font-style:%s;",token);
3728 (void) WriteBlobString(image,message);
3731 if (LocaleCompare("font-size",keyword) == 0)
3733 GetMagickToken(q,&q,token);
3734 (void) FormatLocaleString(message,MaxTextExtent,
3735 "font-size:%s;",token);
3736 (void) WriteBlobString(image,message);
3739 if (LocaleCompare("font-weight",keyword) == 0)
3741 GetMagickToken(q,&q,token);
3742 (void) FormatLocaleString(message,MaxTextExtent,
3743 "font-weight:%s;",token);
3744 (void) WriteBlobString(image,message);
3753 if (LocaleCompare("gradient-units",keyword) == 0)
3755 GetMagickToken(q,&q,token);
3758 if (LocaleCompare("text-align",keyword) == 0)
3760 GetMagickToken(q,&q,token);
3761 (void) FormatLocaleString(message,MaxTextExtent,
3762 "text-align %s ",token);
3763 (void) WriteBlobString(image,message);
3766 if (LocaleCompare("text-anchor",keyword) == 0)
3768 GetMagickToken(q,&q,token);
3769 (void) FormatLocaleString(message,MaxTextExtent,
3770 "text-anchor %s ",token);
3771 (void) WriteBlobString(image,message);
3780 if (LocaleCompare("image",keyword) == 0)
3782 GetMagickToken(q,&q,token);
3783 primitive_type=ImagePrimitive;
3792 if (LocaleCompare("line",keyword) == 0)
3794 primitive_type=LinePrimitive;
3803 if (LocaleCompare("matte",keyword) == 0)
3805 primitive_type=MattePrimitive;
3814 if (LocaleCompare("opacity",keyword) == 0)
3816 GetMagickToken(q,&q,token);
3817 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3819 (void) WriteBlobString(image,message);
3828 if (LocaleCompare("path",keyword) == 0)
3830 primitive_type=PathPrimitive;
3833 if (LocaleCompare("point",keyword) == 0)
3835 primitive_type=PointPrimitive;
3838 if (LocaleCompare("polyline",keyword) == 0)
3840 primitive_type=PolylinePrimitive;
3843 if (LocaleCompare("polygon",keyword) == 0)
3845 primitive_type=PolygonPrimitive;
3848 if (LocaleCompare("pop",keyword) == 0)
3850 GetMagickToken(q,&q,token);
3851 if (LocaleCompare("clip-path",token) == 0)
3853 (void) WriteBlobString(image,"</clipPath>\n");
3856 if (LocaleCompare("defs",token) == 0)
3858 (void) WriteBlobString(image,"</defs>\n");
3861 if (LocaleCompare("gradient",token) == 0)
3863 (void) FormatLocaleString(message,MaxTextExtent,
3864 "</%sGradient>\n",type);
3865 (void) WriteBlobString(image,message);
3868 if (LocaleCompare("graphic-context",token) == 0)
3872 ThrowWriterException(DrawError,
3873 "UnbalancedGraphicContextPushPop");
3874 (void) WriteBlobString(image,"</g>\n");
3876 if (LocaleCompare("pattern",token) == 0)
3878 (void) WriteBlobString(image,"</pattern>\n");
3881 if (LocaleCompare("defs",token) == 0)
3882 (void) WriteBlobString(image,"</g>\n");
3885 if (LocaleCompare("push",keyword) == 0)
3887 GetMagickToken(q,&q,token);
3888 if (LocaleCompare("clip-path",token) == 0)
3890 GetMagickToken(q,&q,token);
3891 (void) FormatLocaleString(message,MaxTextExtent,
3892 "<clipPath id=\"%s\">\n",token);
3893 (void) WriteBlobString(image,message);
3896 if (LocaleCompare("defs",token) == 0)
3898 (void) WriteBlobString(image,"<defs>\n");
3901 if (LocaleCompare("gradient",token) == 0)
3903 GetMagickToken(q,&q,token);
3904 (void) CopyMagickString(name,token,MaxTextExtent);
3905 GetMagickToken(q,&q,token);
3906 (void) CopyMagickString(type,token,MaxTextExtent);
3907 GetMagickToken(q,&q,token);
3908 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3909 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3910 GetMagickToken(q,&q,token);
3912 GetMagickToken(q,&q,token);
3913 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
3914 svg_info.element.cy=StringToDouble(token,(char **) NULL);
3915 GetMagickToken(q,&q,token);
3917 GetMagickToken(q,&q,token);
3918 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
3919 svg_info.element.major=StringToDouble(token,
3921 GetMagickToken(q,&q,token);
3923 GetMagickToken(q,&q,token);
3924 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
3925 svg_info.element.minor=StringToDouble(token,
3927 (void) FormatLocaleString(message,MaxTextExtent,
3928 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3929 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3930 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3931 if (LocaleCompare(type,"radial") == 0)
3933 GetMagickToken(q,&q,token);
3935 GetMagickToken(q,&q,token);
3936 svg_info.element.angle=StringToDouble(token,
3938 (void) FormatLocaleString(message,MaxTextExtent,
3939 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3940 "fx=\"%g\" fy=\"%g\">\n",type,name,
3941 svg_info.element.cx,svg_info.element.cy,
3942 svg_info.element.angle,svg_info.element.major,
3943 svg_info.element.minor);
3945 (void) WriteBlobString(image,message);
3948 if (LocaleCompare("graphic-context",token) == 0)
3953 AffineToTransform(image,&affine);
3956 (void) WriteBlobString(image,"<g style=\"");
3959 if (LocaleCompare("pattern",token) == 0)
3961 GetMagickToken(q,&q,token);
3962 (void) CopyMagickString(name,token,MaxTextExtent);
3963 GetMagickToken(q,&q,token);
3964 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
3965 GetMagickToken(q,&q,token);
3967 GetMagickToken(q,&q,token);
3968 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
3969 GetMagickToken(q,&q,token);
3971 GetMagickToken(q,&q,token);
3972 svg_info.bounds.width=StringToDouble(token,
3974 GetMagickToken(q,&q,token);
3976 GetMagickToken(q,&q,token);
3977 svg_info.bounds.height=StringToDouble(token,
3979 (void) FormatLocaleString(message,MaxTextExtent,
3980 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3981 "height=\"%g\">\n",name,svg_info.bounds.x,
3982 svg_info.bounds.y,svg_info.bounds.width,
3983 svg_info.bounds.height);
3984 (void) WriteBlobString(image,message);
3995 if (LocaleCompare("rectangle",keyword) == 0)
3997 primitive_type=RectanglePrimitive;
4000 if (LocaleCompare("roundRectangle",keyword) == 0)
4002 primitive_type=RoundRectanglePrimitive;
4005 if (LocaleCompare("rotate",keyword) == 0)
4007 GetMagickToken(q,&q,token);
4008 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4010 (void) WriteBlobString(image,message);
4019 if (LocaleCompare("scale",keyword) == 0)
4021 GetMagickToken(q,&q,token);
4022 affine.sx=StringToDouble(token,(char **) NULL);
4023 GetMagickToken(q,&q,token);
4025 GetMagickToken(q,&q,token);
4026 affine.sy=StringToDouble(token,(char **) NULL);
4029 if (LocaleCompare("skewX",keyword) == 0)
4031 GetMagickToken(q,&q,token);
4032 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4034 (void) WriteBlobString(image,message);
4037 if (LocaleCompare("skewY",keyword) == 0)
4039 GetMagickToken(q,&q,token);
4040 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4042 (void) WriteBlobString(image,message);
4045 if (LocaleCompare("stop-color",keyword) == 0)
4048 color[MaxTextExtent];
4050 GetMagickToken(q,&q,token);
4051 (void) CopyMagickString(color,token,MaxTextExtent);
4052 GetMagickToken(q,&q,token);
4053 (void) FormatLocaleString(message,MaxTextExtent,
4054 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4055 (void) WriteBlobString(image,message);
4058 if (LocaleCompare("stroke",keyword) == 0)
4060 GetMagickToken(q,&q,token);
4061 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4063 (void) WriteBlobString(image,message);
4066 if (LocaleCompare("stroke-antialias",keyword) == 0)
4068 GetMagickToken(q,&q,token);
4069 (void) FormatLocaleString(message,MaxTextExtent,
4070 "stroke-antialias:%s;",token);
4071 (void) WriteBlobString(image,message);
4074 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4082 GetMagickToken(p,&p,token);
4083 for (k=0; IsPoint(token); k++)
4084 GetMagickToken(p,&p,token);
4085 (void) WriteBlobString(image,"stroke-dasharray:");
4086 for (j=0; j < k; j++)
4088 GetMagickToken(q,&q,token);
4089 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4091 (void) WriteBlobString(image,message);
4093 (void) WriteBlobString(image,";");
4096 GetMagickToken(q,&q,token);
4097 (void) FormatLocaleString(message,MaxTextExtent,
4098 "stroke-dasharray:%s;",token);
4099 (void) WriteBlobString(image,message);
4102 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4104 GetMagickToken(q,&q,token);
4105 (void) FormatLocaleString(message,MaxTextExtent,
4106 "stroke-dashoffset:%s;",token);
4107 (void) WriteBlobString(image,message);
4110 if (LocaleCompare("stroke-linecap",keyword) == 0)
4112 GetMagickToken(q,&q,token);
4113 (void) FormatLocaleString(message,MaxTextExtent,
4114 "stroke-linecap:%s;",token);
4115 (void) WriteBlobString(image,message);
4118 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4120 GetMagickToken(q,&q,token);
4121 (void) FormatLocaleString(message,MaxTextExtent,
4122 "stroke-linejoin:%s;",token);
4123 (void) WriteBlobString(image,message);
4126 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4128 GetMagickToken(q,&q,token);
4129 (void) FormatLocaleString(message,MaxTextExtent,
4130 "stroke-miterlimit:%s;",token);
4131 (void) WriteBlobString(image,message);
4134 if (LocaleCompare("stroke-opacity",keyword) == 0)
4136 GetMagickToken(q,&q,token);
4137 (void) FormatLocaleString(message,MaxTextExtent,
4138 "stroke-opacity:%s;",token);
4139 (void) WriteBlobString(image,message);
4142 if (LocaleCompare("stroke-width",keyword) == 0)
4144 GetMagickToken(q,&q,token);
4145 (void) FormatLocaleString(message,MaxTextExtent,
4146 "stroke-width:%s;",token);
4147 (void) WriteBlobString(image,message);
4156 if (LocaleCompare("text",keyword) == 0)
4158 primitive_type=TextPrimitive;
4161 if (LocaleCompare("text-antialias",keyword) == 0)
4163 GetMagickToken(q,&q,token);
4164 (void) FormatLocaleString(message,MaxTextExtent,
4165 "text-antialias:%s;",token);
4166 (void) WriteBlobString(image,message);
4169 if (LocaleCompare("tspan",keyword) == 0)
4171 primitive_type=TextPrimitive;
4174 if (LocaleCompare("translate",keyword) == 0)
4176 GetMagickToken(q,&q,token);
4177 affine.tx=StringToDouble(token,(char **) NULL);
4178 GetMagickToken(q,&q,token);
4180 GetMagickToken(q,&q,token);
4181 affine.ty=StringToDouble(token,(char **) NULL);
4190 if (LocaleCompare("viewbox",keyword) == 0)
4192 GetMagickToken(q,&q,token);
4194 GetMagickToken(q,&q,token);
4195 GetMagickToken(q,&q,token);
4197 GetMagickToken(q,&q,token);
4198 GetMagickToken(q,&q,token);
4200 GetMagickToken(q,&q,token);
4201 GetMagickToken(q,&q,token);
4213 if (status == MagickFalse)
4215 if (primitive_type == UndefinedPrimitive)
4218 Parse the primitive attributes.
4222 for (x=0; *q != '\0'; x++)
4227 if (IsPoint(q) == MagickFalse)
4229 GetMagickToken(q,&q,token);
4230 point.x=StringToDouble(token,(char **) NULL);
4231 GetMagickToken(q,&q,token);
4233 GetMagickToken(q,&q,token);
4234 point.y=StringToDouble(token,(char **) NULL);
4235 GetMagickToken(q,(const char **) NULL,token);
4237 GetMagickToken(q,&q,token);
4238 primitive_info[i].primitive=primitive_type;
4239 primitive_info[i].point=point;
4240 primitive_info[i].coordinates=0;
4241 primitive_info[i].method=FloodfillMethod;
4243 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4245 number_points+=6*BezierQuantum+360;
4246 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4247 number_points,sizeof(*primitive_info));
4248 if (primitive_info == (PrimitiveInfo *) NULL)
4250 (void) ThrowMagickException(exception,GetMagickModule(),
4251 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4255 primitive_info[j].primitive=primitive_type;
4256 primitive_info[j].coordinates=x;
4257 primitive_info[j].method=FloodfillMethod;
4258 primitive_info[j].text=(char *) NULL;
4261 AffineToTransform(image,&affine);
4265 switch (primitive_type)
4267 case PointPrimitive:
4270 if (primitive_info[j].coordinates != 1)
4279 if (primitive_info[j].coordinates != 2)
4284 (void) FormatLocaleString(message,MaxTextExtent,
4285 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4286 primitive_info[j].point.x,primitive_info[j].point.y,
4287 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4288 (void) WriteBlobString(image,message);
4291 case RectanglePrimitive:
4293 if (primitive_info[j].coordinates != 2)
4298 (void) FormatLocaleString(message,MaxTextExtent,
4299 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4300 primitive_info[j].point.x,primitive_info[j].point.y,
4301 primitive_info[j+1].point.x-primitive_info[j].point.x,
4302 primitive_info[j+1].point.y-primitive_info[j].point.y);
4303 (void) WriteBlobString(image,message);
4306 case RoundRectanglePrimitive:
4308 if (primitive_info[j].coordinates != 3)
4313 (void) FormatLocaleString(message,MaxTextExtent,
4314 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4315 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4316 primitive_info[j].point.y,primitive_info[j+1].point.x-
4317 primitive_info[j].point.x,primitive_info[j+1].point.y-
4318 primitive_info[j].point.y,primitive_info[j+2].point.x,
4319 primitive_info[j+2].point.y);
4320 (void) WriteBlobString(image,message);
4325 if (primitive_info[j].coordinates != 3)
4332 case EllipsePrimitive:
4334 if (primitive_info[j].coordinates != 3)
4339 (void) FormatLocaleString(message,MaxTextExtent,
4340 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4341 primitive_info[j].point.x,primitive_info[j].point.y,
4342 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4343 (void) WriteBlobString(image,message);
4346 case CirclePrimitive:
4352 if (primitive_info[j].coordinates != 2)
4357 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4358 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4359 (void) FormatLocaleString(message,MaxTextExtent,
4360 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4361 primitive_info[j].point.x,primitive_info[j].point.y,
4363 (void) WriteBlobString(image,message);
4366 case PolylinePrimitive:
4368 if (primitive_info[j].coordinates < 2)
4373 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4374 (void) WriteBlobString(image,message);
4375 length=strlen(message);
4378 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4379 primitive_info[j].point.x,primitive_info[j].point.y);
4380 length+=strlen(message);
4383 (void) WriteBlobString(image,"\n ");
4384 length=strlen(message)+5;
4386 (void) WriteBlobString(image,message);
4388 (void) WriteBlobString(image,"\"/>\n");
4391 case PolygonPrimitive:
4393 if (primitive_info[j].coordinates < 3)
4398 primitive_info[i]=primitive_info[j];
4399 primitive_info[i].coordinates=0;
4400 primitive_info[j].coordinates++;
4402 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4403 (void) WriteBlobString(image,message);
4404 length=strlen(message);
4407 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4408 primitive_info[j].point.x,primitive_info[j].point.y);
4409 length+=strlen(message);
4412 (void) WriteBlobString(image,"\n ");
4413 length=strlen(message)+5;
4415 (void) WriteBlobString(image,message);
4417 (void) WriteBlobString(image,"\"/>\n");
4420 case BezierPrimitive:
4422 if (primitive_info[j].coordinates < 3)
4434 GetMagickToken(q,&q,token);
4435 number_attributes=1;
4436 for (p=token; *p != '\0'; p++)
4437 if (isalpha((int) *p))
4438 number_attributes++;
4439 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4441 number_points+=6*BezierQuantum*number_attributes;
4442 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4443 number_points,sizeof(*primitive_info));
4444 if (primitive_info == (PrimitiveInfo *) NULL)
4446 (void) ThrowMagickException(exception,GetMagickModule(),
4447 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4452 (void) WriteBlobString(image," <path d=\"");
4453 (void) WriteBlobString(image,token);
4454 (void) WriteBlobString(image,"\"/>\n");
4457 case ColorPrimitive:
4458 case MattePrimitive:
4460 if (primitive_info[j].coordinates != 1)
4465 GetMagickToken(q,&q,token);
4466 if (LocaleCompare("point",token) == 0)
4467 primitive_info[j].method=PointMethod;
4468 if (LocaleCompare("replace",token) == 0)
4469 primitive_info[j].method=ReplaceMethod;
4470 if (LocaleCompare("floodfill",token) == 0)
4471 primitive_info[j].method=FloodfillMethod;
4472 if (LocaleCompare("filltoborder",token) == 0)
4473 primitive_info[j].method=FillToBorderMethod;
4474 if (LocaleCompare("reset",token) == 0)
4475 primitive_info[j].method=ResetMethod;
4483 if (primitive_info[j].coordinates != 1)
4488 GetMagickToken(q,&q,token);
4489 (void) FormatLocaleString(message,MaxTextExtent,
4490 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4491 primitive_info[j].point.y);
4492 (void) WriteBlobString(image,message);
4493 for (p=token; *p != '\0'; p++)
4496 case '<': (void) WriteBlobString(image,"<"); break;
4497 case '>': (void) WriteBlobString(image,">"); break;
4498 case '&': (void) WriteBlobString(image,"&"); break;
4499 default: (void) WriteBlobByte(image,*p); break;
4501 (void) WriteBlobString(image,"</text>\n");
4504 case ImagePrimitive:
4506 if (primitive_info[j].coordinates != 2)
4511 GetMagickToken(q,&q,token);
4512 (void) FormatLocaleString(message,MaxTextExtent,
4513 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4514 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4515 primitive_info[j].point.y,primitive_info[j+1].point.x,
4516 primitive_info[j+1].point.y,token);
4517 (void) WriteBlobString(image,message);
4521 if (primitive_info == (PrimitiveInfo *) NULL)
4523 primitive_info[i].primitive=UndefinedPrimitive;
4524 if (status == MagickFalse)
4527 (void) WriteBlobString(image,"</svg>\n");
4529 Relinquish resources.
4531 token=DestroyString(token);
4532 if (primitive_info != (PrimitiveInfo *) NULL)
4533 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4534 (void) CloseBlob(image);