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");
1095 svg_info->bounds.x=0;
1096 svg_info->bounds.y=0;
1097 svg_info->bounds.width=0;
1098 svg_info->bounds.height=0;
1101 if (LocaleCompare((const char *) name,"tspan") == 0)
1103 if (*svg_info->text != '\0')
1114 text=EscapeString(svg_info->text,'\'');
1115 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1116 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1117 svg_info->center.y,text);
1118 text=DestroyString(text);
1119 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1120 draw_info->pointsize=svg_info->pointsize;
1121 draw_info->text=AcquireString(svg_info->text);
1122 (void) ConcatenateString(&draw_info->text," ");
1123 (void) GetTypeMetrics(svg_info->image,draw_info,
1124 &metrics,svg_info->exception);
1125 svg_info->bounds.x+=metrics.width;
1126 draw_info=DestroyDrawInfo(draw_info);
1127 *svg_info->text='\0';
1129 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1137 if (attributes != (const xmlChar **) NULL)
1138 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1140 keyword=(const char *) attributes[i];
1141 value=(const char *) attributes[i+1];
1142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1143 " %s = %s",keyword,value);
1149 if (LocaleCompare(keyword,"angle") == 0)
1151 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1152 GetUserSpaceCoordinateValue(svg_info,0,value));
1160 if (LocaleCompare(keyword,"clip-path") == 0)
1162 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1165 if (LocaleCompare(keyword,"clip-rule") == 0)
1167 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1170 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1172 (void) CloneString(&units,value);
1173 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1176 if (LocaleCompare(keyword,"color") == 0)
1178 (void) CloneString(&color,value);
1181 if (LocaleCompare(keyword,"cx") == 0)
1183 svg_info->element.cx=
1184 GetUserSpaceCoordinateValue(svg_info,1,value);
1187 if (LocaleCompare(keyword,"cy") == 0)
1189 svg_info->element.cy=
1190 GetUserSpaceCoordinateValue(svg_info,-1,value);
1198 if (LocaleCompare(keyword,"d") == 0)
1200 (void) CloneString(&svg_info->vertices,value);
1203 if (LocaleCompare(keyword,"dx") == 0)
1205 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1208 if (LocaleCompare(keyword,"dy") == 0)
1210 svg_info->bounds.y+=
1211 GetUserSpaceCoordinateValue(svg_info,-1,value);
1219 if (LocaleCompare(keyword,"fill") == 0)
1221 if (LocaleCompare(value,"currentColor") == 0)
1223 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1226 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1229 if (LocaleCompare(keyword,"fillcolor") == 0)
1231 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1234 if (LocaleCompare(keyword,"fill-rule") == 0)
1236 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1239 if (LocaleCompare(keyword,"fill-opacity") == 0)
1241 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1245 if (LocaleCompare(keyword,"font-family") == 0)
1247 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1251 if (LocaleCompare(keyword,"font-stretch") == 0)
1253 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1257 if (LocaleCompare(keyword,"font-style") == 0)
1259 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1262 if (LocaleCompare(keyword,"font-size") == 0)
1264 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1265 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1266 svg_info->pointsize);
1269 if (LocaleCompare(keyword,"font-weight") == 0)
1271 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1280 if (LocaleCompare(keyword,"gradientTransform") == 0)
1287 GetAffineMatrix(&transform);
1288 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1289 tokens=GetTransformTokens(context,value,&number_tokens);
1290 for (j=0; j < (number_tokens-1); j+=2)
1292 keyword=(char *) tokens[j];
1293 if (keyword == (char *) NULL)
1295 value=(char *) tokens[j+1];
1296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1297 " %s: %s",keyword,value);
1299 GetAffineMatrix(&affine);
1305 if (LocaleCompare(keyword,"matrix") == 0)
1307 p=(const char *) value;
1308 GetMagickToken(p,&p,token);
1309 affine.sx=StringToDouble(value,(char **) NULL);
1310 GetMagickToken(p,&p,token);
1312 GetMagickToken(p,&p,token);
1313 affine.rx=StringToDouble(token,(char **) NULL);
1314 GetMagickToken(p,&p,token);
1316 GetMagickToken(p,&p,token);
1317 affine.ry=StringToDouble(token,(char **) NULL);
1318 GetMagickToken(p,&p,token);
1320 GetMagickToken(p,&p,token);
1321 affine.sy=StringToDouble(token,(char **) NULL);
1322 GetMagickToken(p,&p,token);
1324 GetMagickToken(p,&p,token);
1325 affine.tx=StringToDouble(token,(char **) NULL);
1326 GetMagickToken(p,&p,token);
1328 GetMagickToken(p,&p,token);
1329 affine.ty=StringToDouble(token,(char **) NULL);
1337 if (LocaleCompare(keyword,"rotate") == 0)
1342 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1343 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1344 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1345 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1346 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1354 if (LocaleCompare(keyword,"scale") == 0)
1356 for (p=(const char *) value; *p != '\0'; p++)
1357 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1360 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1361 affine.sy=affine.sx;
1364 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1365 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1368 if (LocaleCompare(keyword,"skewX") == 0)
1370 affine.sx=svg_info->affine.sx;
1371 affine.ry=tan(DegreesToRadians(fmod(
1372 GetUserSpaceCoordinateValue(svg_info,1,value),
1374 affine.sy=svg_info->affine.sy;
1377 if (LocaleCompare(keyword,"skewY") == 0)
1379 affine.sx=svg_info->affine.sx;
1380 affine.rx=tan(DegreesToRadians(fmod(
1381 GetUserSpaceCoordinateValue(svg_info,-1,value),
1383 affine.sy=svg_info->affine.sy;
1391 if (LocaleCompare(keyword,"translate") == 0)
1393 for (p=(const char *) value; *p != '\0'; p++)
1394 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1397 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1398 affine.ty=affine.tx;
1401 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1409 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1410 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1411 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1412 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1413 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1415 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1418 (void) FormatLocaleFile(svg_info->file,
1419 "affine %g %g %g %g %g %g\n",transform.sx,
1420 transform.rx,transform.ry,transform.sy,transform.tx,
1422 for (j=0; tokens[j] != (char *) NULL; j++)
1423 tokens[j]=DestroyString(tokens[j]);
1424 tokens=(char **) RelinquishMagickMemory(tokens);
1427 if (LocaleCompare(keyword,"gradientUnits") == 0)
1429 (void) CloneString(&units,value);
1430 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1439 if (LocaleCompare(keyword,"height") == 0)
1441 svg_info->bounds.height=
1442 GetUserSpaceCoordinateValue(svg_info,-1,value);
1445 if (LocaleCompare(keyword,"href") == 0)
1447 (void) CloneString(&svg_info->url,value);
1455 if (LocaleCompare(keyword,"major") == 0)
1457 svg_info->element.major=
1458 GetUserSpaceCoordinateValue(svg_info,1,value);
1461 if (LocaleCompare(keyword,"minor") == 0)
1463 svg_info->element.minor=
1464 GetUserSpaceCoordinateValue(svg_info,-1,value);
1472 if (LocaleCompare(keyword,"offset") == 0)
1474 (void) CloneString(&svg_info->offset,value);
1477 if (LocaleCompare(keyword,"opacity") == 0)
1479 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1487 if (LocaleCompare(keyword,"path") == 0)
1489 (void) CloneString(&svg_info->url,value);
1492 if (LocaleCompare(keyword,"points") == 0)
1494 (void) CloneString(&svg_info->vertices,value);
1502 if (LocaleCompare(keyword,"r") == 0)
1504 svg_info->element.major=
1505 GetUserSpaceCoordinateValue(svg_info,1,value);
1506 svg_info->element.minor=
1507 GetUserSpaceCoordinateValue(svg_info,-1,value);
1510 if (LocaleCompare(keyword,"rotate") == 0)
1515 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1516 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1517 svg_info->bounds.x,svg_info->bounds.y);
1518 svg_info->bounds.x=0;
1519 svg_info->bounds.y=0;
1520 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1523 if (LocaleCompare(keyword,"rx") == 0)
1525 if (LocaleCompare((const char *) name,"ellipse") == 0)
1526 svg_info->element.major=
1527 GetUserSpaceCoordinateValue(svg_info,1,value);
1530 GetUserSpaceCoordinateValue(svg_info,1,value);
1533 if (LocaleCompare(keyword,"ry") == 0)
1535 if (LocaleCompare((const char *) name,"ellipse") == 0)
1536 svg_info->element.minor=
1537 GetUserSpaceCoordinateValue(svg_info,-1,value);
1540 GetUserSpaceCoordinateValue(svg_info,-1,value);
1548 if (LocaleCompare(keyword,"stop-color") == 0)
1550 (void) CloneString(&svg_info->stop_color,value);
1553 if (LocaleCompare(keyword,"stroke") == 0)
1555 if (LocaleCompare(value,"currentColor") == 0)
1557 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1560 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1563 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1565 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1566 LocaleCompare(value,"true") == 0);
1569 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1571 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1575 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1577 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1581 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1583 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1587 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1589 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1593 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1595 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1599 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1601 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1605 if (LocaleCompare(keyword,"stroke-width") == 0)
1607 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1608 GetUserSpaceCoordinateValue(svg_info,1,value));
1611 if (LocaleCompare(keyword,"style") == 0)
1613 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1614 tokens=GetStyleTokens(context,value,&number_tokens);
1615 for (j=0; j < (number_tokens-1); j+=2)
1617 keyword=(char *) tokens[j];
1618 value=(char *) tokens[j+1];
1619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1620 " %s: %s",keyword,value);
1626 if (LocaleCompare(keyword,"clip-path") == 0)
1628 (void) FormatLocaleFile(svg_info->file,
1629 "clip-path '%s'\n",value);
1632 if (LocaleCompare(keyword,"clip-rule") == 0)
1634 (void) FormatLocaleFile(svg_info->file,
1635 "clip-rule '%s'\n",value);
1638 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1640 (void) CloneString(&units,value);
1641 (void) FormatLocaleFile(svg_info->file,
1642 "clip-units '%s'\n",value);
1645 if (LocaleCompare(keyword,"color") == 0)
1647 (void) CloneString(&color,value);
1655 if (LocaleCompare(keyword,"fill") == 0)
1657 if (LocaleCompare(value,"currentColor") == 0)
1659 (void) FormatLocaleFile(svg_info->file,
1660 "fill '%s'\n",color);
1663 if (LocaleCompare(value,"#00000000") == 0)
1664 (void) FormatLocaleFile(svg_info->file,
1665 "fill '#000000'\n");
1667 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1671 if (LocaleCompare(keyword,"fillcolor") == 0)
1673 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1677 if (LocaleCompare(keyword,"fill-rule") == 0)
1679 (void) FormatLocaleFile(svg_info->file,
1680 "fill-rule '%s'\n",value);
1683 if (LocaleCompare(keyword,"fill-opacity") == 0)
1685 (void) FormatLocaleFile(svg_info->file,
1686 "fill-opacity '%s'\n",value);
1689 if (LocaleCompare(keyword,"font-family") == 0)
1691 (void) FormatLocaleFile(svg_info->file,
1692 "font-family '%s'\n",value);
1695 if (LocaleCompare(keyword,"font-stretch") == 0)
1697 (void) FormatLocaleFile(svg_info->file,
1698 "font-stretch '%s'\n",value);
1701 if (LocaleCompare(keyword,"font-style") == 0)
1703 (void) FormatLocaleFile(svg_info->file,
1704 "font-style '%s'\n",value);
1707 if (LocaleCompare(keyword,"font-size") == 0)
1709 svg_info->pointsize=GetUserSpaceCoordinateValue(
1711 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1712 svg_info->pointsize);
1715 if (LocaleCompare(keyword,"font-weight") == 0)
1717 (void) FormatLocaleFile(svg_info->file,
1718 "font-weight '%s'\n",value);
1726 if (LocaleCompare(keyword,"offset") == 0)
1728 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1729 GetUserSpaceCoordinateValue(svg_info,1,value));
1732 if (LocaleCompare(keyword,"opacity") == 0)
1734 (void) FormatLocaleFile(svg_info->file,
1735 "opacity '%s'\n",value);
1743 if (LocaleCompare(keyword,"stop-color") == 0)
1745 (void) CloneString(&svg_info->stop_color,value);
1748 if (LocaleCompare(keyword,"stroke") == 0)
1750 if (LocaleCompare(value,"currentColor") == 0)
1752 (void) FormatLocaleFile(svg_info->file,
1753 "stroke '%s'\n",color);
1756 if (LocaleCompare(value,"#00000000") == 0)
1757 (void) FormatLocaleFile(svg_info->file,
1758 "fill '#000000'\n");
1760 (void) FormatLocaleFile(svg_info->file,
1761 "stroke '%s'\n",value);
1764 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1766 (void) FormatLocaleFile(svg_info->file,
1767 "stroke-antialias %d\n",
1768 LocaleCompare(value,"true") == 0);
1771 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1773 (void) FormatLocaleFile(svg_info->file,
1774 "stroke-dasharray %s\n",value);
1777 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1779 (void) FormatLocaleFile(svg_info->file,
1780 "stroke-dashoffset %s\n",
1784 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1786 (void) FormatLocaleFile(svg_info->file,
1787 "stroke-linecap '%s'\n",value);
1790 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1792 (void) FormatLocaleFile(svg_info->file,
1793 "stroke-linejoin '%s'\n",
1797 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1799 (void) FormatLocaleFile(svg_info->file,
1800 "stroke-miterlimit '%s'\n",
1804 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1806 (void) FormatLocaleFile(svg_info->file,
1807 "stroke-opacity '%s'\n",value);
1810 if (LocaleCompare(keyword,"stroke-width") == 0)
1812 (void) FormatLocaleFile(svg_info->file,
1813 "stroke-width %g\n",
1814 GetUserSpaceCoordinateValue(svg_info,1,value));
1822 if (LocaleCompare(keyword,"text-align") == 0)
1824 (void) FormatLocaleFile(svg_info->file,
1825 "text-align '%s'\n",value);
1828 if (LocaleCompare(keyword,"text-anchor") == 0)
1830 (void) FormatLocaleFile(svg_info->file,
1831 "text-anchor '%s'\n",value);
1834 if (LocaleCompare(keyword,"text-decoration") == 0)
1836 if (LocaleCompare(value,"underline") == 0)
1837 (void) FormatLocaleFile(svg_info->file,
1838 "decorate underline\n");
1839 if (LocaleCompare(value,"line-through") == 0)
1840 (void) FormatLocaleFile(svg_info->file,
1841 "decorate line-through\n");
1842 if (LocaleCompare(value,"overline") == 0)
1843 (void) FormatLocaleFile(svg_info->file,
1844 "decorate overline\n");
1847 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1849 (void) FormatLocaleFile(svg_info->file,
1850 "text-antialias %d\n",
1851 LocaleCompare(value,"true") == 0);
1860 for (j=0; tokens[j] != (char *) NULL; j++)
1861 tokens[j]=DestroyString(tokens[j]);
1862 tokens=(char **) RelinquishMagickMemory(tokens);
1870 if (LocaleCompare(keyword,"text-align") == 0)
1872 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1876 if (LocaleCompare(keyword,"text-anchor") == 0)
1878 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1882 if (LocaleCompare(keyword,"text-decoration") == 0)
1884 if (LocaleCompare(value,"underline") == 0)
1885 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1886 if (LocaleCompare(value,"line-through") == 0)
1887 (void) FormatLocaleFile(svg_info->file,
1888 "decorate line-through\n");
1889 if (LocaleCompare(value,"overline") == 0)
1890 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1893 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1895 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1896 LocaleCompare(value,"true") == 0);
1899 if (LocaleCompare(keyword,"transform") == 0)
1906 GetAffineMatrix(&transform);
1907 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1908 tokens=GetTransformTokens(context,value,&number_tokens);
1909 for (j=0; j < (number_tokens-1); j+=2)
1911 keyword=(char *) tokens[j];
1912 value=(char *) tokens[j+1];
1913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1914 " %s: %s",keyword,value);
1916 GetAffineMatrix(&affine);
1922 if (LocaleCompare(keyword,"matrix") == 0)
1924 p=(const char *) value;
1925 GetMagickToken(p,&p,token);
1926 affine.sx=StringToDouble(value,(char **) NULL);
1927 GetMagickToken(p,&p,token);
1929 GetMagickToken(p,&p,token);
1930 affine.rx=StringToDouble(token,(char **) NULL);
1931 GetMagickToken(p,&p,token);
1933 GetMagickToken(p,&p,token);
1934 affine.ry=StringToDouble(token,(char **) NULL);
1935 GetMagickToken(p,&p,token);
1937 GetMagickToken(p,&p,token);
1938 affine.sy=StringToDouble(token,(char **) NULL);
1939 GetMagickToken(p,&p,token);
1941 GetMagickToken(p,&p,token);
1942 affine.tx=StringToDouble(token,(char **) NULL);
1943 GetMagickToken(p,&p,token);
1945 GetMagickToken(p,&p,token);
1946 affine.ty=StringToDouble(token,(char **) NULL);
1954 if (LocaleCompare(keyword,"rotate") == 0)
1961 p=(const char *) value;
1962 GetMagickToken(p,&p,token);
1963 angle=StringToDouble(value,(char **) NULL);
1964 GetMagickToken(p,&p,token);
1966 GetMagickToken(p,&p,token);
1967 x=StringToDouble(token,(char **) NULL);
1968 GetMagickToken(p,&p,token);
1970 GetMagickToken(p,&p,token);
1971 y=StringToDouble(token,(char **) NULL);
1972 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1973 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1974 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1975 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1978 svg_info->center.x=x;
1979 svg_info->center.y=y;
1987 if (LocaleCompare(keyword,"scale") == 0)
1989 for (p=(const char *) value; *p != '\0'; p++)
1990 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1993 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1994 affine.sy=affine.sx;
1996 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1998 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2001 if (LocaleCompare(keyword,"skewX") == 0)
2003 affine.sx=svg_info->affine.sx;
2004 affine.ry=tan(DegreesToRadians(fmod(
2005 GetUserSpaceCoordinateValue(svg_info,1,value),
2007 affine.sy=svg_info->affine.sy;
2010 if (LocaleCompare(keyword,"skewY") == 0)
2012 affine.sx=svg_info->affine.sx;
2013 affine.rx=tan(DegreesToRadians(fmod(
2014 GetUserSpaceCoordinateValue(svg_info,-1,value),
2016 affine.sy=svg_info->affine.sy;
2024 if (LocaleCompare(keyword,"translate") == 0)
2026 for (p=(const char *) value; *p != '\0'; p++)
2027 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2030 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2031 affine.ty=affine.tx;
2033 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2042 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2043 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2044 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2045 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2046 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2048 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2051 (void) FormatLocaleFile(svg_info->file,
2052 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2053 transform.ry,transform.sy,transform.tx,transform.ty);
2054 for (j=0; tokens[j] != (char *) NULL; j++)
2055 tokens[j]=DestroyString(tokens[j]);
2056 tokens=(char **) RelinquishMagickMemory(tokens);
2064 if (LocaleCompare(keyword,"verts") == 0)
2066 (void) CloneString(&svg_info->vertices,value);
2069 if (LocaleCompare(keyword,"viewBox") == 0)
2071 p=(const char *) value;
2072 GetMagickToken(p,&p,token);
2073 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2074 GetMagickToken(p,&p,token);
2076 GetMagickToken(p,&p,token);
2077 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2078 GetMagickToken(p,&p,token);
2080 GetMagickToken(p,&p,token);
2081 svg_info->view_box.width=StringToDouble(token,
2083 if (svg_info->bounds.width == 0)
2084 svg_info->bounds.width=svg_info->view_box.width;
2085 GetMagickToken(p,&p,token);
2087 GetMagickToken(p,&p,token);
2088 svg_info->view_box.height=StringToDouble(token,
2090 if (svg_info->bounds.height == 0)
2091 svg_info->bounds.height=svg_info->view_box.height;
2099 if (LocaleCompare(keyword,"width") == 0)
2101 svg_info->bounds.width=
2102 GetUserSpaceCoordinateValue(svg_info,1,value);
2110 if (LocaleCompare(keyword,"x") == 0)
2112 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2115 if (LocaleCompare(keyword,"xlink:href") == 0)
2117 (void) CloneString(&svg_info->url,value);
2120 if (LocaleCompare(keyword,"x1") == 0)
2122 svg_info->segment.x1=
2123 GetUserSpaceCoordinateValue(svg_info,1,value);
2126 if (LocaleCompare(keyword,"x2") == 0)
2128 svg_info->segment.x2=
2129 GetUserSpaceCoordinateValue(svg_info,1,value);
2137 if (LocaleCompare(keyword,"y") == 0)
2139 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2142 if (LocaleCompare(keyword,"y1") == 0)
2144 svg_info->segment.y1=
2145 GetUserSpaceCoordinateValue(svg_info,-1,value);
2148 if (LocaleCompare(keyword,"y2") == 0)
2150 svg_info->segment.y2=
2151 GetUserSpaceCoordinateValue(svg_info,-1,value);
2160 if (LocaleCompare((const char *) name,"svg") == 0)
2162 if (svg_info->document->encoding != (const xmlChar *) NULL)
2163 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2164 (const char *) svg_info->document->encoding);
2165 if (attributes != (const xmlChar **) NULL)
2171 if ((svg_info->view_box.width == 0.0) ||
2172 (svg_info->view_box.height == 0.0))
2173 svg_info->view_box=svg_info->bounds;
2174 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2175 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2176 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2177 (double) svg_info->width,(double) svg_info->height);
2178 sx=(double) svg_info->width/svg_info->view_box.width;
2179 sy=(double) svg_info->height/svg_info->view_box.height;
2180 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",
2184 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2185 units=DestroyString(units);
2186 if (color != (char *) NULL)
2187 color=DestroyString(color);
2190 static void SVGEndElement(void *context,const xmlChar *name)
2196 Called when the end of an element has been detected.
2198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2199 " SAX.endElement(%s)",name);
2200 svg_info=(SVGInfo *) context;
2201 if (strchr((char *) name,':') != (char *) NULL)
2204 Skip over namespace.
2206 for ( ; *name != ':'; name++) ;
2214 if (LocaleCompare((const char *) name,"circle") == 0)
2216 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2217 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2218 svg_info->element.cy+svg_info->element.minor);
2219 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2222 if (LocaleCompare((const char *) name,"clipPath") == 0)
2224 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2232 if (LocaleCompare((const char *) name,"defs") == 0)
2234 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2237 if (LocaleCompare((const char *) name,"desc") == 0)
2242 if (*svg_info->text == '\0')
2244 (void) fputc('#',svg_info->file);
2245 for (p=svg_info->text; *p != '\0'; p++)
2247 (void) fputc(*p,svg_info->file);
2249 (void) fputc('#',svg_info->file);
2251 (void) fputc('\n',svg_info->file);
2252 *svg_info->text='\0';
2260 if (LocaleCompare((const char *) name,"ellipse") == 0)
2265 angle=svg_info->element.angle;
2266 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2267 svg_info->element.cx,svg_info->element.cy,
2268 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2269 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2270 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2278 if (LocaleCompare((const char *) name,"g") == 0)
2280 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2288 if (LocaleCompare((const char *) name,"image") == 0)
2290 (void) FormatLocaleFile(svg_info->file,
2291 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2292 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2294 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2302 if (LocaleCompare((const char *) name,"line") == 0)
2304 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2305 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2306 svg_info->segment.y2);
2307 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2310 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2312 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2320 if (LocaleCompare((const char *) name,"pattern") == 0)
2322 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2325 if (LocaleCompare((const char *) name,"path") == 0)
2327 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2328 svg_info->vertices);
2329 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2332 if (LocaleCompare((const char *) name,"polygon") == 0)
2334 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2335 svg_info->vertices);
2336 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2339 if (LocaleCompare((const char *) name,"polyline") == 0)
2341 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2342 svg_info->vertices);
2343 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2351 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2353 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2356 if (LocaleCompare((const char *) name,"rect") == 0)
2358 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2360 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2361 svg_info->bounds.x,svg_info->bounds.y,
2362 svg_info->bounds.x+svg_info->bounds.width,
2363 svg_info->bounds.y+svg_info->bounds.height);
2364 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2367 if (svg_info->radius.x == 0.0)
2368 svg_info->radius.x=svg_info->radius.y;
2369 if (svg_info->radius.y == 0.0)
2370 svg_info->radius.y=svg_info->radius.x;
2371 (void) FormatLocaleFile(svg_info->file,
2372 "roundRectangle %g,%g %g,%g %g,%g\n",
2373 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2374 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2375 svg_info->radius.x,svg_info->radius.y);
2376 svg_info->radius.x=0.0;
2377 svg_info->radius.y=0.0;
2378 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2386 if (LocaleCompare((const char *) name,"stop") == 0)
2388 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2389 svg_info->stop_color,svg_info->offset);
2392 if (LocaleCompare((const char *) name,"svg") == 0)
2394 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2402 if (LocaleCompare((const char *) name,"text") == 0)
2404 if (*svg_info->text != '\0')
2409 text=EscapeString(svg_info->text,'\'');
2410 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2411 svg_info->bounds.x,svg_info->bounds.y,text);
2412 text=DestroyString(text);
2413 *svg_info->text='\0';
2415 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2418 if (LocaleCompare((const char *) name,"tspan") == 0)
2420 if (*svg_info->text != '\0')
2431 text=EscapeString(svg_info->text,'\'');
2432 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2433 svg_info->bounds.x,svg_info->bounds.y,text);
2434 text=DestroyString(text);
2435 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2436 draw_info->pointsize=svg_info->pointsize;
2437 draw_info->text=AcquireString(svg_info->text);
2438 (void) ConcatenateString(&draw_info->text," ");
2439 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2440 svg_info->exception);
2441 svg_info->bounds.x+=metrics.width;
2442 draw_info=DestroyDrawInfo(draw_info);
2443 *svg_info->text='\0';
2445 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2448 if (LocaleCompare((const char *) name,"title") == 0)
2450 if (*svg_info->text == '\0')
2452 (void) CloneString(&svg_info->title,svg_info->text);
2453 *svg_info->text='\0';
2461 *svg_info->text='\0';
2462 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2463 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2467 static void SVGCharacters(void *context,const xmlChar *c,int length)
2482 Receiving some characters from the parser.
2484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2485 " SAX.characters(%s,%.20g)",c,(double) length);
2486 svg_info=(SVGInfo *) context;
2487 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2488 if (text == (char *) NULL)
2491 for (i=0; i < (ssize_t) length; i++)
2495 if (svg_info->text == (char *) NULL)
2496 svg_info->text=text;
2499 (void) ConcatenateString(&svg_info->text,text);
2500 text=DestroyString(text);
2504 static void SVGReference(void *context,const xmlChar *name)
2513 Called when an entity reference is detected.
2515 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2517 svg_info=(SVGInfo *) context;
2518 parser=svg_info->parser;
2519 if (parser == (xmlParserCtxtPtr) NULL)
2521 if (parser->node == (xmlNodePtr) NULL)
2524 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2526 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2529 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2535 Receiving some ignorable whitespaces from the parser.
2537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2538 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2539 svg_info=(SVGInfo *) context;
2543 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2544 const xmlChar *data)
2550 A processing instruction has been parsed.
2552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2553 " SAX.processingInstruction(%s, %s)",target,data);
2554 svg_info=(SVGInfo *) context;
2558 static void SVGComment(void *context,const xmlChar *value)
2564 A comment has been parsed.
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2568 svg_info=(SVGInfo *) context;
2569 if (svg_info->comment != (char *) NULL)
2570 (void) ConcatenateString(&svg_info->comment,"\n");
2571 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2574 static void SVGWarning(void *context,const char *format,...)
2578 reason[MaxTextExtent];
2587 Display and format a warning messages, gives file, line, position and
2590 va_start(operands,format);
2591 svg_info=(SVGInfo *) context;
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2594 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2595 (void) vsprintf(reason,format,operands);
2597 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2599 message=GetExceptionMessage(errno);
2600 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2601 DelegateWarning,reason,"`%s`",message);
2602 message=DestroyString(message);
2606 static void SVGError(void *context,const char *format,...)
2610 reason[MaxTextExtent];
2619 Display and format a error formats, gives file, line, position and
2622 va_start(operands,format);
2623 svg_info=(SVGInfo *) context;
2624 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2626 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2627 (void) vsprintf(reason,format,operands);
2629 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2631 message=GetExceptionMessage(errno);
2632 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2633 reason,"`%s`",message);
2634 message=DestroyString(message);
2638 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2650 Called when a pcdata block has been parsed.
2652 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2654 svg_info=(SVGInfo *) context;
2655 parser=svg_info->parser;
2656 child=xmlGetLastChild(parser->node);
2657 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2659 xmlTextConcat(child,value,length);
2662 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2665 static void SVGExternalSubset(void *context,const xmlChar *name,
2666 const xmlChar *external_id,const xmlChar *system_id)
2681 Does this document has an external subset?
2683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2684 " SAX.externalSubset(%s, %s, %s)",name,
2685 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2686 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2687 svg_info=(SVGInfo *) context;
2688 parser=svg_info->parser;
2689 if (((external_id == NULL) && (system_id == NULL)) ||
2690 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2691 (svg_info->document == 0)))
2693 input=SVGResolveEntity(context,external_id,system_id);
2696 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2697 parser_context=(*parser);
2698 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2699 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2701 parser->errNo=XML_ERR_NO_MEMORY;
2702 parser->input=parser_context.input;
2703 parser->inputNr=parser_context.inputNr;
2704 parser->inputMax=parser_context.inputMax;
2705 parser->inputTab=parser_context.inputTab;
2711 xmlPushInput(parser,input);
2712 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2713 if (input->filename == (char *) NULL)
2714 input->filename=(char *) xmlStrdup(system_id);
2717 input->base=parser->input->cur;
2718 input->cur=parser->input->cur;
2720 xmlParseExternalSubset(parser,external_id,system_id);
2721 while (parser->inputNr > 1)
2722 (void) xmlPopInput(parser);
2723 xmlFreeInputStream(parser->input);
2724 xmlFree(parser->inputTab);
2725 parser->input=parser_context.input;
2726 parser->inputNr=parser_context.inputNr;
2727 parser->inputMax=parser_context.inputMax;
2728 parser->inputTab=parser_context.inputTab;
2731 #if defined(MAGICKCORE_RSVG_DELEGATE)
2732 static void SVGSetImageSize(int *width,int *height,gpointer context)
2737 image=(Image *) context;
2738 *width=(int) (*width*image->resolution.x/72.0);
2739 *height=(int) (*height*image->resolution.y/72.0);
2743 #if defined(__cplusplus) || defined(c_plusplus)
2747 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2750 filename[MaxTextExtent];
2769 message[MaxTextExtent];
2780 assert(image_info != (const ImageInfo *) NULL);
2781 assert(image_info->signature == MagickSignature);
2782 assert(exception != (ExceptionInfo *) NULL);
2783 if (image_info->debug != MagickFalse)
2784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2785 image_info->filename);
2786 assert(exception->signature == MagickSignature);
2787 image=AcquireImage(image_info,exception);
2788 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2789 if (status == MagickFalse)
2791 image=DestroyImageList(image);
2792 return((Image *) NULL);
2794 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2796 #if defined(MAGICKCORE_RSVG_DELEGATE)
2797 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2804 register unsigned char
2817 register const guchar
2840 svg_handle=rsvg_handle_new();
2841 if (svg_handle == (RsvgHandle *) NULL)
2842 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2843 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2844 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2845 if ((image->resolution.x != 72.0) && (image->resolution.y != 72.0))
2846 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2847 image->resolution.y);
2848 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2850 error=(GError *) NULL;
2851 (void) rsvg_handle_write(svg_handle,message,n,&error);
2852 if (error != (GError *) NULL)
2853 g_error_free(error);
2855 error=(GError *) NULL;
2856 rsvg_handle_close(svg_handle,&error);
2857 if (error != (GError *) NULL)
2858 g_error_free(error);
2859 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2860 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2861 image->columns=dimension_info.width;
2862 image->rows=dimension_info.height;
2863 pixels=(unsigned char *) NULL;
2865 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2866 rsvg_handle_free(svg_handle);
2867 image->columns=gdk_pixbuf_get_width(pixel_info);
2868 image->rows=gdk_pixbuf_get_height(pixel_info);
2870 image->matte=MagickTrue;
2871 SetImageProperty(image,"svg:base-uri",
2872 rsvg_handle_get_base_uri(svg_handle),exception);
2873 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle),
2875 SetImageProperty(image,"svg:description",
2876 rsvg_handle_get_desc(svg_handle),exception);
2877 if ((image->columns == 0) || (image->rows == 0))
2879 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2880 g_object_unref(G_OBJECT(pixel_info));
2882 g_object_unref(svg_handle);
2883 ThrowReaderException(MissingDelegateError,
2884 "NoDecodeDelegateForThisImageFormat");
2886 if (image_info->ping == MagickFalse)
2888 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2889 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2890 image->rows*sizeof(*pixels));
2891 if (pixels == (unsigned char *) NULL)
2893 g_object_unref(svg_handle);
2894 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2897 (void) SetImageBackgroundColor(image,exception);
2898 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2899 cairo_surface=cairo_image_surface_create_for_data(pixels,
2900 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2901 if (cairo_surface == (cairo_surface_t *) NULL)
2903 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2904 g_object_unref(svg_handle);
2905 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2907 cairo_info=cairo_create(cairo_surface);
2908 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2909 cairo_paint(cairo_info);
2910 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2911 rsvg_handle_render_cairo(svg_handle,cairo_info);
2912 cairo_destroy(cairo_info);
2913 cairo_surface_destroy(cairo_surface);
2914 g_object_unref(svg_handle);
2917 p=gdk_pixbuf_get_pixels(pixel_info);
2919 GetPixelInfo(image,&fill_color);
2920 for (y=0; y < (ssize_t) image->rows; y++)
2922 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2923 if (q == (Quantum *) NULL)
2925 for (x=0; x < (ssize_t) image->columns; x++)
2927 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2928 fill_color.blue=ScaleCharToQuantum(*p++);
2929 fill_color.green=ScaleCharToQuantum(*p++);
2930 fill_color.red=ScaleCharToQuantum(*p++);
2932 fill_color.red=ScaleCharToQuantum(*p++);
2933 fill_color.green=ScaleCharToQuantum(*p++);
2934 fill_color.blue=ScaleCharToQuantum(*p++);
2936 fill_color.alpha=ScaleCharToQuantum(*p++);
2937 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2942 gamma=1.0-QuantumScale*fill_color.alpha;
2943 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2944 fill_color.blue*=gamma;
2945 fill_color.green*=gamma;
2946 fill_color.red*=gamma;
2949 CompositePixelOver(image,&fill_color,fill_color.alpha,q,
2950 (MagickRealType) GetPixelAlpha(image,q),q);
2951 q+=GetPixelChannels(image);
2953 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2955 if (image->previous == (Image *) NULL)
2957 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2959 if (status == MagickFalse)
2964 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2965 if (pixels != (unsigned char *) NULL)
2966 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2968 g_object_unref(G_OBJECT(pixel_info));
2970 (void) CloseBlob(image);
2971 return(GetFirstImageInList(image));
2978 unique_file=AcquireUniqueFileResource(filename);
2979 if (unique_file != -1)
2980 file=fdopen(unique_file,"w");
2981 if ((unique_file == -1) || (file == (FILE *) NULL))
2983 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2984 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2986 image=DestroyImageList(image);
2987 return((Image *) NULL);
2992 svg_info=AcquireSVGInfo();
2993 if (svg_info == (SVGInfo *) NULL)
2994 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2995 svg_info->file=file;
2996 svg_info->exception=exception;
2997 svg_info->image=image;
2998 svg_info->image_info=image_info;
2999 svg_info->bounds.width=image->columns;
3000 svg_info->bounds.height=image->rows;
3001 if (image_info->size != (char *) NULL)
3002 (void) CloneString(&svg_info->size,image_info->size);
3003 if (image->debug != MagickFalse)
3004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3006 (void) xmlSubstituteEntitiesDefault(1);
3007 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3008 sax_modules.internalSubset=SVGInternalSubset;
3009 sax_modules.isStandalone=SVGIsStandalone;
3010 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3011 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3012 sax_modules.resolveEntity=SVGResolveEntity;
3013 sax_modules.getEntity=SVGGetEntity;
3014 sax_modules.entityDecl=SVGEntityDeclaration;
3015 sax_modules.notationDecl=SVGNotationDeclaration;
3016 sax_modules.attributeDecl=SVGAttributeDeclaration;
3017 sax_modules.elementDecl=SVGElementDeclaration;
3018 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3019 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3020 sax_modules.startDocument=SVGStartDocument;
3021 sax_modules.endDocument=SVGEndDocument;
3022 sax_modules.startElement=SVGStartElement;
3023 sax_modules.endElement=SVGEndElement;
3024 sax_modules.reference=SVGReference;
3025 sax_modules.characters=SVGCharacters;
3026 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3027 sax_modules.processingInstruction=SVGProcessingInstructions;
3028 sax_modules.comment=SVGComment;
3029 sax_modules.warning=SVGWarning;
3030 sax_modules.error=SVGError;
3031 sax_modules.fatalError=SVGError;
3032 sax_modules.getParameterEntity=SVGGetParameterEntity;
3033 sax_modules.cdataBlock=SVGCDataBlock;
3034 sax_modules.externalSubset=SVGExternalSubset;
3035 sax_handler=(&sax_modules);
3036 n=ReadBlob(image,MaxTextExtent,message);
3039 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3040 message,n,image->filename);
3041 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3043 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3048 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3049 xmlFreeParserCtxt(svg_info->parser);
3050 if (image->debug != MagickFalse)
3051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3053 (void) fclose(file);
3054 (void) CloseBlob(image);
3055 image->columns=svg_info->width;
3056 image->rows=svg_info->height;
3057 if (exception->severity >= ErrorException)
3059 image=DestroyImage(image);
3060 return((Image *) NULL);
3062 if (image_info->ping == MagickFalse)
3070 image=DestroyImage(image);
3071 image=(Image *) NULL;
3072 read_info=CloneImageInfo(image_info);
3073 SetImageInfoBlob(read_info,(void *) NULL,0);
3074 if (read_info->density != (char *) NULL)
3075 read_info->density=DestroyString(read_info->density);
3076 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3078 image=ReadImage(read_info,exception);
3079 read_info=DestroyImageInfo(read_info);
3080 if (image != (Image *) NULL)
3081 (void) CopyMagickString(image->filename,image_info->filename,
3085 Relinquish resources.
3087 if (image != (Image *) NULL)
3089 if (svg_info->title != (char *) NULL)
3090 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3091 if (svg_info->comment != (char *) NULL)
3092 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3095 svg_info=DestroySVGInfo(svg_info);
3096 (void) RelinquishUniqueFileResource(filename);
3097 return(GetFirstImageInList(image));
3102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3106 % R e g i s t e r S V G I m a g e %
3110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3112 % RegisterSVGImage() adds attributes for the SVG image format to
3113 % the list of supported formats. The attributes include the image format
3114 % tag, a method to read and/or write the format, whether the format
3115 % supports the saving of more than one frame to the same file or blob,
3116 % whether the format supports native in-memory I/O, and a brief
3117 % description of the format.
3119 % The format of the RegisterSVGImage method is:
3121 % size_t RegisterSVGImage(void)
3124 ModuleExport size_t RegisterSVGImage(void)
3127 version[MaxTextExtent];
3133 #if defined(LIBXML_DOTTED_VERSION)
3134 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3136 #if defined(MAGICKCORE_RSVG_DELEGATE)
3138 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3139 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3141 entry=SetMagickInfo("SVG");
3142 #if defined(MAGICKCORE_XML_DELEGATE)
3143 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3145 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3146 entry->blob_support=MagickFalse;
3147 entry->seekable_stream=MagickFalse;
3148 entry->description=ConstantString("Scalable Vector Graphics");
3149 if (*version != '\0')
3150 entry->version=ConstantString(version);
3151 entry->magick=(IsImageFormatHandler *) IsSVG;
3152 entry->module=ConstantString("SVG");
3153 (void) RegisterMagickInfo(entry);
3154 entry=SetMagickInfo("SVGZ");
3155 #if defined(MAGICKCORE_XML_DELEGATE)
3156 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3158 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3159 entry->blob_support=MagickFalse;
3160 entry->seekable_stream=MagickFalse;
3161 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3162 if (*version != '\0')
3163 entry->version=ConstantString(version);
3164 entry->magick=(IsImageFormatHandler *) IsSVG;
3165 entry->module=ConstantString("SVG");
3166 (void) RegisterMagickInfo(entry);
3167 entry=SetMagickInfo("MSVG");
3168 #if defined(MAGICKCORE_XML_DELEGATE)
3169 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3171 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3172 entry->blob_support=MagickFalse;
3173 entry->seekable_stream=MagickFalse;
3174 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3175 entry->magick=(IsImageFormatHandler *) IsSVG;
3176 entry->module=ConstantString("SVG");
3177 (void) RegisterMagickInfo(entry);
3178 return(MagickImageCoderSignature);
3182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3186 % U n r e g i s t e r S V G I m a g e %
3190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3192 % UnregisterSVGImage() removes format registrations made by the
3193 % SVG module from the list of supported formats.
3195 % The format of the UnregisterSVGImage method is:
3197 % UnregisterSVGImage(void)
3200 ModuleExport void UnregisterSVGImage(void)
3202 (void) UnregisterMagickInfo("SVGZ");
3203 (void) UnregisterMagickInfo("SVG");
3204 (void) UnregisterMagickInfo("MSVG");
3205 #if defined(MAGICKCORE_RSVG_DELEGATE)
3211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3215 % W r i t e S V G I m a g e %
3219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3221 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3224 % The format of the WriteSVGImage method is:
3226 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3227 % Image *image,ExceptionInfo *exception)
3229 % A description of each parameter follows.
3231 % o image_info: the image info.
3233 % o image: The image.
3235 % o exception: return any errors or warnings in this structure.
3239 static void AffineToTransform(Image *image,AffineMatrix *affine)
3242 transform[MaxTextExtent];
3244 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3246 if ((fabs(affine->rx) < MagickEpsilon) &&
3247 (fabs(affine->ry) < MagickEpsilon))
3249 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3250 (fabs(affine->sy-1.0) < MagickEpsilon))
3252 (void) WriteBlobString(image,"\">\n");
3255 (void) FormatLocaleString(transform,MaxTextExtent,
3256 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3257 (void) WriteBlobString(image,transform);
3262 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3263 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3264 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3270 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3271 (void) FormatLocaleString(transform,MaxTextExtent,
3272 "\" transform=\"rotate(%g)\">\n",theta);
3273 (void) WriteBlobString(image,transform);
3280 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3281 (fabs(affine->rx) < MagickEpsilon) &&
3282 (fabs(affine->ry) < MagickEpsilon) &&
3283 (fabs(affine->sy-1.0) < MagickEpsilon))
3285 (void) FormatLocaleString(transform,MaxTextExtent,
3286 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3287 (void) WriteBlobString(image,transform);
3291 (void) FormatLocaleString(transform,MaxTextExtent,
3292 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3293 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3294 (void) WriteBlobString(image,transform);
3297 static MagickBooleanType IsPoint(const char *point)
3305 value=strtol(point,&p,10);
3307 return(p != point ? MagickTrue : MagickFalse);
3310 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3315 register const Quantum
3321 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3326 at_fitting_opts_type
3345 Trace image and write as SVG.
3347 fitting_options=at_fitting_opts_new();
3348 output_options=at_output_opts_new();
3349 type=GetImageType(image,exception);
3351 if ((type == BilevelType) || (type == GrayscaleType))
3353 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3355 for (y=0; y < (ssize_t) image->rows; y++)
3357 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3358 if (p == (const Quantum *) NULL)
3360 for (x=0; x < (ssize_t) image->columns; x++)
3362 trace->bitmap[i++]=GetPixelRed(image,p);
3363 if (number_planes == 3)
3365 trace->bitmap[i++]=GetPixelGreen(image,p);
3366 trace->bitmap[i++]=GetPixelBlue(image,p);
3368 p+=GetPixelChannels(image);
3371 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3373 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3374 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3379 at_splines_free(splines);
3380 at_bitmap_free(trace);
3381 at_output_opts_free(output_options);
3382 at_fitting_opts_free(fitting_options);
3387 message[MaxTextExtent],
3388 tuple[MaxTextExtent];
3393 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3394 (void) WriteBlobString(image,
3395 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3396 (void) WriteBlobString(image,
3397 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3398 (void) FormatLocaleString(message,MaxTextExtent,
3399 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3400 (double) image->rows);
3401 (void) WriteBlobString(image,message);
3402 GetPixelInfo(image,&pixel);
3403 for (y=0; y < (ssize_t) image->rows; y++)
3405 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3406 if (p == (const Quantum *) NULL)
3408 for (x=0; x < (ssize_t) image->columns; x++)
3410 GetPixelInfoPixel(image,p,&pixel);
3411 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3412 (void) FormatLocaleString(message,MaxTextExtent,
3413 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3414 (double) x,(double) y,tuple);
3415 (void) WriteBlobString(image,message);
3416 p+=GetPixelChannels(image);
3419 (void) WriteBlobString(image,"</svg>\n");
3425 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3426 ExceptionInfo *exception)
3428 #define BezierQuantum 200
3434 keyword[MaxTextExtent],
3435 message[MaxTextExtent],
3436 name[MaxTextExtent],
3438 type[MaxTextExtent];
3480 Open output image file.
3482 assert(image_info != (const ImageInfo *) NULL);
3483 assert(image_info->signature == MagickSignature);
3484 assert(image != (Image *) NULL);
3485 assert(image->signature == MagickSignature);
3486 if (image->debug != MagickFalse)
3487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3488 assert(exception != (ExceptionInfo *) NULL);
3489 assert(exception->signature == MagickSignature);
3490 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3491 if (status == MagickFalse)
3493 value=GetImageArtifact(image,"SVG");
3494 if (value != (char *) NULL)
3496 (void) WriteBlobString(image,value);
3497 (void) CloseBlob(image);
3500 value=GetImageArtifact(image,"MVG");
3501 if (value == (char *) NULL)
3502 return(TraceSVGImage(image,exception));
3506 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3507 (void) WriteBlobString(image,
3508 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3509 (void) WriteBlobString(image,
3510 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3511 (void) FormatLocaleString(message,MaxTextExtent,
3512 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3514 (void) WriteBlobString(image,message);
3516 Allocate primitive info memory.
3519 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3520 sizeof(*primitive_info));
3521 if (primitive_info == (PrimitiveInfo *) NULL)
3522 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3523 GetAffineMatrix(&affine);
3524 token=AcquireString(value);
3528 for (q=(const char *) value; *q != '\0'; )
3531 Interpret graphic primitive.
3533 GetMagickToken(q,&q,keyword);
3534 if (*keyword == '\0')
3536 if (*keyword == '#')
3541 if (active != MagickFalse)
3543 AffineToTransform(image,&affine);
3546 (void) WriteBlobString(image,"<desc>");
3547 (void) WriteBlobString(image,keyword+1);
3548 for ( ; (*q != '\n') && (*q != '\0'); q++)
3551 case '<': (void) WriteBlobString(image,"<"); break;
3552 case '>': (void) WriteBlobString(image,">"); break;
3553 case '&': (void) WriteBlobString(image,"&"); break;
3554 default: (void) WriteBlobByte(image,*q); break;
3556 (void) WriteBlobString(image,"</desc>\n");
3559 primitive_type=UndefinedPrimitive;
3567 if (LocaleCompare("affine",keyword) == 0)
3569 GetMagickToken(q,&q,token);
3570 affine.sx=StringToDouble(token,(char **) NULL);
3571 GetMagickToken(q,&q,token);
3573 GetMagickToken(q,&q,token);
3574 affine.rx=StringToDouble(token,(char **) NULL);
3575 GetMagickToken(q,&q,token);
3577 GetMagickToken(q,&q,token);
3578 affine.ry=StringToDouble(token,(char **) NULL);
3579 GetMagickToken(q,&q,token);
3581 GetMagickToken(q,&q,token);
3582 affine.sy=StringToDouble(token,(char **) NULL);
3583 GetMagickToken(q,&q,token);
3585 GetMagickToken(q,&q,token);
3586 affine.tx=StringToDouble(token,(char **) NULL);
3587 GetMagickToken(q,&q,token);
3589 GetMagickToken(q,&q,token);
3590 affine.ty=StringToDouble(token,(char **) NULL);
3593 if (LocaleCompare("angle",keyword) == 0)
3595 GetMagickToken(q,&q,token);
3596 affine.rx=StringToDouble(token,(char **) NULL);
3597 affine.ry=StringToDouble(token,(char **) NULL);
3600 if (LocaleCompare("arc",keyword) == 0)
3602 primitive_type=ArcPrimitive;
3611 if (LocaleCompare("bezier",keyword) == 0)
3613 primitive_type=BezierPrimitive;
3622 if (LocaleCompare("clip-path",keyword) == 0)
3624 GetMagickToken(q,&q,token);
3625 (void) FormatLocaleString(message,MaxTextExtent,
3626 "clip-path:url(#%s);",token);
3627 (void) WriteBlobString(image,message);
3630 if (LocaleCompare("clip-rule",keyword) == 0)
3632 GetMagickToken(q,&q,token);
3633 (void) FormatLocaleString(message,MaxTextExtent,
3634 "clip-rule:%s;",token);
3635 (void) WriteBlobString(image,message);
3638 if (LocaleCompare("clip-units",keyword) == 0)
3640 GetMagickToken(q,&q,token);
3641 (void) FormatLocaleString(message,MaxTextExtent,
3642 "clipPathUnits=%s;",token);
3643 (void) WriteBlobString(image,message);
3646 if (LocaleCompare("circle",keyword) == 0)
3648 primitive_type=CirclePrimitive;
3651 if (LocaleCompare("color",keyword) == 0)
3653 primitive_type=ColorPrimitive;
3662 if (LocaleCompare("decorate",keyword) == 0)
3664 GetMagickToken(q,&q,token);
3665 (void) FormatLocaleString(message,MaxTextExtent,
3666 "text-decoration:%s;",token);
3667 (void) WriteBlobString(image,message);
3676 if (LocaleCompare("ellipse",keyword) == 0)
3678 primitive_type=EllipsePrimitive;
3687 if (LocaleCompare("fill",keyword) == 0)
3689 GetMagickToken(q,&q,token);
3690 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3692 (void) WriteBlobString(image,message);
3695 if (LocaleCompare("fill-rule",keyword) == 0)
3697 GetMagickToken(q,&q,token);
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "fill-rule:%s;",token);
3700 (void) WriteBlobString(image,message);
3703 if (LocaleCompare("fill-opacity",keyword) == 0)
3705 GetMagickToken(q,&q,token);
3706 (void) FormatLocaleString(message,MaxTextExtent,
3707 "fill-opacity:%s;",token);
3708 (void) WriteBlobString(image,message);
3711 if (LocaleCompare("font-family",keyword) == 0)
3713 GetMagickToken(q,&q,token);
3714 (void) FormatLocaleString(message,MaxTextExtent,
3715 "font-family:%s;",token);
3716 (void) WriteBlobString(image,message);
3719 if (LocaleCompare("font-stretch",keyword) == 0)
3721 GetMagickToken(q,&q,token);
3722 (void) FormatLocaleString(message,MaxTextExtent,
3723 "font-stretch:%s;",token);
3724 (void) WriteBlobString(image,message);
3727 if (LocaleCompare("font-style",keyword) == 0)
3729 GetMagickToken(q,&q,token);
3730 (void) FormatLocaleString(message,MaxTextExtent,
3731 "font-style:%s;",token);
3732 (void) WriteBlobString(image,message);
3735 if (LocaleCompare("font-size",keyword) == 0)
3737 GetMagickToken(q,&q,token);
3738 (void) FormatLocaleString(message,MaxTextExtent,
3739 "font-size:%s;",token);
3740 (void) WriteBlobString(image,message);
3743 if (LocaleCompare("font-weight",keyword) == 0)
3745 GetMagickToken(q,&q,token);
3746 (void) FormatLocaleString(message,MaxTextExtent,
3747 "font-weight:%s;",token);
3748 (void) WriteBlobString(image,message);
3757 if (LocaleCompare("gradient-units",keyword) == 0)
3759 GetMagickToken(q,&q,token);
3762 if (LocaleCompare("text-align",keyword) == 0)
3764 GetMagickToken(q,&q,token);
3765 (void) FormatLocaleString(message,MaxTextExtent,
3766 "text-align %s ",token);
3767 (void) WriteBlobString(image,message);
3770 if (LocaleCompare("text-anchor",keyword) == 0)
3772 GetMagickToken(q,&q,token);
3773 (void) FormatLocaleString(message,MaxTextExtent,
3774 "text-anchor %s ",token);
3775 (void) WriteBlobString(image,message);
3784 if (LocaleCompare("image",keyword) == 0)
3786 GetMagickToken(q,&q,token);
3787 primitive_type=ImagePrimitive;
3796 if (LocaleCompare("line",keyword) == 0)
3798 primitive_type=LinePrimitive;
3807 if (LocaleCompare("matte",keyword) == 0)
3809 primitive_type=MattePrimitive;
3818 if (LocaleCompare("opacity",keyword) == 0)
3820 GetMagickToken(q,&q,token);
3821 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3823 (void) WriteBlobString(image,message);
3832 if (LocaleCompare("path",keyword) == 0)
3834 primitive_type=PathPrimitive;
3837 if (LocaleCompare("point",keyword) == 0)
3839 primitive_type=PointPrimitive;
3842 if (LocaleCompare("polyline",keyword) == 0)
3844 primitive_type=PolylinePrimitive;
3847 if (LocaleCompare("polygon",keyword) == 0)
3849 primitive_type=PolygonPrimitive;
3852 if (LocaleCompare("pop",keyword) == 0)
3854 GetMagickToken(q,&q,token);
3855 if (LocaleCompare("clip-path",token) == 0)
3857 (void) WriteBlobString(image,"</clipPath>\n");
3860 if (LocaleCompare("defs",token) == 0)
3862 (void) WriteBlobString(image,"</defs>\n");
3865 if (LocaleCompare("gradient",token) == 0)
3867 (void) FormatLocaleString(message,MaxTextExtent,
3868 "</%sGradient>\n",type);
3869 (void) WriteBlobString(image,message);
3872 if (LocaleCompare("graphic-context",token) == 0)
3876 ThrowWriterException(DrawError,
3877 "UnbalancedGraphicContextPushPop");
3878 (void) WriteBlobString(image,"</g>\n");
3880 if (LocaleCompare("pattern",token) == 0)
3882 (void) WriteBlobString(image,"</pattern>\n");
3885 if (LocaleCompare("defs",token) == 0)
3886 (void) WriteBlobString(image,"</g>\n");
3889 if (LocaleCompare("push",keyword) == 0)
3891 GetMagickToken(q,&q,token);
3892 if (LocaleCompare("clip-path",token) == 0)
3894 GetMagickToken(q,&q,token);
3895 (void) FormatLocaleString(message,MaxTextExtent,
3896 "<clipPath id=\"%s\">\n",token);
3897 (void) WriteBlobString(image,message);
3900 if (LocaleCompare("defs",token) == 0)
3902 (void) WriteBlobString(image,"<defs>\n");
3905 if (LocaleCompare("gradient",token) == 0)
3907 GetMagickToken(q,&q,token);
3908 (void) CopyMagickString(name,token,MaxTextExtent);
3909 GetMagickToken(q,&q,token);
3910 (void) CopyMagickString(type,token,MaxTextExtent);
3911 GetMagickToken(q,&q,token);
3912 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3913 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3914 GetMagickToken(q,&q,token);
3916 GetMagickToken(q,&q,token);
3917 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
3918 svg_info.element.cy=StringToDouble(token,(char **) NULL);
3919 GetMagickToken(q,&q,token);
3921 GetMagickToken(q,&q,token);
3922 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
3923 svg_info.element.major=StringToDouble(token,
3925 GetMagickToken(q,&q,token);
3927 GetMagickToken(q,&q,token);
3928 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
3929 svg_info.element.minor=StringToDouble(token,
3931 (void) FormatLocaleString(message,MaxTextExtent,
3932 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3933 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3934 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3935 if (LocaleCompare(type,"radial") == 0)
3937 GetMagickToken(q,&q,token);
3939 GetMagickToken(q,&q,token);
3940 svg_info.element.angle=StringToDouble(token,
3942 (void) FormatLocaleString(message,MaxTextExtent,
3943 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3944 "fx=\"%g\" fy=\"%g\">\n",type,name,
3945 svg_info.element.cx,svg_info.element.cy,
3946 svg_info.element.angle,svg_info.element.major,
3947 svg_info.element.minor);
3949 (void) WriteBlobString(image,message);
3952 if (LocaleCompare("graphic-context",token) == 0)
3957 AffineToTransform(image,&affine);
3960 (void) WriteBlobString(image,"<g style=\"");
3963 if (LocaleCompare("pattern",token) == 0)
3965 GetMagickToken(q,&q,token);
3966 (void) CopyMagickString(name,token,MaxTextExtent);
3967 GetMagickToken(q,&q,token);
3968 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
3969 GetMagickToken(q,&q,token);
3971 GetMagickToken(q,&q,token);
3972 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
3973 GetMagickToken(q,&q,token);
3975 GetMagickToken(q,&q,token);
3976 svg_info.bounds.width=StringToDouble(token,
3978 GetMagickToken(q,&q,token);
3980 GetMagickToken(q,&q,token);
3981 svg_info.bounds.height=StringToDouble(token,
3983 (void) FormatLocaleString(message,MaxTextExtent,
3984 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3985 "height=\"%g\">\n",name,svg_info.bounds.x,
3986 svg_info.bounds.y,svg_info.bounds.width,
3987 svg_info.bounds.height);
3988 (void) WriteBlobString(image,message);
3999 if (LocaleCompare("rectangle",keyword) == 0)
4001 primitive_type=RectanglePrimitive;
4004 if (LocaleCompare("roundRectangle",keyword) == 0)
4006 primitive_type=RoundRectanglePrimitive;
4009 if (LocaleCompare("rotate",keyword) == 0)
4011 GetMagickToken(q,&q,token);
4012 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4014 (void) WriteBlobString(image,message);
4023 if (LocaleCompare("scale",keyword) == 0)
4025 GetMagickToken(q,&q,token);
4026 affine.sx=StringToDouble(token,(char **) NULL);
4027 GetMagickToken(q,&q,token);
4029 GetMagickToken(q,&q,token);
4030 affine.sy=StringToDouble(token,(char **) NULL);
4033 if (LocaleCompare("skewX",keyword) == 0)
4035 GetMagickToken(q,&q,token);
4036 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4038 (void) WriteBlobString(image,message);
4041 if (LocaleCompare("skewY",keyword) == 0)
4043 GetMagickToken(q,&q,token);
4044 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4046 (void) WriteBlobString(image,message);
4049 if (LocaleCompare("stop-color",keyword) == 0)
4052 color[MaxTextExtent];
4054 GetMagickToken(q,&q,token);
4055 (void) CopyMagickString(color,token,MaxTextExtent);
4056 GetMagickToken(q,&q,token);
4057 (void) FormatLocaleString(message,MaxTextExtent,
4058 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4059 (void) WriteBlobString(image,message);
4062 if (LocaleCompare("stroke",keyword) == 0)
4064 GetMagickToken(q,&q,token);
4065 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4067 (void) WriteBlobString(image,message);
4070 if (LocaleCompare("stroke-antialias",keyword) == 0)
4072 GetMagickToken(q,&q,token);
4073 (void) FormatLocaleString(message,MaxTextExtent,
4074 "stroke-antialias:%s;",token);
4075 (void) WriteBlobString(image,message);
4078 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4086 GetMagickToken(p,&p,token);
4087 for (k=0; IsPoint(token); k++)
4088 GetMagickToken(p,&p,token);
4089 (void) WriteBlobString(image,"stroke-dasharray:");
4090 for (j=0; j < k; j++)
4092 GetMagickToken(q,&q,token);
4093 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4095 (void) WriteBlobString(image,message);
4097 (void) WriteBlobString(image,";");
4100 GetMagickToken(q,&q,token);
4101 (void) FormatLocaleString(message,MaxTextExtent,
4102 "stroke-dasharray:%s;",token);
4103 (void) WriteBlobString(image,message);
4106 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4108 GetMagickToken(q,&q,token);
4109 (void) FormatLocaleString(message,MaxTextExtent,
4110 "stroke-dashoffset:%s;",token);
4111 (void) WriteBlobString(image,message);
4114 if (LocaleCompare("stroke-linecap",keyword) == 0)
4116 GetMagickToken(q,&q,token);
4117 (void) FormatLocaleString(message,MaxTextExtent,
4118 "stroke-linecap:%s;",token);
4119 (void) WriteBlobString(image,message);
4122 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4124 GetMagickToken(q,&q,token);
4125 (void) FormatLocaleString(message,MaxTextExtent,
4126 "stroke-linejoin:%s;",token);
4127 (void) WriteBlobString(image,message);
4130 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4132 GetMagickToken(q,&q,token);
4133 (void) FormatLocaleString(message,MaxTextExtent,
4134 "stroke-miterlimit:%s;",token);
4135 (void) WriteBlobString(image,message);
4138 if (LocaleCompare("stroke-opacity",keyword) == 0)
4140 GetMagickToken(q,&q,token);
4141 (void) FormatLocaleString(message,MaxTextExtent,
4142 "stroke-opacity:%s;",token);
4143 (void) WriteBlobString(image,message);
4146 if (LocaleCompare("stroke-width",keyword) == 0)
4148 GetMagickToken(q,&q,token);
4149 (void) FormatLocaleString(message,MaxTextExtent,
4150 "stroke-width:%s;",token);
4151 (void) WriteBlobString(image,message);
4160 if (LocaleCompare("text",keyword) == 0)
4162 primitive_type=TextPrimitive;
4165 if (LocaleCompare("text-antialias",keyword) == 0)
4167 GetMagickToken(q,&q,token);
4168 (void) FormatLocaleString(message,MaxTextExtent,
4169 "text-antialias:%s;",token);
4170 (void) WriteBlobString(image,message);
4173 if (LocaleCompare("tspan",keyword) == 0)
4175 primitive_type=TextPrimitive;
4178 if (LocaleCompare("translate",keyword) == 0)
4180 GetMagickToken(q,&q,token);
4181 affine.tx=StringToDouble(token,(char **) NULL);
4182 GetMagickToken(q,&q,token);
4184 GetMagickToken(q,&q,token);
4185 affine.ty=StringToDouble(token,(char **) NULL);
4194 if (LocaleCompare("viewbox",keyword) == 0)
4196 GetMagickToken(q,&q,token);
4198 GetMagickToken(q,&q,token);
4199 GetMagickToken(q,&q,token);
4201 GetMagickToken(q,&q,token);
4202 GetMagickToken(q,&q,token);
4204 GetMagickToken(q,&q,token);
4205 GetMagickToken(q,&q,token);
4217 if (status == MagickFalse)
4219 if (primitive_type == UndefinedPrimitive)
4222 Parse the primitive attributes.
4226 for (x=0; *q != '\0'; x++)
4231 if (IsPoint(q) == MagickFalse)
4233 GetMagickToken(q,&q,token);
4234 point.x=StringToDouble(token,(char **) NULL);
4235 GetMagickToken(q,&q,token);
4237 GetMagickToken(q,&q,token);
4238 point.y=StringToDouble(token,(char **) NULL);
4239 GetMagickToken(q,(const char **) NULL,token);
4241 GetMagickToken(q,&q,token);
4242 primitive_info[i].primitive=primitive_type;
4243 primitive_info[i].point=point;
4244 primitive_info[i].coordinates=0;
4245 primitive_info[i].method=FloodfillMethod;
4247 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4249 number_points+=6*BezierQuantum+360;
4250 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4251 number_points,sizeof(*primitive_info));
4252 if (primitive_info == (PrimitiveInfo *) NULL)
4254 (void) ThrowMagickException(exception,GetMagickModule(),
4255 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4259 primitive_info[j].primitive=primitive_type;
4260 primitive_info[j].coordinates=x;
4261 primitive_info[j].method=FloodfillMethod;
4262 primitive_info[j].text=(char *) NULL;
4265 AffineToTransform(image,&affine);
4269 switch (primitive_type)
4271 case PointPrimitive:
4274 if (primitive_info[j].coordinates != 1)
4283 if (primitive_info[j].coordinates != 2)
4288 (void) FormatLocaleString(message,MaxTextExtent,
4289 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4290 primitive_info[j].point.x,primitive_info[j].point.y,
4291 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4292 (void) WriteBlobString(image,message);
4295 case RectanglePrimitive:
4297 if (primitive_info[j].coordinates != 2)
4302 (void) FormatLocaleString(message,MaxTextExtent,
4303 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4304 primitive_info[j].point.x,primitive_info[j].point.y,
4305 primitive_info[j+1].point.x-primitive_info[j].point.x,
4306 primitive_info[j+1].point.y-primitive_info[j].point.y);
4307 (void) WriteBlobString(image,message);
4310 case RoundRectanglePrimitive:
4312 if (primitive_info[j].coordinates != 3)
4317 (void) FormatLocaleString(message,MaxTextExtent,
4318 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4319 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4320 primitive_info[j].point.y,primitive_info[j+1].point.x-
4321 primitive_info[j].point.x,primitive_info[j+1].point.y-
4322 primitive_info[j].point.y,primitive_info[j+2].point.x,
4323 primitive_info[j+2].point.y);
4324 (void) WriteBlobString(image,message);
4329 if (primitive_info[j].coordinates != 3)
4336 case EllipsePrimitive:
4338 if (primitive_info[j].coordinates != 3)
4343 (void) FormatLocaleString(message,MaxTextExtent,
4344 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4345 primitive_info[j].point.x,primitive_info[j].point.y,
4346 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4347 (void) WriteBlobString(image,message);
4350 case CirclePrimitive:
4356 if (primitive_info[j].coordinates != 2)
4361 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4362 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4363 (void) FormatLocaleString(message,MaxTextExtent,
4364 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4365 primitive_info[j].point.x,primitive_info[j].point.y,
4367 (void) WriteBlobString(image,message);
4370 case PolylinePrimitive:
4372 if (primitive_info[j].coordinates < 2)
4377 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4378 (void) WriteBlobString(image,message);
4379 length=strlen(message);
4382 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4383 primitive_info[j].point.x,primitive_info[j].point.y);
4384 length+=strlen(message);
4387 (void) WriteBlobString(image,"\n ");
4388 length=strlen(message)+5;
4390 (void) WriteBlobString(image,message);
4392 (void) WriteBlobString(image,"\"/>\n");
4395 case PolygonPrimitive:
4397 if (primitive_info[j].coordinates < 3)
4402 primitive_info[i]=primitive_info[j];
4403 primitive_info[i].coordinates=0;
4404 primitive_info[j].coordinates++;
4406 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4407 (void) WriteBlobString(image,message);
4408 length=strlen(message);
4411 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4412 primitive_info[j].point.x,primitive_info[j].point.y);
4413 length+=strlen(message);
4416 (void) WriteBlobString(image,"\n ");
4417 length=strlen(message)+5;
4419 (void) WriteBlobString(image,message);
4421 (void) WriteBlobString(image,"\"/>\n");
4424 case BezierPrimitive:
4426 if (primitive_info[j].coordinates < 3)
4438 GetMagickToken(q,&q,token);
4439 number_attributes=1;
4440 for (p=token; *p != '\0'; p++)
4441 if (isalpha((int) *p))
4442 number_attributes++;
4443 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4445 number_points+=6*BezierQuantum*number_attributes;
4446 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4447 number_points,sizeof(*primitive_info));
4448 if (primitive_info == (PrimitiveInfo *) NULL)
4450 (void) ThrowMagickException(exception,GetMagickModule(),
4451 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4456 (void) WriteBlobString(image," <path d=\"");
4457 (void) WriteBlobString(image,token);
4458 (void) WriteBlobString(image,"\"/>\n");
4461 case ColorPrimitive:
4462 case MattePrimitive:
4464 if (primitive_info[j].coordinates != 1)
4469 GetMagickToken(q,&q,token);
4470 if (LocaleCompare("point",token) == 0)
4471 primitive_info[j].method=PointMethod;
4472 if (LocaleCompare("replace",token) == 0)
4473 primitive_info[j].method=ReplaceMethod;
4474 if (LocaleCompare("floodfill",token) == 0)
4475 primitive_info[j].method=FloodfillMethod;
4476 if (LocaleCompare("filltoborder",token) == 0)
4477 primitive_info[j].method=FillToBorderMethod;
4478 if (LocaleCompare("reset",token) == 0)
4479 primitive_info[j].method=ResetMethod;
4487 if (primitive_info[j].coordinates != 1)
4492 GetMagickToken(q,&q,token);
4493 (void) FormatLocaleString(message,MaxTextExtent,
4494 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4495 primitive_info[j].point.y);
4496 (void) WriteBlobString(image,message);
4497 for (p=token; *p != '\0'; p++)
4500 case '<': (void) WriteBlobString(image,"<"); break;
4501 case '>': (void) WriteBlobString(image,">"); break;
4502 case '&': (void) WriteBlobString(image,"&"); break;
4503 default: (void) WriteBlobByte(image,*p); break;
4505 (void) WriteBlobString(image,"</text>\n");
4508 case ImagePrimitive:
4510 if (primitive_info[j].coordinates != 2)
4515 GetMagickToken(q,&q,token);
4516 (void) FormatLocaleString(message,MaxTextExtent,
4517 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4518 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4519 primitive_info[j].point.y,primitive_info[j+1].point.x,
4520 primitive_info[j+1].point.y,token);
4521 (void) WriteBlobString(image,message);
4525 if (primitive_info == (PrimitiveInfo *) NULL)
4527 primitive_info[i].primitive=UndefinedPrimitive;
4528 if (status == MagickFalse)
4531 (void) WriteBlobString(image,"</svg>\n");
4533 Relinquish resources.
4535 token=DestroyString(token);
4536 if (primitive_info != (PrimitiveInfo *) NULL)
4537 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4538 (void) CloseBlob(image);