2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "magick/studio.h"
44 #include "magick/annotate.h"
45 #include "magick/artifact.h"
46 #include "magick/blob.h"
47 #include "magick/blob-private.h"
48 #include "magick/cache.h"
49 #include "magick/constitute.h"
50 #include "magick/composite-private.h"
51 #include "magick/draw.h"
52 #include "magick/exception.h"
53 #include "magick/exception-private.h"
54 #include "magick/gem.h"
55 #include "magick/image.h"
56 #include "magick/image-private.h"
57 #include "magick/list.h"
58 #include "magick/log.h"
59 #include "magick/magick.h"
60 #include "magick/memory_.h"
61 #include "magick/monitor.h"
62 #include "magick/monitor-private.h"
63 #include "magick/quantum-private.h"
64 #include "magick/pixel-private.h"
65 #include "magick/property.h"
66 #include "magick/resource_.h"
67 #include "magick/static.h"
68 #include "magick/string_.h"
69 #include "magick/module.h"
70 #include "magick/token.h"
71 #include "magick/utility.h"
72 #if defined(MAGICKCORE_XML_DELEGATE)
73 # if defined(__WINDOWS__)
74 # if defined(__MINGW32__)
77 # include <win32config.h>
80 # include <libxml/parser.h>
81 # include <libxml/xmlmemory.h>
82 # include <libxml/parserInternals.h>
83 # include <libxml/xmlerror.h>
86 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
87 #include "autotrace/autotrace.h"
90 #if defined(MAGICKCORE_RSVG_DELEGATE)
91 #include "librsvg/rsvg.h"
92 #if defined(MAGICKCORE_CAIRO_DELEGATE)
93 #include "librsvg/rsvg-cairo.h"
95 #include "librsvg/librsvg-features.h"
101 #define MVGPrintf (void) fprintf
104 Typedef declarations.
106 typedef struct _BoundingBox
115 typedef struct _ElementInfo
125 typedef struct _SVGInfo
179 #if defined(MAGICKCORE_XML_DELEGATE)
189 Forward declarations.
191 static MagickBooleanType
192 WriteSVGImage(const ImageInfo *,Image *);
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 % IsSVG()() returns MagickTrue if the image format type, identified by the
206 % magick string, is SVG.
208 % The format of the IsSVG method is:
210 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
212 % A description of each parameter follows:
214 % o magick: compare image format pattern against these bytes.
216 % o length: Specifies the length of the magick string.
219 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
223 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
228 #if defined(MAGICKCORE_XML_DELEGATE)
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 % R e a d S V G I m a g e %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
241 % allocates the memory necessary for the new Image structure and returns a
242 % pointer to the new image.
244 % The format of the ReadSVGImage method is:
246 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
248 % A description of each parameter follows:
250 % o image_info: the image info.
252 % o exception: return any errors or warnings in this structure.
256 static SVGInfo *AcquireSVGInfo(void)
261 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
262 if (svg_info == (SVGInfo *) NULL)
263 return((SVGInfo *) NULL);
264 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
265 svg_info->text=AcquireString("");
266 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
267 if (svg_info->scale == (double *) NULL)
268 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
269 GetAffineMatrix(&svg_info->affine);
270 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
274 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
276 if (svg_info->text != (char *) NULL)
277 svg_info->text=DestroyString(svg_info->text);
278 if (svg_info->scale != (double *) NULL)
279 svg_info->scale=(double *) (svg_info->scale);
280 if (svg_info->title != (char *) NULL)
281 svg_info->title=DestroyString(svg_info->title);
282 if (svg_info->comment != (char *) NULL)
283 svg_info->comment=DestroyString(svg_info->comment);
284 return((SVGInfo *) RelinquishMagickMemory(svg_info));
287 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
291 token[MaxTextExtent];
299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
300 assert(string != (const char *) NULL);
301 p=(const char *) string;
302 GetMagickToken(p,&p,token);
304 if (strchr(token,'%') != (char *) NULL)
312 if (svg_info->view_box.width == 0.0)
314 return(svg_info->view_box.width*value/100.0);
318 if (svg_info->view_box.height == 0.0)
320 return(svg_info->view_box.height*value/100.0);
322 alpha=value-svg_info->view_box.width;
323 beta=value-svg_info->view_box.height;
324 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
326 GetMagickToken(p,&p,token);
327 if (LocaleNCompare(token,"cm",2) == 0)
328 return(DefaultResolution*svg_info->scale[0]/2.54*value);
329 if (LocaleNCompare(token,"em",2) == 0)
330 return(svg_info->pointsize*value);
331 if (LocaleNCompare(token,"ex",2) == 0)
332 return(svg_info->pointsize*value/2.0);
333 if (LocaleNCompare(token,"in",2) == 0)
334 return(DefaultResolution*svg_info->scale[0]*value);
335 if (LocaleNCompare(token,"mm",2) == 0)
336 return(DefaultResolution*svg_info->scale[0]/25.4*value);
337 if (LocaleNCompare(token,"pc",2) == 0)
338 return(DefaultResolution*svg_info->scale[0]/6.0*value);
339 if (LocaleNCompare(token,"pt",2) == 0)
340 return(svg_info->scale[0]*value);
341 if (LocaleNCompare(token,"px",2) == 0)
346 static void StripStyleTokens(char *message)
355 assert(message != (char *) NULL);
356 if (*message == '\0')
358 length=strlen(message);
360 while (isspace((int) ((unsigned char) *p)) != 0)
363 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
365 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
367 StripString(message);
370 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
382 svg_info=(SVGInfo *) context;
384 if (style == (const char *) NULL)
385 return((char **) NULL);
386 text=AcquireString(style);
387 (void) SubstituteString(&text,":","\n");
388 (void) SubstituteString(&text,";","\n");
389 tokens=StringToList(text);
390 text=DestroyString(text);
391 for (i=0; tokens[i] != (char *) NULL; i++)
392 StripStyleTokens(tokens[i]);
397 static char **GetTransformTokens(void *context,const char *text,
413 svg_info=(SVGInfo *) context;
415 if (text == (const char *) NULL)
416 return((char **) NULL);
418 Determine the number of arguments.
420 for (p=text; *p != '\0'; p++)
425 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
426 if (tokens == (char **) NULL)
428 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
429 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
430 return((char **) NULL);
433 Convert string to an ASCII list.
437 for (q=p; *q != '\0'; q++)
439 if ((*q != '(') && (*q != ')') && (*q != '\0'))
441 tokens[i]=AcquireString(p);
442 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
443 StripString(tokens[i++]);
446 tokens[i]=AcquireString(p);
447 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
448 StripString(tokens[i++]);
449 tokens[i]=(char *) NULL;
453 #if defined(__cplusplus) || defined(c_plusplus)
457 static int SVGIsStandalone(void *context)
463 Is this document tagged standalone?
465 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
466 svg_info=(SVGInfo *) context;
467 return(svg_info->document->standalone == 1);
470 static int SVGHasInternalSubset(void *context)
476 Does this document has an internal subset?
478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
479 " SAX.SVGHasInternalSubset()");
480 svg_info=(SVGInfo *) context;
481 return(svg_info->document->intSubset != NULL);
484 static int SVGHasExternalSubset(void *context)
490 Does this document has an external subset?
492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
493 " SAX.SVGHasExternalSubset()");
494 svg_info=(SVGInfo *) context;
495 return(svg_info->document->extSubset != NULL);
498 static void SVGInternalSubset(void *context,const xmlChar *name,
499 const xmlChar *external_id,const xmlChar *system_id)
505 Does this document has an internal subset?
507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
508 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
509 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
510 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
511 svg_info=(SVGInfo *) context;
512 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
515 static xmlParserInputPtr SVGResolveEntity(void *context,
516 const xmlChar *public_id,const xmlChar *system_id)
525 Special entity resolver, better left to the parser, it has more
526 context than the application layer. The default behaviour is to
527 not resolve the entities, in that case the ENTITY_REF nodes are
528 built in the structure (and the parameter values).
530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
531 " SAX.resolveEntity(%s, %s)",
532 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
533 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
534 svg_info=(SVGInfo *) context;
535 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
536 public_id,svg_info->parser);
540 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
546 Get an entity by name.
548 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
550 svg_info=(SVGInfo *) context;
551 return(xmlGetDocEntity(svg_info->document,name));
554 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
560 Get a parameter entity by name.
562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
563 " SAX.getParameterEntity(%s)",name);
564 svg_info=(SVGInfo *) context;
565 return(xmlGetParameterEntity(svg_info->document,name));
568 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
569 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
575 An entity definition has been parsed.
577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
578 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
579 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
580 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
581 svg_info=(SVGInfo *) context;
582 if (svg_info->parser->inSubset == 1)
583 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
586 if (svg_info->parser->inSubset == 2)
587 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
591 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
592 const xmlChar *name,int type,int value,const xmlChar *default_value,
593 xmlEnumerationPtr tree)
606 An attribute definition has been parsed.
608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
609 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
611 svg_info=(SVGInfo *) context;
612 fullname=(xmlChar *) NULL;
613 prefix=(xmlChar *) NULL;
614 parser=svg_info->parser;
615 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
616 if (parser->inSubset == 1)
617 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
618 element,fullname,prefix,(xmlAttributeType) type,
619 (xmlAttributeDefault) value,default_value,tree);
621 if (parser->inSubset == 2)
622 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
623 element,fullname,prefix,(xmlAttributeType) type,
624 (xmlAttributeDefault) value,default_value,tree);
625 if (prefix != (xmlChar *) NULL)
627 if (fullname != (xmlChar *) NULL)
631 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
632 xmlElementContentPtr content)
641 An element definition has been parsed.
643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
644 " SAX.elementDecl(%s, %d, ...)",name,type);
645 svg_info=(SVGInfo *) context;
646 parser=svg_info->parser;
647 if (parser->inSubset == 1)
648 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
649 name,(xmlElementTypeVal) type,content);
651 if (parser->inSubset == 2)
652 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
653 name,(xmlElementTypeVal) type,content);
656 static void SVGNotationDeclaration(void *context,const xmlChar *name,
657 const xmlChar *public_id,const xmlChar *system_id)
666 What to do when a notation declaration has been parsed.
668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
669 " SAX.notationDecl(%s, %s, %s)",name,
670 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
671 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
672 svg_info=(SVGInfo *) context;
673 parser=svg_info->parser;
674 if (parser->inSubset == 1)
675 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
676 name,public_id,system_id);
678 if (parser->inSubset == 2)
679 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
680 name,public_id,system_id);
683 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
684 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
690 What to do when an unparsed entity declaration is parsed.
692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
693 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
694 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
695 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
696 svg_info=(SVGInfo *) context;
697 (void) xmlAddDocEntity(svg_info->document,name,
698 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
702 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
708 Receive the document locator at startup, actually xmlDefaultSAXLocator.
711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
712 " SAX.setDocumentLocator()");
713 svg_info=(SVGInfo *) context;
716 static void SVGStartDocument(void *context)
725 Called when the document start being processed.
727 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
728 svg_info=(SVGInfo *) context;
729 GetExceptionInfo(svg_info->exception);
730 parser=svg_info->parser;
731 svg_info->document=xmlNewDoc(parser->version);
732 if (svg_info->document == (xmlDocPtr) NULL)
734 if (parser->encoding == NULL)
735 svg_info->document->encoding=(const xmlChar *) NULL;
737 svg_info->document->encoding=xmlStrdup(parser->encoding);
738 svg_info->document->standalone=parser->standalone;
741 static void SVGEndDocument(void *context)
747 Called when the document end has been detected.
749 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
750 svg_info=(SVGInfo *) context;
751 if (svg_info->offset != (char *) NULL)
752 svg_info->offset=DestroyString(svg_info->offset);
753 if (svg_info->stop_color != (char *) NULL)
754 svg_info->stop_color=DestroyString(svg_info->stop_color);
755 if (svg_info->scale != (double *) NULL)
756 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
757 if (svg_info->text != (char *) NULL)
758 svg_info->text=DestroyString(svg_info->text);
759 if (svg_info->vertices != (char *) NULL)
760 svg_info->vertices=DestroyString(svg_info->vertices);
761 if (svg_info->url != (char *) NULL)
762 svg_info->url=DestroyString(svg_info->url);
763 #if defined(MAGICKCORE_XML_DELEGATE)
764 if (svg_info->document != (xmlDocPtr) NULL)
766 xmlFreeDoc(svg_info->document);
767 svg_info->document=(xmlDocPtr) NULL;
772 static void SVGStartElement(void *context,const xmlChar *name,
773 const xmlChar **attributes)
778 token[MaxTextExtent],
798 Called when an opening tag has been processed.
800 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
802 svg_info=(SVGInfo *) context;
804 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
805 svg_info->n+1UL,sizeof(*svg_info->scale));
806 if (svg_info->scale == (double *) NULL)
808 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
809 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
812 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
813 color=AcquireString("none");
814 units=AcquireString("userSpaceOnUse");
815 value=(const char *) NULL;
816 if (attributes != (const xmlChar **) NULL)
817 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
819 keyword=(const char *) attributes[i];
820 value=(const char *) attributes[i+1];
826 if (LocaleCompare(keyword,"cx") == 0)
828 svg_info->element.cx=
829 GetUserSpaceCoordinateValue(svg_info,1,value);
832 if (LocaleCompare(keyword,"cy") == 0)
834 svg_info->element.cy=
835 GetUserSpaceCoordinateValue(svg_info,-1,value);
843 if (LocaleCompare(keyword,"fx") == 0)
845 svg_info->element.major=
846 GetUserSpaceCoordinateValue(svg_info,1,value);
849 if (LocaleCompare(keyword,"fy") == 0)
851 svg_info->element.minor=
852 GetUserSpaceCoordinateValue(svg_info,-1,value);
860 if (LocaleCompare(keyword,"height") == 0)
862 svg_info->bounds.height=
863 GetUserSpaceCoordinateValue(svg_info,-1,value);
871 if (LocaleCompare(keyword,"id") == 0)
873 (void) CopyMagickString(id,value,MaxTextExtent);
881 if (LocaleCompare(keyword,"r") == 0)
883 svg_info->element.angle=
884 GetUserSpaceCoordinateValue(svg_info,0,value);
892 if (LocaleCompare(keyword,"width") == 0)
894 svg_info->bounds.width=
895 GetUserSpaceCoordinateValue(svg_info,1,value);
903 if (LocaleCompare(keyword,"x") == 0)
905 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
909 if (LocaleCompare(keyword,"x1") == 0)
911 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
915 if (LocaleCompare(keyword,"x2") == 0)
917 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
926 if (LocaleCompare(keyword,"y") == 0)
928 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
932 if (LocaleCompare(keyword,"y1") == 0)
934 svg_info->segment.y1=
935 GetUserSpaceCoordinateValue(svg_info,-1,value);
938 if (LocaleCompare(keyword,"y2") == 0)
940 svg_info->segment.y2=
941 GetUserSpaceCoordinateValue(svg_info,-1,value);
955 if (LocaleCompare((const char *) name,"circle") == 0)
957 MVGPrintf(svg_info->file,"push graphic-context\n");
960 if (LocaleCompare((const char *) name,"clipPath") == 0)
962 MVGPrintf(svg_info->file,"push clip-path '%s'\n",id);
970 if (LocaleCompare((const char *) name,"defs") == 0)
972 MVGPrintf(svg_info->file,"push defs\n");
980 if (LocaleCompare((const char *) name,"ellipse") == 0)
982 MVGPrintf(svg_info->file,"push graphic-context\n");
990 if (LocaleCompare((const char *) name,"g") == 0)
992 MVGPrintf(svg_info->file,"push graphic-context\n");
1000 if (LocaleCompare((const char *) name,"image") == 0)
1002 MVGPrintf(svg_info->file,"push graphic-context\n");
1010 if (LocaleCompare((const char *) name,"line") == 0)
1012 MVGPrintf(svg_info->file,"push graphic-context\n");
1015 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1017 MVGPrintf(svg_info->file,"push gradient '%s' linear %g,%g %g,%g\n",id,
1018 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1019 svg_info->segment.y2);
1027 if (LocaleCompare((const char *) name,"path") == 0)
1029 MVGPrintf(svg_info->file,"push graphic-context\n");
1032 if (LocaleCompare((const char *) name,"pattern") == 0)
1034 MVGPrintf(svg_info->file,"push pattern '%s' %g,%g %g,%g\n",id,
1035 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1036 svg_info->bounds.height);
1039 if (LocaleCompare((const char *) name,"polygon") == 0)
1041 MVGPrintf(svg_info->file,"push graphic-context\n");
1044 if (LocaleCompare((const char *) name,"polyline") == 0)
1046 MVGPrintf(svg_info->file,"push graphic-context\n");
1054 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1056 MVGPrintf(svg_info->file,"push gradient '%s' radial %g,%g %g,%g %g\n",
1057 id,svg_info->element.cx,svg_info->element.cy,
1058 svg_info->element.major,svg_info->element.minor,
1059 svg_info->element.angle);
1062 if (LocaleCompare((const char *) name,"rect") == 0)
1064 MVGPrintf(svg_info->file,"push graphic-context\n");
1072 if (LocaleCompare((const char *) name,"svg") == 0)
1074 MVGPrintf(svg_info->file,"push graphic-context\n");
1082 if (LocaleCompare((const char *) name,"text") == 0)
1084 MVGPrintf(svg_info->file,"push graphic-context\n");
1087 if (LocaleCompare((const char *) name,"tspan") == 0)
1089 if (*svg_info->text != '\0')
1100 text=EscapeString(svg_info->text,'\'');
1101 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x-
1102 svg_info->center.x,svg_info->bounds.y-svg_info->center.y,text);
1103 text=DestroyString(text);
1104 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1105 draw_info->pointsize=svg_info->pointsize;
1106 draw_info->text=AcquireString(svg_info->text);
1107 (void) ConcatenateString(&draw_info->text," ");
1108 GetTypeMetrics(svg_info->image,draw_info,&metrics);
1109 svg_info->bounds.x+=metrics.width;
1110 draw_info=DestroyDrawInfo(draw_info);
1111 *svg_info->text='\0';
1113 MVGPrintf(svg_info->file,"push graphic-context\n");
1121 if (attributes != (const xmlChar **) NULL)
1122 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1124 keyword=(const char *) attributes[i];
1125 value=(const char *) attributes[i+1];
1126 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1127 " %s = %s",keyword,value);
1133 if (LocaleCompare(keyword,"angle") == 0)
1135 MVGPrintf(svg_info->file,"angle %g\n",
1136 GetUserSpaceCoordinateValue(svg_info,0,value));
1144 if (LocaleCompare(keyword,"clip-path") == 0)
1146 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1149 if (LocaleCompare(keyword,"clip-rule") == 0)
1151 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1154 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1156 (void) CloneString(&units,value);
1157 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1160 if (LocaleCompare(keyword,"color") == 0)
1162 (void) CloneString(&color,value);
1165 if (LocaleCompare(keyword,"cx") == 0)
1167 svg_info->element.cx=
1168 GetUserSpaceCoordinateValue(svg_info,1,value);
1171 if (LocaleCompare(keyword,"cy") == 0)
1173 svg_info->element.cy=
1174 GetUserSpaceCoordinateValue(svg_info,-1,value);
1182 if (LocaleCompare(keyword,"d") == 0)
1184 (void) CloneString(&svg_info->vertices,value);
1187 if (LocaleCompare(keyword,"dx") == 0)
1189 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1192 if (LocaleCompare(keyword,"dy") == 0)
1194 svg_info->bounds.y+=
1195 GetUserSpaceCoordinateValue(svg_info,-1,value);
1203 if (LocaleCompare(keyword,"fill") == 0)
1205 if (LocaleCompare(value,"currentColor") == 0)
1207 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1210 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1213 if (LocaleCompare(keyword,"fillcolor") == 0)
1215 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1218 if (LocaleCompare(keyword,"fill-rule") == 0)
1220 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1223 if (LocaleCompare(keyword,"fill-opacity") == 0)
1225 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1228 if (LocaleCompare(keyword,"font-family") == 0)
1230 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1233 if (LocaleCompare(keyword,"font-stretch") == 0)
1235 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1238 if (LocaleCompare(keyword,"font-style") == 0)
1240 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1243 if (LocaleCompare(keyword,"font-size") == 0)
1245 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1246 MVGPrintf(svg_info->file,"font-size %g\n",svg_info->pointsize);
1249 if (LocaleCompare(keyword,"font-weight") == 0)
1251 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1259 if (LocaleCompare(keyword,"gradientTransform") == 0)
1266 GetAffineMatrix(&transform);
1267 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1268 tokens=GetTransformTokens(context,value,&number_tokens);
1269 for (j=0; j < (number_tokens-1); j+=2)
1271 keyword=(char *) tokens[j];
1272 if (keyword == (char *) NULL)
1274 value=(char *) tokens[j+1];
1275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1276 " %s: %s",keyword,value);
1278 GetAffineMatrix(&affine);
1284 if (LocaleCompare(keyword,"matrix") == 0)
1286 p=(const char *) value;
1287 GetMagickToken(p,&p,token);
1288 affine.sx=atof(value);
1289 GetMagickToken(p,&p,token);
1291 GetMagickToken(p,&p,token);
1292 affine.rx=atof(token);
1293 GetMagickToken(p,&p,token);
1295 GetMagickToken(p,&p,token);
1296 affine.ry=atof(token);
1297 GetMagickToken(p,&p,token);
1299 GetMagickToken(p,&p,token);
1300 affine.sy=atof(token);
1301 GetMagickToken(p,&p,token);
1303 GetMagickToken(p,&p,token);
1304 affine.tx=atof(token);
1305 GetMagickToken(p,&p,token);
1307 GetMagickToken(p,&p,token);
1308 affine.ty=atof(token);
1316 if (LocaleCompare(keyword,"rotate") == 0)
1321 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1322 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1323 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1324 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1325 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1333 if (LocaleCompare(keyword,"scale") == 0)
1335 for (p=(const char *) value; *p != '\0'; p++)
1336 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1339 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1340 affine.sy=affine.sx;
1343 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1344 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1347 if (LocaleCompare(keyword,"skewX") == 0)
1349 affine.sx=svg_info->affine.sx;
1350 affine.ry=tan(DegreesToRadians(fmod(
1351 GetUserSpaceCoordinateValue(svg_info,1,value),
1353 affine.sy=svg_info->affine.sy;
1356 if (LocaleCompare(keyword,"skewY") == 0)
1358 affine.sx=svg_info->affine.sx;
1359 affine.rx=tan(DegreesToRadians(fmod(
1360 GetUserSpaceCoordinateValue(svg_info,-1,value),
1362 affine.sy=svg_info->affine.sy;
1370 if (LocaleCompare(keyword,"translate") == 0)
1372 for (p=(const char *) value; *p != '\0'; p++)
1373 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1376 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1377 affine.ty=affine.tx;
1380 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1388 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1389 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1390 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1391 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1392 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1394 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1397 MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1398 transform.sx,transform.rx,transform.ry,transform.sy,
1399 transform.tx,transform.ty);
1400 for (j=0; tokens[j] != (char *) NULL; j++)
1401 tokens[j]=DestroyString(tokens[j]);
1402 tokens=(char **) RelinquishMagickMemory(tokens);
1405 if (LocaleCompare(keyword,"gradientUnits") == 0)
1407 (void) CloneString(&units,value);
1408 MVGPrintf(svg_info->file,"gradient-units '%s'\n",value);
1416 if (LocaleCompare(keyword,"height") == 0)
1418 svg_info->bounds.height=
1419 GetUserSpaceCoordinateValue(svg_info,-1,value);
1422 if (LocaleCompare(keyword,"href") == 0)
1424 (void) CloneString(&svg_info->url,value);
1432 if (LocaleCompare(keyword,"major") == 0)
1434 svg_info->element.major=
1435 GetUserSpaceCoordinateValue(svg_info,1,value);
1438 if (LocaleCompare(keyword,"minor") == 0)
1440 svg_info->element.minor=
1441 GetUserSpaceCoordinateValue(svg_info,-1,value);
1449 if (LocaleCompare(keyword,"offset") == 0)
1451 (void) CloneString(&svg_info->offset,value);
1454 if (LocaleCompare(keyword,"opacity") == 0)
1456 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1464 if (LocaleCompare(keyword,"path") == 0)
1466 (void) CloneString(&svg_info->url,value);
1469 if (LocaleCompare(keyword,"points") == 0)
1471 (void) CloneString(&svg_info->vertices,value);
1479 if (LocaleCompare(keyword,"r") == 0)
1481 svg_info->element.major=
1482 GetUserSpaceCoordinateValue(svg_info,1,value);
1483 svg_info->element.minor=
1484 GetUserSpaceCoordinateValue(svg_info,-1,value);
1487 if (LocaleCompare(keyword,"rotate") == 0)
1492 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1493 MVGPrintf(svg_info->file,"translate %g,%g\n",svg_info->bounds.x,
1494 svg_info->bounds.y);
1495 svg_info->bounds.x=0;
1496 svg_info->bounds.y=0;
1497 MVGPrintf(svg_info->file,"rotate %g\n",angle);
1500 if (LocaleCompare(keyword,"rx") == 0)
1502 if (LocaleCompare((const char *) name,"ellipse") == 0)
1503 svg_info->element.major=
1504 GetUserSpaceCoordinateValue(svg_info,1,value);
1507 GetUserSpaceCoordinateValue(svg_info,1,value);
1510 if (LocaleCompare(keyword,"ry") == 0)
1512 if (LocaleCompare((const char *) name,"ellipse") == 0)
1513 svg_info->element.minor=
1514 GetUserSpaceCoordinateValue(svg_info,-1,value);
1517 GetUserSpaceCoordinateValue(svg_info,-1,value);
1525 if (LocaleCompare(keyword,"stop-color") == 0)
1527 (void) CloneString(&svg_info->stop_color,value);
1530 if (LocaleCompare(keyword,"stroke") == 0)
1532 if (LocaleCompare(value,"currentColor") == 0)
1534 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1537 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1540 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1542 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1543 LocaleCompare(value,"true") == 0);
1546 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1548 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1551 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1553 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",value);
1556 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1558 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1561 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1563 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",value);
1566 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1568 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",value);
1571 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1573 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1576 if (LocaleCompare(keyword,"stroke-width") == 0)
1578 MVGPrintf(svg_info->file,"stroke-width %g\n",
1579 GetUserSpaceCoordinateValue(svg_info,1,value));
1582 if (LocaleCompare(keyword,"style") == 0)
1584 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1585 tokens=GetStyleTokens(context,value,&number_tokens);
1586 for (j=0; j < (number_tokens-1); j+=2)
1588 keyword=(char *) tokens[j];
1589 value=(char *) tokens[j+1];
1590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1591 " %s: %s",keyword,value);
1597 if (LocaleCompare(keyword,"clip-path") == 0)
1599 MVGPrintf(svg_info->file,"clip-path '%s'\n",value);
1602 if (LocaleCompare(keyword,"clip-rule") == 0)
1604 MVGPrintf(svg_info->file,"clip-rule '%s'\n",value);
1607 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1609 (void) CloneString(&units,value);
1610 MVGPrintf(svg_info->file,"clip-units '%s'\n",value);
1613 if (LocaleCompare(keyword,"color") == 0)
1615 (void) CloneString(&color,value);
1623 if (LocaleCompare(keyword,"fill") == 0)
1625 if (LocaleCompare(value,"currentColor") == 0)
1627 MVGPrintf(svg_info->file,"fill '%s'\n",color);
1630 if (LocaleCompare(value,"#00000000") == 0)
1631 MVGPrintf(svg_info->file,"fill '#000000'\n");
1633 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1636 if (LocaleCompare(keyword,"fillcolor") == 0)
1638 MVGPrintf(svg_info->file,"fill '%s'\n",value);
1641 if (LocaleCompare(keyword,"fill-rule") == 0)
1643 MVGPrintf(svg_info->file,"fill-rule '%s'\n",value);
1646 if (LocaleCompare(keyword,"fill-opacity") == 0)
1648 MVGPrintf(svg_info->file,"fill-opacity '%s'\n",value);
1651 if (LocaleCompare(keyword,"font-family") == 0)
1653 MVGPrintf(svg_info->file,"font-family '%s'\n",value);
1656 if (LocaleCompare(keyword,"font-stretch") == 0)
1658 MVGPrintf(svg_info->file,"font-stretch '%s'\n",value);
1661 if (LocaleCompare(keyword,"font-style") == 0)
1663 MVGPrintf(svg_info->file,"font-style '%s'\n",value);
1666 if (LocaleCompare(keyword,"font-size") == 0)
1668 svg_info->pointsize=GetUserSpaceCoordinateValue(
1670 MVGPrintf(svg_info->file,"font-size %g\n",
1671 svg_info->pointsize);
1674 if (LocaleCompare(keyword,"font-weight") == 0)
1676 MVGPrintf(svg_info->file,"font-weight '%s'\n",value);
1684 if (LocaleCompare(keyword,"offset") == 0)
1686 MVGPrintf(svg_info->file,"offset %g\n",
1687 GetUserSpaceCoordinateValue(svg_info,1,value));
1690 if (LocaleCompare(keyword,"opacity") == 0)
1692 MVGPrintf(svg_info->file,"opacity '%s'\n",value);
1700 if (LocaleCompare(keyword,"stop-color") == 0)
1702 (void) CloneString(&svg_info->stop_color,value);
1705 if (LocaleCompare(keyword,"stroke") == 0)
1707 if (LocaleCompare(value,"currentColor") == 0)
1709 MVGPrintf(svg_info->file,"stroke '%s'\n",color);
1712 if (LocaleCompare(value,"#00000000") == 0)
1713 MVGPrintf(svg_info->file,"fill '#000000'\n");
1715 MVGPrintf(svg_info->file,"stroke '%s'\n",value);
1718 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1720 MVGPrintf(svg_info->file,"stroke-antialias %d\n",
1721 LocaleCompare(value,"true") == 0);
1724 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1726 MVGPrintf(svg_info->file,"stroke-dasharray %s\n",value);
1729 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1731 MVGPrintf(svg_info->file,"stroke-dashoffset %s\n",
1735 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1737 MVGPrintf(svg_info->file,"stroke-linecap '%s'\n",value);
1740 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1742 MVGPrintf(svg_info->file,"stroke-linejoin '%s'\n",
1746 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1748 MVGPrintf(svg_info->file,"stroke-miterlimit '%s'\n",
1752 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1754 MVGPrintf(svg_info->file,"stroke-opacity '%s'\n",value);
1757 if (LocaleCompare(keyword,"stroke-width") == 0)
1759 MVGPrintf(svg_info->file,"stroke-width %g\n",
1760 GetUserSpaceCoordinateValue(svg_info,1,value));
1768 if (LocaleCompare(keyword,"text-align") == 0)
1770 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1773 if (LocaleCompare(keyword,"text-anchor") == 0)
1775 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1778 if (LocaleCompare(keyword,"text-decoration") == 0)
1780 if (LocaleCompare(value,"underline") == 0)
1781 MVGPrintf(svg_info->file,"decorate underline\n");
1782 if (LocaleCompare(value,"line-through") == 0)
1783 MVGPrintf(svg_info->file,"decorate line-through\n");
1784 if (LocaleCompare(value,"overline") == 0)
1785 MVGPrintf(svg_info->file,"decorate overline\n");
1788 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1790 MVGPrintf(svg_info->file,"text-antialias %d\n",
1791 LocaleCompare(value,"true") == 0);
1800 for (j=0; tokens[j] != (char *) NULL; j++)
1801 tokens[j]=DestroyString(tokens[j]);
1802 tokens=(char **) RelinquishMagickMemory(tokens);
1810 if (LocaleCompare(keyword,"text-align") == 0)
1812 MVGPrintf(svg_info->file,"text-align '%s'\n",value);
1815 if (LocaleCompare(keyword,"text-anchor") == 0)
1817 MVGPrintf(svg_info->file,"text-anchor '%s'\n",value);
1820 if (LocaleCompare(keyword,"text-decoration") == 0)
1822 if (LocaleCompare(value,"underline") == 0)
1823 MVGPrintf(svg_info->file,"decorate underline\n");
1824 if (LocaleCompare(value,"line-through") == 0)
1825 MVGPrintf(svg_info->file,"decorate line-through\n");
1826 if (LocaleCompare(value,"overline") == 0)
1827 MVGPrintf(svg_info->file,"decorate overline\n");
1830 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1832 MVGPrintf(svg_info->file,"text-antialias %d\n",
1833 LocaleCompare(value,"true") == 0);
1836 if (LocaleCompare(keyword,"transform") == 0)
1843 GetAffineMatrix(&transform);
1844 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1845 tokens=GetTransformTokens(context,value,&number_tokens);
1846 for (j=0; j < (number_tokens-1); j+=2)
1848 keyword=(char *) tokens[j];
1849 value=(char *) tokens[j+1];
1850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1851 " %s: %s",keyword,value);
1853 GetAffineMatrix(&affine);
1859 if (LocaleCompare(keyword,"matrix") == 0)
1861 p=(const char *) value;
1862 GetMagickToken(p,&p,token);
1863 affine.sx=atof(value);
1864 GetMagickToken(p,&p,token);
1866 GetMagickToken(p,&p,token);
1867 affine.rx=atof(token);
1868 GetMagickToken(p,&p,token);
1870 GetMagickToken(p,&p,token);
1871 affine.ry=atof(token);
1872 GetMagickToken(p,&p,token);
1874 GetMagickToken(p,&p,token);
1875 affine.sy=atof(token);
1876 GetMagickToken(p,&p,token);
1878 GetMagickToken(p,&p,token);
1879 affine.tx=atof(token);
1880 GetMagickToken(p,&p,token);
1882 GetMagickToken(p,&p,token);
1883 affine.ty=atof(token);
1891 if (LocaleCompare(keyword,"rotate") == 0)
1898 p=(const char *) value;
1899 GetMagickToken(p,&p,token);
1901 GetMagickToken(p,&p,token);
1903 GetMagickToken(p,&p,token);
1905 GetMagickToken(p,&p,token);
1907 GetMagickToken(p,&p,token);
1909 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1910 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1911 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1912 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1915 svg_info->center.x=x;
1916 svg_info->center.y=y;
1924 if (LocaleCompare(keyword,"scale") == 0)
1926 for (p=(const char *) value; *p != '\0'; p++)
1927 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1930 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1931 affine.sy=affine.sx;
1933 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1935 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1938 if (LocaleCompare(keyword,"skewX") == 0)
1940 affine.sx=svg_info->affine.sx;
1941 affine.ry=tan(DegreesToRadians(fmod(
1942 GetUserSpaceCoordinateValue(svg_info,1,value),
1944 affine.sy=svg_info->affine.sy;
1947 if (LocaleCompare(keyword,"skewY") == 0)
1949 affine.sx=svg_info->affine.sx;
1950 affine.rx=tan(DegreesToRadians(fmod(
1951 GetUserSpaceCoordinateValue(svg_info,-1,value),
1953 affine.sy=svg_info->affine.sy;
1961 if (LocaleCompare(keyword,"translate") == 0)
1963 for (p=(const char *) value; *p != '\0'; p++)
1964 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1967 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1968 affine.ty=affine.tx;
1970 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
1979 transform.sx=current.sx*affine.sx+current.ry*affine.rx;
1980 transform.rx=current.rx*affine.sx+current.sy*affine.rx;
1981 transform.ry=current.sx*affine.ry+current.ry*affine.sy;
1982 transform.sy=current.rx*affine.ry+current.sy*affine.sy;
1983 transform.tx=current.sx*affine.tx+current.ry*affine.ty+
1985 transform.ty=current.rx*affine.tx+current.sy*affine.ty+
1988 MVGPrintf(svg_info->file,"affine %g %g %g %g %g %g\n",
1989 transform.sx,transform.rx,transform.ry,transform.sy,
1990 transform.tx,transform.ty);
1991 for (j=0; tokens[j] != (char *) NULL; j++)
1992 tokens[j]=DestroyString(tokens[j]);
1993 tokens=(char **) RelinquishMagickMemory(tokens);
2001 if (LocaleCompare(keyword,"verts") == 0)
2003 (void) CloneString(&svg_info->vertices,value);
2006 if (LocaleCompare(keyword,"viewBox") == 0)
2008 p=(const char *) value;
2009 GetMagickToken(p,&p,token);
2010 svg_info->view_box.x=atof(token);
2011 GetMagickToken(p,&p,token);
2013 GetMagickToken(p,&p,token);
2014 svg_info->view_box.y=atof(token);
2015 GetMagickToken(p,&p,token);
2017 GetMagickToken(p,&p,token);
2018 svg_info->view_box.width=atof(token);
2019 if (svg_info->bounds.width == 0)
2020 svg_info->bounds.width=svg_info->view_box.width;
2021 GetMagickToken(p,&p,token);
2023 GetMagickToken(p,&p,token);
2024 svg_info->view_box.height=atof(token);
2025 if (svg_info->bounds.height == 0)
2026 svg_info->bounds.height=svg_info->view_box.height;
2034 if (LocaleCompare(keyword,"width") == 0)
2036 svg_info->bounds.width=
2037 GetUserSpaceCoordinateValue(svg_info,1,value);
2045 if (LocaleCompare(keyword,"x") == 0)
2047 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2050 if (LocaleCompare(keyword,"xlink:href") == 0)
2052 (void) CloneString(&svg_info->url,value);
2055 if (LocaleCompare(keyword,"x1") == 0)
2057 svg_info->segment.x1=
2058 GetUserSpaceCoordinateValue(svg_info,1,value);
2061 if (LocaleCompare(keyword,"x2") == 0)
2063 svg_info->segment.x2=
2064 GetUserSpaceCoordinateValue(svg_info,1,value);
2072 if (LocaleCompare(keyword,"y") == 0)
2074 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2077 if (LocaleCompare(keyword,"y1") == 0)
2079 svg_info->segment.y1=
2080 GetUserSpaceCoordinateValue(svg_info,-1,value);
2083 if (LocaleCompare(keyword,"y2") == 0)
2085 svg_info->segment.y2=
2086 GetUserSpaceCoordinateValue(svg_info,-1,value);
2095 if (LocaleCompare((const char *) name,"svg") == 0)
2097 if (svg_info->document->encoding != (const xmlChar *) NULL)
2098 MVGPrintf(svg_info->file,"encoding \"%s\"\n",
2099 (const char *) svg_info->document->encoding);
2100 if (attributes != (const xmlChar **) NULL)
2106 if ((svg_info->view_box.width == 0.0) ||
2107 (svg_info->view_box.height == 0.0))
2108 svg_info->view_box=svg_info->bounds;
2109 svg_info->width=(unsigned long) (svg_info->bounds.width+0.5);
2110 svg_info->height=(unsigned long) (svg_info->bounds.height+0.5);
2111 MVGPrintf(svg_info->file,"viewbox 0 0 %lu %lu\n",svg_info->width,
2113 sx=(double) svg_info->width/svg_info->view_box.width;
2114 sy=(double) svg_info->height/svg_info->view_box.height;
2115 MVGPrintf(svg_info->file,"affine %g 0 0 %g 0.0 0.0\n",sx,sy);
2118 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2119 units=DestroyString(units);
2120 if (color != (char *) NULL)
2121 color=DestroyString(color);
2124 static void SVGEndElement(void *context,const xmlChar *name)
2130 Called when the end of an element has been detected.
2132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2133 " SAX.endElement(%s)",name);
2134 svg_info=(SVGInfo *) context;
2140 if (LocaleCompare((const char *) name,"circle") == 0)
2142 MVGPrintf(svg_info->file,"circle %g,%g %g,%g\n",svg_info->element.cx,
2143 svg_info->element.cy,svg_info->element.cx,svg_info->element.cy+
2144 svg_info->element.minor);
2145 MVGPrintf(svg_info->file,"pop graphic-context\n");
2148 if (LocaleCompare((const char *) name,"clipPath") == 0)
2150 MVGPrintf(svg_info->file,"pop clip-path\n");
2158 if (LocaleCompare((const char *) name,"defs") == 0)
2160 MVGPrintf(svg_info->file,"pop defs\n");
2163 if (LocaleCompare((const char *) name,"desc") == 0)
2168 if (*svg_info->text == '\0')
2170 (void) fputc('#',svg_info->file);
2171 for (p=svg_info->text; *p != '\0'; p++)
2173 (void) fputc(*p,svg_info->file);
2175 (void) fputc('#',svg_info->file);
2177 (void) fputc('\n',svg_info->file);
2178 *svg_info->text='\0';
2186 if (LocaleCompare((const char *) name,"ellipse") == 0)
2191 angle=svg_info->element.angle;
2192 MVGPrintf(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2193 svg_info->element.cx,svg_info->element.cy,
2194 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2195 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2196 MVGPrintf(svg_info->file,"pop graphic-context\n");
2204 if (LocaleCompare((const char *) name,"g") == 0)
2206 MVGPrintf(svg_info->file,"pop graphic-context\n");
2214 if (LocaleCompare((const char *) name,"image") == 0)
2216 MVGPrintf(svg_info->file,"image Over %g,%g %g,%g '%s'\n",
2217 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
2218 svg_info->bounds.height,svg_info->url);
2219 MVGPrintf(svg_info->file,"pop graphic-context\n");
2227 if (LocaleCompare((const char *) name,"line") == 0)
2229 MVGPrintf(svg_info->file,"line %g,%g %g,%g\n",svg_info->segment.x1,
2230 svg_info->segment.y1,svg_info->segment.x2,svg_info->segment.y2);
2231 MVGPrintf(svg_info->file,"pop graphic-context\n");
2234 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2236 MVGPrintf(svg_info->file,"pop gradient\n");
2244 if (LocaleCompare((const char *) name,"pattern") == 0)
2246 MVGPrintf(svg_info->file,"pop pattern\n");
2249 if (LocaleCompare((const char *) name,"path") == 0)
2251 MVGPrintf(svg_info->file,"path '%s'\n",svg_info->vertices);
2252 MVGPrintf(svg_info->file,"pop graphic-context\n");
2255 if (LocaleCompare((const char *) name,"polygon") == 0)
2257 MVGPrintf(svg_info->file,"polygon %s\n",svg_info->vertices);
2258 MVGPrintf(svg_info->file,"pop graphic-context\n");
2261 if (LocaleCompare((const char *) name,"polyline") == 0)
2263 MVGPrintf(svg_info->file,"polyline %s\n",svg_info->vertices);
2264 MVGPrintf(svg_info->file,"pop graphic-context\n");
2272 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2274 MVGPrintf(svg_info->file,"pop gradient\n");
2277 if (LocaleCompare((const char *) name,"rect") == 0)
2279 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2281 MVGPrintf(svg_info->file,"rectangle %g,%g %g,%g\n",
2282 svg_info->bounds.x,svg_info->bounds.y,
2283 svg_info->bounds.x+svg_info->bounds.width,
2284 svg_info->bounds.y+svg_info->bounds.height);
2285 MVGPrintf(svg_info->file,"pop graphic-context\n");
2288 if (svg_info->radius.x == 0.0)
2289 svg_info->radius.x=svg_info->radius.y;
2290 if (svg_info->radius.y == 0.0)
2291 svg_info->radius.y=svg_info->radius.x;
2292 MVGPrintf(svg_info->file,"roundRectangle %g,%g %g,%g %g,%g\n",
2293 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2294 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2295 svg_info->radius.x,svg_info->radius.y);
2296 svg_info->radius.x=0.0;
2297 svg_info->radius.y=0.0;
2298 MVGPrintf(svg_info->file,"pop graphic-context\n");
2306 if (LocaleCompare((const char *) name,"stop") == 0)
2308 MVGPrintf(svg_info->file,"stop-color '%s' %s\n",svg_info->stop_color,
2312 if (LocaleCompare((const char *) name,"svg") == 0)
2314 MVGPrintf(svg_info->file,"pop graphic-context\n");
2322 if (LocaleCompare((const char *) name,"text") == 0)
2324 if (*svg_info->text != '\0')
2329 text=EscapeString(svg_info->text,'\'');
2331 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x-
2332 svg_info->center.x,svg_info->bounds.y-svg_info->center.y,text);
2333 text=DestroyString(text);
2334 *svg_info->text='\0';
2336 MVGPrintf(svg_info->file,"pop graphic-context\n");
2339 if (LocaleCompare((const char *) name,"tspan") == 0)
2341 if (*svg_info->text != '\0')
2352 text=EscapeString(svg_info->text,'\'');
2354 MVGPrintf(svg_info->file,"text %g,%g '%s'\n",svg_info->bounds.x,
2355 svg_info->bounds.y,text);
2356 text=DestroyString(text);
2357 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2358 draw_info->pointsize=svg_info->pointsize;
2359 draw_info->text=AcquireString(svg_info->text);
2360 (void) ConcatenateString(&draw_info->text," ");
2361 GetTypeMetrics(svg_info->image,draw_info,&metrics);
2362 svg_info->bounds.x+=metrics.width;
2363 draw_info=DestroyDrawInfo(draw_info);
2364 *svg_info->text='\0';
2366 MVGPrintf(svg_info->file,"pop graphic-context\n");
2369 if (LocaleCompare((const char *) name,"title") == 0)
2371 if (*svg_info->text == '\0')
2373 (void) CloneString(&svg_info->title,svg_info->text);
2374 *svg_info->text='\0';
2382 *svg_info->text='\0';
2383 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2384 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2388 static void SVGCharacters(void *context,const xmlChar *c,int length)
2400 Receiving some characters from the parser.
2402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403 " SAX.characters(%s,%lu)",c,(unsigned long) length);
2404 svg_info=(SVGInfo *) context;
2405 if (svg_info->text != (char *) NULL)
2406 svg_info->text=(char *) ResizeQuantumMemory(svg_info->text,
2407 strlen(svg_info->text)+length+MaxTextExtent,sizeof(*svg_info->text));
2410 svg_info->text=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2411 sizeof(*svg_info->text));
2412 if (svg_info->text != (char *) NULL)
2413 *svg_info->text='\0';
2415 if (svg_info->text == (char *) NULL)
2417 p=svg_info->text+strlen(svg_info->text);
2418 for (i=0; i < (long) length; i++)
2423 static void SVGReference(void *context,const xmlChar *name)
2432 Called when an entity reference is detected.
2434 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2436 svg_info=(SVGInfo *) context;
2437 parser=svg_info->parser;
2438 if (parser == (xmlParserCtxtPtr) NULL)
2440 if (parser->node == (xmlNodePtr) NULL)
2443 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2445 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2448 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2454 Receiving some ignorable whitespaces from the parser.
2456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2457 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2458 svg_info=(SVGInfo *) context;
2461 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2462 const xmlChar *data)
2468 A processing instruction has been parsed.
2470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2471 " SAX.processingInstruction(%s, %s)",target,data);
2472 svg_info=(SVGInfo *) context;
2475 static void SVGComment(void *context,const xmlChar *value)
2481 A comment has been parsed.
2483 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2485 svg_info=(SVGInfo *) context;
2486 if (svg_info->comment != (char *) NULL)
2487 (void) ConcatenateString(&svg_info->comment,"\n");
2488 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2491 static void SVGWarning(void *context,const char *format,...)
2495 reason[MaxTextExtent];
2504 Display and format a warning messages, gives file, line, position and
2507 va_start(operands,format);
2508 svg_info=(SVGInfo *) context;
2509 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2511 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2512 (void) vsprintf(reason,format,operands);
2514 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2516 message=GetExceptionMessage(errno);
2517 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2518 DelegateWarning,reason,"`%s`",message);
2519 message=DestroyString(message);
2523 static void SVGError(void *context,const char *format,...)
2527 reason[MaxTextExtent];
2536 Display and format a error formats, gives file, line, position and
2539 va_start(operands,format);
2540 svg_info=(SVGInfo *) context;
2541 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2543 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2544 (void) vsprintf(reason,format,operands);
2546 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2548 message=GetExceptionMessage(errno);
2549 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2550 reason,"`%s`",message);
2551 message=DestroyString(message);
2555 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2567 Called when a pcdata block has been parsed.
2569 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2571 svg_info=(SVGInfo *) context;
2572 parser=svg_info->parser;
2573 child=xmlGetLastChild(parser->node);
2574 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2576 xmlTextConcat(child,value,length);
2579 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2582 static void SVGExternalSubset(void *context,const xmlChar *name,
2583 const xmlChar *external_id,const xmlChar *system_id)
2598 Does this document has an external subset?
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2601 " SAX.externalSubset(%s, %s, %s)",name,
2602 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2603 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2604 svg_info=(SVGInfo *) context;
2605 parser=svg_info->parser;
2606 if (((external_id == NULL) && (system_id == NULL)) ||
2607 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2608 (svg_info->document == 0)))
2610 input=SVGResolveEntity(context,external_id,system_id);
2613 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2614 parser_context=(*parser);
2615 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2616 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2618 parser->errNo=XML_ERR_NO_MEMORY;
2619 parser->input=parser_context.input;
2620 parser->inputNr=parser_context.inputNr;
2621 parser->inputMax=parser_context.inputMax;
2622 parser->inputTab=parser_context.inputTab;
2628 xmlPushInput(parser,input);
2629 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2630 if (input->filename == (char *) NULL)
2631 input->filename=(char *) xmlStrdup(system_id);
2634 input->base=parser->input->cur;
2635 input->cur=parser->input->cur;
2637 xmlParseExternalSubset(parser,external_id,system_id);
2638 while (parser->inputNr > 1)
2639 (void) xmlPopInput(parser);
2640 xmlFreeInputStream(parser->input);
2641 xmlFree(parser->inputTab);
2642 parser->input=parser_context.input;
2643 parser->inputNr=parser_context.inputNr;
2644 parser->inputMax=parser_context.inputMax;
2645 parser->inputTab=parser_context.inputTab;
2648 #if defined(MAGICKCORE_RSVG_DELEGATE)
2649 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2650 static void SVGSetImageSize(int *width,int *height,gpointer context)
2655 image=(Image *) context;
2656 *width=(int) (*width*image->x_resolution/72.0);
2657 *height=(int) (*height*image->y_resolution/72.0);
2662 #if defined(__cplusplus) || defined(c_plusplus)
2666 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2673 SVGHasInternalSubset,
2674 SVGHasExternalSubset,
2677 SVGEntityDeclaration,
2678 SVGNotationDeclaration,
2679 SVGAttributeDeclaration,
2680 SVGElementDeclaration,
2681 SVGUnparsedEntityDeclaration,
2682 SVGSetDocumentLocator,
2689 SVGIgnorableWhitespace,
2690 SVGProcessingInstructions,
2695 SVGGetParameterEntity,
2701 filename[MaxTextExtent];
2720 message[MaxTextExtent];
2728 assert(image_info != (const ImageInfo *) NULL);
2729 assert(image_info->signature == MagickSignature);
2730 assert(exception != (ExceptionInfo *) NULL);
2731 if (image_info->debug != MagickFalse)
2732 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2733 image_info->filename);
2734 assert(exception->signature == MagickSignature);
2735 image=AcquireImage(image_info);
2736 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2737 if (status == MagickFalse)
2739 image=DestroyImageList(image);
2740 return((Image *) NULL);
2742 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2744 #if defined(MAGICKCORE_RSVG_DELEGATE)
2745 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2752 register unsigned char
2765 register const guchar
2782 register PixelPacket
2788 svg_handle=rsvg_handle_new();
2789 if (svg_handle == (RsvgHandle *) NULL)
2790 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2791 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2792 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2793 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2795 if ((image->x_resolution != 72.0) && (image->y_resolution != 72.0))
2796 rsvg_handle_set_dpi_x_y(svg_handle,image->x_resolution,
2797 image->y_resolution);
2798 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2800 error=(GError *) NULL;
2801 (void) rsvg_handle_write(svg_handle,message,n,&error);
2802 if (error != (GError *) NULL)
2803 g_error_free(error);
2805 error=(GError *) NULL;
2806 rsvg_handle_close(svg_handle,&error);
2807 if (error != (GError *) NULL)
2808 g_error_free(error);
2809 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2810 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2811 image->columns=dimension_info.width*image->x_resolution/72.0;
2812 image->rows=dimension_info.height*image->y_resolution/72.0;
2813 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2814 image->rows*sizeof(*pixels));
2816 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2817 rsvg_handle_free(svg_handle);
2818 image->columns=gdk_pixbuf_get_width(pixel_info);
2819 image->rows=gdk_pixbuf_get_height(pixel_info);
2821 if ((image->columns == 0) || (image->rows == 0))
2823 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2824 g_object_unref(G_OBJECT(pixel_info));
2826 g_object_unref(svg_handle);
2827 ThrowReaderException(MissingDelegateError,
2828 "NoDecodeDelegateForThisImageFormat");
2830 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2831 if (pixels == (unsigned char *) NULL)
2833 g_object_unref(svg_handle);
2834 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2837 image->matte=MagickTrue;
2838 (void) SetImageBackgroundColor(image);
2839 SetImageProperty(image,"svg:base-uri",
2840 rsvg_handle_get_base_uri(svg_handle));
2841 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle));
2842 SetImageProperty(image,"svg:description",
2843 rsvg_handle_get_desc(svg_handle));
2844 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2845 cairo_surface=cairo_image_surface_create_for_data(pixels,
2846 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2847 if (cairo_surface == (cairo_surface_t *) NULL)
2849 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2850 g_object_unref(svg_handle);
2851 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2853 cairo_info=cairo_create(cairo_surface);
2854 cairo_scale(cairo_info,image->x_resolution/72.0,image->y_resolution/72.0);
2855 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2856 cairo_paint(cairo_info);
2857 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2858 rsvg_handle_render_cairo(svg_handle,cairo_info);
2859 cairo_destroy(cairo_info);
2860 cairo_surface_destroy(cairo_surface);
2861 g_object_unref(svg_handle);
2864 p=gdk_pixbuf_get_pixels(pixel_info);
2866 for (y=0; y < (long) image->rows; y++)
2868 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2869 if (q == (PixelPacket *) NULL)
2871 for (x=0; x < (long) image->columns; x++)
2873 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2874 fill_color.blue=ScaleCharToQuantum(*p++);
2875 fill_color.green=ScaleCharToQuantum(*p++);
2876 fill_color.red=ScaleCharToQuantum(*p++);
2878 fill_color.red=ScaleCharToQuantum(*p++);
2879 fill_color.green=ScaleCharToQuantum(*p++);
2880 fill_color.blue=ScaleCharToQuantum(*p++);
2882 fill_color.opacity=QuantumRange-ScaleCharToQuantum(*p++);
2883 MagickCompositeOver(&fill_color,fill_color.opacity,q,(MagickRealType)
2887 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2889 if (image->previous == (Image *) NULL)
2891 status=SetImageProgress(image,LoadImageTag,y,image->rows);
2892 if (status == MagickFalse)
2896 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2897 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2899 g_object_unref(G_OBJECT(pixel_info));
2901 (void) CloseBlob(image);
2902 return(GetFirstImageInList(image));
2909 unique_file=AcquireUniqueFileResource(filename);
2910 if (unique_file != -1)
2911 file=fdopen(unique_file,"w");
2912 if ((unique_file == -1) || (file == (FILE *) NULL))
2914 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2915 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2917 image=DestroyImageList(image);
2918 return((Image *) NULL);
2923 svg_info=AcquireSVGInfo();
2924 if (svg_info == (SVGInfo *) NULL)
2925 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2926 svg_info->file=file;
2927 svg_info->exception=exception;
2928 svg_info->image=image;
2929 svg_info->image_info=image_info;
2930 svg_info->bounds.width=image->columns;
2931 svg_info->bounds.height=image->rows;
2932 if (image_info->size != (char *) NULL)
2933 (void) CloneString(&svg_info->size,image_info->size);
2934 if (image->debug != MagickFalse)
2935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
2937 (void) xmlSubstituteEntitiesDefault(1);
2938 sax_handler=(&SAXModules);
2939 n=ReadBlob(image,MaxTextExtent,message);
2942 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
2943 message,n,image->filename);
2944 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2946 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
2951 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
2952 xmlFreeParserCtxt(svg_info->parser);
2953 if (image->debug != MagickFalse)
2954 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
2956 (void) fclose(file);
2957 (void) CloseBlob(image);
2958 image->columns=svg_info->width;
2959 image->rows=svg_info->height;
2960 if (exception->severity >= ErrorException)
2962 image=DestroyImage(image);
2963 return((Image *) NULL);
2965 if (image_info->ping == MagickFalse)
2973 image=DestroyImage(image);
2974 image=(Image *) NULL;
2975 read_info=CloneImageInfo(image_info);
2976 SetImageInfoBlob(read_info,(void *) NULL,0);
2977 if (read_info->density != (char *) NULL)
2978 read_info->density=DestroyString(read_info->density);
2979 (void) FormatMagickString(read_info->filename,MaxTextExtent,"mvg:%s",
2981 image=ReadImage(read_info,exception);
2982 read_info=DestroyImageInfo(read_info);
2983 if (image != (Image *) NULL)
2984 (void) CopyMagickString(image->filename,image_info->filename,
2988 Relinquish resources.
2990 if (image != (Image *) NULL)
2992 if (svg_info->title != (char *) NULL)
2993 (void) SetImageProperty(image,"svg:title",svg_info->title);
2994 if (svg_info->comment != (char *) NULL)
2995 (void) SetImageProperty(image,"svg:comment",svg_info->comment);
2997 svg_info=DestroySVGInfo(svg_info);
2998 (void) RelinquishUniqueFileResource(filename);
2999 return(GetFirstImageInList(image));
3004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008 % R e g i s t e r S V G I m a g e %
3012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014 % RegisterSVGImage() adds attributes for the SVG image format to
3015 % the list of supported formats. The attributes include the image format
3016 % tag, a method to read and/or write the format, whether the format
3017 % supports the saving of more than one frame to the same file or blob,
3018 % whether the format supports native in-memory I/O, and a brief
3019 % description of the format.
3021 % The format of the RegisterSVGImage method is:
3023 % unsigned long RegisterSVGImage(void)
3026 ModuleExport unsigned long RegisterSVGImage(void)
3029 version[MaxTextExtent];
3035 #if defined(LIBXML_DOTTED_VERSION)
3036 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3038 #if defined(MAGICKCORE_RSVG_DELEGATE)
3040 (void) FormatMagickString(version,MaxTextExtent,"RSVG %d.%d.%d",
3041 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3043 entry=SetMagickInfo("SVG");
3044 #if defined(MAGICKCORE_XML_DELEGATE)
3045 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3047 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3048 entry->blob_support=MagickFalse;
3049 entry->seekable_stream=MagickFalse;
3050 entry->description=ConstantString("Scalable Vector Graphics");
3051 if (*version != '\0')
3052 entry->version=ConstantString(version);
3053 entry->magick=(IsImageFormatHandler *) IsSVG;
3054 entry->module=ConstantString("SVG");
3055 (void) RegisterMagickInfo(entry);
3056 entry=SetMagickInfo("SVGZ");
3057 #if defined(MAGICKCORE_XML_DELEGATE)
3058 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3060 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3061 entry->blob_support=MagickFalse;
3062 entry->seekable_stream=MagickFalse;
3063 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3064 if (*version != '\0')
3065 entry->version=ConstantString(version);
3066 entry->magick=(IsImageFormatHandler *) IsSVG;
3067 entry->module=ConstantString("SVG");
3068 (void) RegisterMagickInfo(entry);
3069 entry=SetMagickInfo("MSVG");
3070 #if defined(MAGICKCORE_XML_DELEGATE)
3071 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3073 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3074 entry->blob_support=MagickFalse;
3075 entry->seekable_stream=MagickFalse;
3076 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3077 entry->magick=(IsImageFormatHandler *) IsSVG;
3078 entry->module=ConstantString("SVG");
3079 (void) RegisterMagickInfo(entry);
3080 return(MagickImageCoderSignature);
3084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088 % U n r e g i s t e r S V G I m a g e %
3092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3094 % UnregisterSVGImage() removes format registrations made by the
3095 % SVG module from the list of supported formats.
3097 % The format of the UnregisterSVGImage method is:
3099 % UnregisterSVGImage(void)
3102 ModuleExport void UnregisterSVGImage(void)
3104 (void) UnregisterMagickInfo("SVGZ");
3105 (void) UnregisterMagickInfo("SVG");
3106 (void) UnregisterMagickInfo("MSVG");
3107 #if defined(MAGICKCORE_RSVG_DELEGATE)
3113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117 % W r i t e S V G I m a g e %
3121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3123 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3126 % The format of the WriteSVGImage method is:
3128 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3130 % A description of each parameter follows.
3132 % o image_info: the image info.
3134 % o image: The image.
3138 static void AffineToTransform(Image *image,AffineMatrix *affine)
3141 transform[MaxTextExtent];
3143 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3145 if ((fabs(affine->rx) < MagickEpsilon) &&
3146 (fabs(affine->ry) < MagickEpsilon))
3148 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3149 (fabs(affine->sy-1.0) < MagickEpsilon))
3151 (void) WriteBlobString(image,"\">\n");
3154 (void) FormatMagickString(transform,MaxTextExtent,
3155 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3156 (void) WriteBlobString(image,transform);
3161 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3162 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3163 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3169 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3170 (void) FormatMagickString(transform,MaxTextExtent,
3171 "\" transform=\"rotate(%g)\">\n",theta);
3172 (void) WriteBlobString(image,transform);
3179 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3180 (fabs(affine->rx) < MagickEpsilon) &&
3181 (fabs(affine->ry) < MagickEpsilon) &&
3182 (fabs(affine->sy-1.0) < MagickEpsilon))
3184 (void) FormatMagickString(transform,MaxTextExtent,
3185 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3186 (void) WriteBlobString(image,transform);
3190 (void) FormatMagickString(transform,MaxTextExtent,
3191 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",affine->sx,affine->rx,
3192 affine->ry,affine->sy,affine->tx,affine->ty);
3193 (void) WriteBlobString(image,transform);
3196 static MagickBooleanType IsPoint(const char *point)
3204 value=strtol(point,&p,10);
3205 return(p != point ? MagickTrue : MagickFalse);
3208 static MagickBooleanType TraceSVGImage(Image *image)
3213 register const PixelPacket
3219 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3224 at_fitting_opts_type
3243 Trace image and write as SVG.
3245 fitting_options=at_fitting_opts_new();
3246 output_options=at_output_opts_new();
3247 type=GetImageType(image,&image->exception);
3249 if ((type == BilevelType) || (type == GrayscaleType))
3251 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3253 for (y=0; y < (long) image->rows; y++)
3255 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3256 if (p == (const PixelPacket *) NULL)
3258 for (x=0; x < (long) image->columns; x++)
3260 trace->bitmap[i++]=p->red;
3261 if (number_planes == 3)
3263 trace->bitmap[i++]=p->green;
3264 trace->bitmap[i++]=p->blue;
3269 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3271 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3272 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3277 at_splines_free(splines);
3278 at_bitmap_free(trace);
3279 at_output_opts_free(output_options);
3280 at_fitting_opts_free(fitting_options);
3285 message[MaxTextExtent],
3286 tuple[MaxTextExtent];
3291 register const IndexPacket
3294 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3295 (void) WriteBlobString(image,
3296 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3297 (void) WriteBlobString(image,
3298 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3299 (void) FormatMagickString(message,MaxTextExtent,
3300 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3301 (void) WriteBlobString(image,message);
3302 GetMagickPixelPacket(image,&pixel);
3303 for (y=0; y < (long) image->rows; y++)
3305 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3306 if (p == (const PixelPacket *) NULL)
3308 indexes=GetVirtualIndexQueue(image);
3309 for (x=0; x < (long) image->columns; x++)
3311 SetMagickPixelPacket(image,p,indexes+x,&pixel);
3312 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
3314 (void) FormatMagickString(message,MaxTextExtent,
3315 " <circle cx=\"%ld\" cy=\"%ld\" r=\"1\" fill=\"%s\"/>\n",x,y,tuple);
3316 (void) WriteBlobString(image,message);
3320 (void) WriteBlobString(image,"</svg>\n");
3326 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image)
3328 #define BezierQuantum 200
3334 keyword[MaxTextExtent],
3335 message[MaxTextExtent],
3336 name[MaxTextExtent],
3338 type[MaxTextExtent];
3380 Open output image file.
3382 assert(image_info != (const ImageInfo *) NULL);
3383 assert(image_info->signature == MagickSignature);
3384 assert(image != (Image *) NULL);
3385 assert(image->signature == MagickSignature);
3386 if (image->debug != MagickFalse)
3387 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3388 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3389 if (status == MagickFalse)
3391 value=GetImageArtifact(image,"SVG");
3392 if (value != (char *) NULL)
3394 (void) WriteBlobString(image,value);
3395 (void) CloseBlob(image);
3398 value=GetImageArtifact(image,"MVG");
3399 if (value == (char *) NULL)
3400 return(TraceSVGImage(image));
3404 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3405 (void) WriteBlobString(image,
3406 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3407 (void) WriteBlobString(image,
3408 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3409 (void) FormatMagickString(message,MaxTextExtent,
3410 "<svg width=\"%lu\" height=\"%lu\">\n",image->columns,image->rows);
3411 (void) WriteBlobString(image,message);
3413 Allocate primitive info memory.
3416 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3417 sizeof(*primitive_info));
3418 if (primitive_info == (PrimitiveInfo *) NULL)
3419 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3420 GetAffineMatrix(&affine);
3421 token=AcquireString(value);
3425 for (q=(const char *) value; *q != '\0'; )
3428 Interpret graphic primitive.
3430 GetMagickToken(q,&q,keyword);
3431 if (*keyword == '\0')
3433 if (*keyword == '#')
3438 if (active != MagickFalse)
3440 AffineToTransform(image,&affine);
3443 (void) WriteBlobString(image,"<desc>");
3444 (void) WriteBlobString(image,keyword+1);
3445 for ( ; (*q != '\n') && (*q != '\0'); q++)
3448 case '<': (void) WriteBlobString(image,"<"); break;
3449 case '>': (void) WriteBlobString(image,">"); break;
3450 case '&': (void) WriteBlobString(image,"&"); break;
3451 default: (void) WriteBlobByte(image,*q); break;
3453 (void) WriteBlobString(image,"</desc>\n");
3456 primitive_type=UndefinedPrimitive;
3464 if (LocaleCompare("affine",keyword) == 0)
3466 GetMagickToken(q,&q,token);
3467 affine.sx=atof(token);
3468 GetMagickToken(q,&q,token);
3470 GetMagickToken(q,&q,token);
3471 affine.rx=atof(token);
3472 GetMagickToken(q,&q,token);
3474 GetMagickToken(q,&q,token);
3475 affine.ry=atof(token);
3476 GetMagickToken(q,&q,token);
3478 GetMagickToken(q,&q,token);
3479 affine.sy=atof(token);
3480 GetMagickToken(q,&q,token);
3482 GetMagickToken(q,&q,token);
3483 affine.tx=atof(token);
3484 GetMagickToken(q,&q,token);
3486 GetMagickToken(q,&q,token);
3487 affine.ty=atof(token);
3490 if (LocaleCompare("angle",keyword) == 0)
3492 GetMagickToken(q,&q,token);
3493 affine.rx=atof(token);
3494 affine.ry=atof(token);
3497 if (LocaleCompare("arc",keyword) == 0)
3499 primitive_type=ArcPrimitive;
3508 if (LocaleCompare("bezier",keyword) == 0)
3510 primitive_type=BezierPrimitive;
3519 if (LocaleCompare("clip-path",keyword) == 0)
3521 GetMagickToken(q,&q,token);
3522 (void) FormatMagickString(message,MaxTextExtent,
3523 "clip-path:url(#%s);",token);
3524 (void) WriteBlobString(image,message);
3527 if (LocaleCompare("clip-rule",keyword) == 0)
3529 GetMagickToken(q,&q,token);
3530 (void) FormatMagickString(message,MaxTextExtent,
3531 "clip-rule:%s;",token);
3532 (void) WriteBlobString(image,message);
3535 if (LocaleCompare("clip-units",keyword) == 0)
3537 GetMagickToken(q,&q,token);
3538 (void) FormatMagickString(message,MaxTextExtent,
3539 "clipPathUnits=%s;",token);
3540 (void) WriteBlobString(image,message);
3543 if (LocaleCompare("circle",keyword) == 0)
3545 primitive_type=CirclePrimitive;
3548 if (LocaleCompare("color",keyword) == 0)
3550 primitive_type=ColorPrimitive;
3559 if (LocaleCompare("decorate",keyword) == 0)
3561 GetMagickToken(q,&q,token);
3562 (void) FormatMagickString(message,MaxTextExtent,
3563 "text-decoration:%s;",token);
3564 (void) WriteBlobString(image,message);
3573 if (LocaleCompare("ellipse",keyword) == 0)
3575 primitive_type=EllipsePrimitive;
3584 if (LocaleCompare("fill",keyword) == 0)
3586 GetMagickToken(q,&q,token);
3587 (void) FormatMagickString(message,MaxTextExtent,"fill:%s;",
3589 (void) WriteBlobString(image,message);
3592 if (LocaleCompare("fill-rule",keyword) == 0)
3594 GetMagickToken(q,&q,token);
3595 (void) FormatMagickString(message,MaxTextExtent,
3596 "fill-rule:%s;",token);
3597 (void) WriteBlobString(image,message);
3600 if (LocaleCompare("fill-opacity",keyword) == 0)
3602 GetMagickToken(q,&q,token);
3603 (void) FormatMagickString(message,MaxTextExtent,
3604 "fill-opacity:%s;",token);
3605 (void) WriteBlobString(image,message);
3608 if (LocaleCompare("font-family",keyword) == 0)
3610 GetMagickToken(q,&q,token);
3611 (void) FormatMagickString(message,MaxTextExtent,
3612 "font-family:%s;",token);
3613 (void) WriteBlobString(image,message);
3616 if (LocaleCompare("font-stretch",keyword) == 0)
3618 GetMagickToken(q,&q,token);
3619 (void) FormatMagickString(message,MaxTextExtent,
3620 "font-stretch:%s;",token);
3621 (void) WriteBlobString(image,message);
3624 if (LocaleCompare("font-style",keyword) == 0)
3626 GetMagickToken(q,&q,token);
3627 (void) FormatMagickString(message,MaxTextExtent,
3628 "font-style:%s;",token);
3629 (void) WriteBlobString(image,message);
3632 if (LocaleCompare("font-size",keyword) == 0)
3634 GetMagickToken(q,&q,token);
3635 (void) FormatMagickString(message,MaxTextExtent,
3636 "font-size:%s;",token);
3637 (void) WriteBlobString(image,message);
3640 if (LocaleCompare("font-weight",keyword) == 0)
3642 GetMagickToken(q,&q,token);
3643 (void) FormatMagickString(message,MaxTextExtent,
3644 "font-weight:%s;",token);
3645 (void) WriteBlobString(image,message);
3654 if (LocaleCompare("gradient-units",keyword) == 0)
3656 GetMagickToken(q,&q,token);
3659 if (LocaleCompare("text-align",keyword) == 0)
3661 GetMagickToken(q,&q,token);
3662 (void) FormatMagickString(message,MaxTextExtent,
3663 "text-align %s ",token);
3664 (void) WriteBlobString(image,message);
3667 if (LocaleCompare("text-anchor",keyword) == 0)
3669 GetMagickToken(q,&q,token);
3670 (void) FormatMagickString(message,MaxTextExtent,
3671 "text-anchor %s ",token);
3672 (void) WriteBlobString(image,message);
3681 if (LocaleCompare("image",keyword) == 0)
3683 GetMagickToken(q,&q,token);
3684 primitive_type=ImagePrimitive;
3693 if (LocaleCompare("line",keyword) == 0)
3695 primitive_type=LinePrimitive;
3704 if (LocaleCompare("matte",keyword) == 0)
3706 primitive_type=MattePrimitive;
3715 if (LocaleCompare("opacity",keyword) == 0)
3717 GetMagickToken(q,&q,token);
3718 (void) FormatMagickString(message,MaxTextExtent,"opacity %s ",
3720 (void) WriteBlobString(image,message);
3729 if (LocaleCompare("path",keyword) == 0)
3731 primitive_type=PathPrimitive;
3734 if (LocaleCompare("point",keyword) == 0)
3736 primitive_type=PointPrimitive;
3739 if (LocaleCompare("polyline",keyword) == 0)
3741 primitive_type=PolylinePrimitive;
3744 if (LocaleCompare("polygon",keyword) == 0)
3746 primitive_type=PolygonPrimitive;
3749 if (LocaleCompare("pop",keyword) == 0)
3751 GetMagickToken(q,&q,token);
3752 if (LocaleCompare("clip-path",token) == 0)
3754 (void) WriteBlobString(image,"</clipPath>\n");
3757 if (LocaleCompare("defs",token) == 0)
3759 (void) WriteBlobString(image,"</defs>\n");
3762 if (LocaleCompare("gradient",token) == 0)
3764 (void) FormatMagickString(message,MaxTextExtent,
3765 "</%sGradient>\n",type);
3766 (void) WriteBlobString(image,message);
3769 if (LocaleCompare("graphic-context",token) == 0)
3773 ThrowWriterException(DrawError,
3774 "UnbalancedGraphicContextPushPop");
3775 (void) WriteBlobString(image,"</g>\n");
3777 if (LocaleCompare("pattern",token) == 0)
3779 (void) WriteBlobString(image,"</pattern>\n");
3782 if (LocaleCompare("defs",token) == 0)
3783 (void) WriteBlobString(image,"</g>\n");
3786 if (LocaleCompare("push",keyword) == 0)
3788 GetMagickToken(q,&q,token);
3789 if (LocaleCompare("clip-path",token) == 0)
3791 GetMagickToken(q,&q,token);
3792 (void) FormatMagickString(message,MaxTextExtent,
3793 "<clipPath id=\"%s\">\n",token);
3794 (void) WriteBlobString(image,message);
3797 if (LocaleCompare("defs",token) == 0)
3799 (void) WriteBlobString(image,"<defs>\n");
3802 if (LocaleCompare("gradient",token) == 0)
3804 GetMagickToken(q,&q,token);
3805 (void) CopyMagickString(name,token,MaxTextExtent);
3806 GetMagickToken(q,&q,token);
3807 (void) CopyMagickString(type,token,MaxTextExtent);
3808 GetMagickToken(q,&q,token);
3809 svg_info.segment.x1=atof(token);
3810 svg_info.element.cx=atof(token);
3811 GetMagickToken(q,&q,token);
3813 GetMagickToken(q,&q,token);
3814 svg_info.segment.y1=atof(token);
3815 svg_info.element.cy=atof(token);
3816 GetMagickToken(q,&q,token);
3818 GetMagickToken(q,&q,token);
3819 svg_info.segment.x2=atof(token);
3820 svg_info.element.major=atof(token);
3821 GetMagickToken(q,&q,token);
3823 GetMagickToken(q,&q,token);
3824 svg_info.segment.y2=atof(token);
3825 svg_info.element.minor=atof(token);
3826 (void) FormatMagickString(message,MaxTextExtent,
3827 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3828 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3829 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3830 if (LocaleCompare(type,"radial") == 0)
3832 GetMagickToken(q,&q,token);
3834 GetMagickToken(q,&q,token);
3835 svg_info.element.angle=atof(token);
3836 (void) FormatMagickString(message,MaxTextExtent,
3837 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3838 "fx=\"%g\" fy=\"%g\">\n",type,name,svg_info.element.cx,
3839 svg_info.element.cy,svg_info.element.angle,
3840 svg_info.element.major,svg_info.element.minor);
3842 (void) WriteBlobString(image,message);
3845 if (LocaleCompare("graphic-context",token) == 0)
3850 AffineToTransform(image,&affine);
3853 (void) WriteBlobString(image,"<g style=\"");
3856 if (LocaleCompare("pattern",token) == 0)
3858 GetMagickToken(q,&q,token);
3859 (void) CopyMagickString(name,token,MaxTextExtent);
3860 GetMagickToken(q,&q,token);
3861 svg_info.bounds.x=atof(token);
3862 GetMagickToken(q,&q,token);
3864 GetMagickToken(q,&q,token);
3865 svg_info.bounds.y=atof(token);
3866 GetMagickToken(q,&q,token);
3868 GetMagickToken(q,&q,token);
3869 svg_info.bounds.width=atof(token);
3870 GetMagickToken(q,&q,token);
3872 GetMagickToken(q,&q,token);
3873 svg_info.bounds.height=atof(token);
3874 (void) FormatMagickString(message,MaxTextExtent,
3875 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3876 "height=\"%g\">\n",name,svg_info.bounds.x,svg_info.bounds.y,
3877 svg_info.bounds.width,svg_info.bounds.height);
3878 (void) WriteBlobString(image,message);
3889 if (LocaleCompare("rectangle",keyword) == 0)
3891 primitive_type=RectanglePrimitive;
3894 if (LocaleCompare("roundRectangle",keyword) == 0)
3896 primitive_type=RoundRectanglePrimitive;
3899 if (LocaleCompare("rotate",keyword) == 0)
3901 GetMagickToken(q,&q,token);
3902 (void) FormatMagickString(message,MaxTextExtent,"rotate(%s) ",
3904 (void) WriteBlobString(image,message);
3913 if (LocaleCompare("scale",keyword) == 0)
3915 GetMagickToken(q,&q,token);
3916 affine.sx=atof(token);
3917 GetMagickToken(q,&q,token);
3919 GetMagickToken(q,&q,token);
3920 affine.sy=atof(token);
3923 if (LocaleCompare("skewX",keyword) == 0)
3925 GetMagickToken(q,&q,token);
3926 (void) FormatMagickString(message,MaxTextExtent,"skewX(%s) ",
3928 (void) WriteBlobString(image,message);
3931 if (LocaleCompare("skewY",keyword) == 0)
3933 GetMagickToken(q,&q,token);
3934 (void) FormatMagickString(message,MaxTextExtent,"skewY(%s) ",
3936 (void) WriteBlobString(image,message);
3939 if (LocaleCompare("stop-color",keyword) == 0)
3942 color[MaxTextExtent];
3944 GetMagickToken(q,&q,token);
3945 (void) CopyMagickString(color,token,MaxTextExtent);
3946 GetMagickToken(q,&q,token);
3947 (void) FormatMagickString(message,MaxTextExtent,
3948 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
3949 (void) WriteBlobString(image,message);
3952 if (LocaleCompare("stroke",keyword) == 0)
3954 GetMagickToken(q,&q,token);
3955 (void) FormatMagickString(message,MaxTextExtent,"stroke:%s;",
3957 (void) WriteBlobString(image,message);
3960 if (LocaleCompare("stroke-antialias",keyword) == 0)
3962 GetMagickToken(q,&q,token);
3963 (void) FormatMagickString(message,MaxTextExtent,
3964 "stroke-antialias:%s;",token);
3965 (void) WriteBlobString(image,message);
3968 if (LocaleCompare("stroke-dasharray",keyword) == 0)
3976 GetMagickToken(p,&p,token);
3977 for (k=0; IsPoint(token); k++)
3978 GetMagickToken(p,&p,token);
3979 (void) WriteBlobString(image,"stroke-dasharray:");
3980 for (j=0; j < k; j++)
3982 GetMagickToken(q,&q,token);
3983 (void) FormatMagickString(message,MaxTextExtent,"%s ",
3985 (void) WriteBlobString(image,message);
3987 (void) WriteBlobString(image,";");
3990 GetMagickToken(q,&q,token);
3991 (void) FormatMagickString(message,MaxTextExtent,
3992 "stroke-dasharray:%s;",token);
3993 (void) WriteBlobString(image,message);
3996 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
3998 GetMagickToken(q,&q,token);
3999 (void) FormatMagickString(message,MaxTextExtent,
4000 "stroke-dashoffset:%s;",token);
4001 (void) WriteBlobString(image,message);
4004 if (LocaleCompare("stroke-linecap",keyword) == 0)
4006 GetMagickToken(q,&q,token);
4007 (void) FormatMagickString(message,MaxTextExtent,
4008 "stroke-linecap:%s;",token);
4009 (void) WriteBlobString(image,message);
4012 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4014 GetMagickToken(q,&q,token);
4015 (void) FormatMagickString(message,MaxTextExtent,
4016 "stroke-linejoin:%s;",token);
4017 (void) WriteBlobString(image,message);
4020 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4022 GetMagickToken(q,&q,token);
4023 (void) FormatMagickString(message,MaxTextExtent,
4024 "stroke-miterlimit:%s;",token);
4025 (void) WriteBlobString(image,message);
4028 if (LocaleCompare("stroke-opacity",keyword) == 0)
4030 GetMagickToken(q,&q,token);
4031 (void) FormatMagickString(message,MaxTextExtent,
4032 "stroke-opacity:%s;",token);
4033 (void) WriteBlobString(image,message);
4036 if (LocaleCompare("stroke-width",keyword) == 0)
4038 GetMagickToken(q,&q,token);
4039 (void) FormatMagickString(message,MaxTextExtent,
4040 "stroke-width:%s;",token);
4041 (void) WriteBlobString(image,message);
4050 if (LocaleCompare("text",keyword) == 0)
4052 primitive_type=TextPrimitive;
4055 if (LocaleCompare("text-antialias",keyword) == 0)
4057 GetMagickToken(q,&q,token);
4058 (void) FormatMagickString(message,MaxTextExtent,
4059 "text-antialias:%s;",token);
4060 (void) WriteBlobString(image,message);
4063 if (LocaleCompare("tspan",keyword) == 0)
4065 primitive_type=TextPrimitive;
4068 if (LocaleCompare("translate",keyword) == 0)
4070 GetMagickToken(q,&q,token);
4071 affine.tx=atof(token);
4072 GetMagickToken(q,&q,token);
4074 GetMagickToken(q,&q,token);
4075 affine.ty=atof(token);
4084 if (LocaleCompare("viewbox",keyword) == 0)
4086 GetMagickToken(q,&q,token);
4088 GetMagickToken(q,&q,token);
4089 GetMagickToken(q,&q,token);
4091 GetMagickToken(q,&q,token);
4092 GetMagickToken(q,&q,token);
4094 GetMagickToken(q,&q,token);
4095 GetMagickToken(q,&q,token);
4107 if (status == MagickFalse)
4109 if (primitive_type == UndefinedPrimitive)
4112 Parse the primitive attributes.
4116 for (x=0; *q != '\0'; x++)
4121 if (IsPoint(q) == MagickFalse)
4123 GetMagickToken(q,&q,token);
4124 point.x=atof(token);
4125 GetMagickToken(q,&q,token);
4127 GetMagickToken(q,&q,token);
4128 point.y=atof(token);
4129 GetMagickToken(q,(const char **) NULL,token);
4131 GetMagickToken(q,&q,token);
4132 primitive_info[i].primitive=primitive_type;
4133 primitive_info[i].point=point;
4134 primitive_info[i].coordinates=0;
4135 primitive_info[i].method=FloodfillMethod;
4137 if (i < (long) (number_points-6*BezierQuantum-360))
4139 number_points+=6*BezierQuantum+360;
4140 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4141 number_points,sizeof(*primitive_info));
4142 if (primitive_info == (PrimitiveInfo *) NULL)
4144 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4145 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4149 primitive_info[j].primitive=primitive_type;
4150 primitive_info[j].coordinates=x;
4151 primitive_info[j].method=FloodfillMethod;
4152 primitive_info[j].text=(char *) NULL;
4155 AffineToTransform(image,&affine);
4159 switch (primitive_type)
4161 case PointPrimitive:
4164 if (primitive_info[j].coordinates != 1)
4173 if (primitive_info[j].coordinates != 2)
4178 (void) FormatMagickString(message,MaxTextExtent,
4179 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4180 primitive_info[j].point.x,primitive_info[j].point.y,
4181 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4182 (void) WriteBlobString(image,message);
4185 case RectanglePrimitive:
4187 if (primitive_info[j].coordinates != 2)
4192 (void) FormatMagickString(message,MaxTextExtent,
4193 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4194 primitive_info[j].point.x,primitive_info[j].point.y,
4195 primitive_info[j+1].point.x-primitive_info[j].point.x,
4196 primitive_info[j+1].point.y-primitive_info[j].point.y);
4197 (void) WriteBlobString(image,message);
4200 case RoundRectanglePrimitive:
4202 if (primitive_info[j].coordinates != 3)
4207 (void) FormatMagickString(message,MaxTextExtent,
4208 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4209 "ry=\"%g\"/>\n",primitive_info[j].point.x,primitive_info[j].point.y,
4210 primitive_info[j+1].point.x-primitive_info[j].point.x,
4211 primitive_info[j+1].point.y-primitive_info[j].point.y,
4212 primitive_info[j+2].point.x,primitive_info[j+2].point.y);
4213 (void) WriteBlobString(image,message);
4218 if (primitive_info[j].coordinates != 3)
4225 case EllipsePrimitive:
4227 if (primitive_info[j].coordinates != 3)
4232 (void) FormatMagickString(message,MaxTextExtent,
4233 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4234 primitive_info[j].point.x,primitive_info[j].point.y,
4235 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4236 (void) WriteBlobString(image,message);
4239 case CirclePrimitive:
4245 if (primitive_info[j].coordinates != 2)
4250 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4251 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4252 (void) FormatMagickString(message,MaxTextExtent,
4253 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4254 primitive_info[j].point.x,primitive_info[j].point.y,
4256 (void) WriteBlobString(image,message);
4259 case PolylinePrimitive:
4261 if (primitive_info[j].coordinates < 2)
4266 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4267 (void) WriteBlobString(image,message);
4268 length=strlen(message);
4271 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4272 primitive_info[j].point.x,primitive_info[j].point.y);
4273 length+=strlen(message);
4276 (void) WriteBlobString(image,"\n ");
4277 length=strlen(message)+5;
4279 (void) WriteBlobString(image,message);
4281 (void) WriteBlobString(image,"\"/>\n");
4284 case PolygonPrimitive:
4286 if (primitive_info[j].coordinates < 3)
4291 primitive_info[i]=primitive_info[j];
4292 primitive_info[i].coordinates=0;
4293 primitive_info[j].coordinates++;
4295 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4296 (void) WriteBlobString(image,message);
4297 length=strlen(message);
4300 (void) FormatMagickString(message,MaxTextExtent,"%g,%g ",
4301 primitive_info[j].point.x,primitive_info[j].point.y);
4302 length+=strlen(message);
4305 (void) WriteBlobString(image,"\n ");
4306 length=strlen(message)+5;
4308 (void) WriteBlobString(image,message);
4310 (void) WriteBlobString(image,"\"/>\n");
4313 case BezierPrimitive:
4315 if (primitive_info[j].coordinates < 3)
4327 GetMagickToken(q,&q,token);
4328 number_attributes=1;
4329 for (p=token; *p != '\0'; p++)
4330 if (isalpha((int) *p))
4331 number_attributes++;
4332 if (i > (long) (number_points-6*BezierQuantum*number_attributes-1))
4334 number_points+=6*BezierQuantum*number_attributes;
4335 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4336 number_points,sizeof(*primitive_info));
4337 if (primitive_info == (PrimitiveInfo *) NULL)
4339 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4340 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4345 (void) WriteBlobString(image," <path d=\"");
4346 (void) WriteBlobString(image,token);
4347 (void) WriteBlobString(image,"\"/>\n");
4350 case ColorPrimitive:
4351 case MattePrimitive:
4353 if (primitive_info[j].coordinates != 1)
4358 GetMagickToken(q,&q,token);
4359 if (LocaleCompare("point",token) == 0)
4360 primitive_info[j].method=PointMethod;
4361 if (LocaleCompare("replace",token) == 0)
4362 primitive_info[j].method=ReplaceMethod;
4363 if (LocaleCompare("floodfill",token) == 0)
4364 primitive_info[j].method=FloodfillMethod;
4365 if (LocaleCompare("filltoborder",token) == 0)
4366 primitive_info[j].method=FillToBorderMethod;
4367 if (LocaleCompare("reset",token) == 0)
4368 primitive_info[j].method=ResetMethod;
4376 if (primitive_info[j].coordinates != 1)
4381 GetMagickToken(q,&q,token);
4382 (void) FormatMagickString(message,MaxTextExtent,
4383 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4384 primitive_info[j].point.y);
4385 (void) WriteBlobString(image,message);
4386 for (p=token; *p != '\0'; p++)
4389 case '<': (void) WriteBlobString(image,"<"); break;
4390 case '>': (void) WriteBlobString(image,">"); break;
4391 case '&': (void) WriteBlobString(image,"&"); break;
4392 default: (void) WriteBlobByte(image,*p); break;
4394 (void) WriteBlobString(image,"</text>\n");
4397 case ImagePrimitive:
4399 if (primitive_info[j].coordinates != 2)
4404 GetMagickToken(q,&q,token);
4405 (void) FormatMagickString(message,MaxTextExtent,
4406 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4407 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4408 primitive_info[j].point.y,primitive_info[j+1].point.x,
4409 primitive_info[j+1].point.y,token);
4410 (void) WriteBlobString(image,message);
4414 if (primitive_info == (PrimitiveInfo *) NULL)
4416 primitive_info[i].primitive=UndefinedPrimitive;
4417 if (status == MagickFalse)
4420 (void) WriteBlobString(image,"</svg>\n");
4422 Relinquish resources.
4424 token=DestroyString(token);
4425 if (primitive_info != (PrimitiveInfo *) NULL)
4426 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4427 (void) CloseBlob(image);