2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Scalable Vector Graphics Format %
21 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/composite-private.h"
52 #include "MagickCore/draw.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/gem.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/log.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/quantum-private.h"
66 #include "MagickCore/pixel-accessor.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/string_.h"
71 #include "MagickCore/string-private.h"
72 #include "MagickCore/token.h"
73 #include "MagickCore/utility.h"
74 #if defined(MAGICKCORE_XML_DELEGATE)
75 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
76 # if defined(__MINGW32__)
79 # include <win32config.h>
82 # include <libxml/parser.h>
83 # include <libxml/xmlmemory.h>
84 # include <libxml/parserInternals.h>
85 # include <libxml/xmlerror.h>
88 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
89 #include "autotrace/autotrace.h"
92 #if defined(MAGICKCORE_RSVG_DELEGATE)
93 #include "librsvg/rsvg.h"
94 #if defined(MAGICKCORE_CAIRO_DELEGATE)
95 #include "librsvg/rsvg-cairo.h"
97 #include "librsvg/librsvg-features.h"
101 Typedef declarations.
103 typedef struct _BoundingBox
112 typedef struct _ElementInfo
122 typedef struct _SVGInfo
176 #if defined(MAGICKCORE_XML_DELEGATE)
186 Forward declarations.
188 static MagickBooleanType
189 WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 % IsSVG()() returns MagickTrue if the image format type, identified by the
203 % magick string, is SVG.
205 % The format of the IsSVG method is:
207 % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
209 % A description of each parameter follows:
211 % o magick: compare image format pattern against these bytes.
213 % o length: Specifies the length of the magick string.
216 static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
220 if (LocaleNCompare((const char *) magick,"?xml",4) == 0)
225 #if defined(MAGICKCORE_XML_DELEGATE)
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 % R e a d S V G I m a g e %
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
238 % allocates the memory necessary for the new Image structure and returns a
239 % pointer to the new image.
241 % The format of the ReadSVGImage method is:
243 % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
245 % A description of each parameter follows:
247 % o image_info: the image info.
249 % o exception: return any errors or warnings in this structure.
253 static SVGInfo *AcquireSVGInfo(void)
258 svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
259 if (svg_info == (SVGInfo *) NULL)
260 return((SVGInfo *) NULL);
261 (void) ResetMagickMemory(svg_info,0,sizeof(*svg_info));
262 svg_info->text=AcquireString("");
263 svg_info->scale=(double *) AcquireMagickMemory(sizeof(*svg_info->scale));
264 if (svg_info->scale == (double *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 GetAffineMatrix(&svg_info->affine);
267 svg_info->scale[0]=ExpandAffine(&svg_info->affine);
271 static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
273 if (svg_info->text != (char *) NULL)
274 svg_info->text=DestroyString(svg_info->text);
275 if (svg_info->scale != (double *) NULL)
276 svg_info->scale=(double *) (svg_info->scale);
277 if (svg_info->title != (char *) NULL)
278 svg_info->title=DestroyString(svg_info->title);
279 if (svg_info->comment != (char *) NULL)
280 svg_info->comment=DestroyString(svg_info->comment);
281 return((SVGInfo *) RelinquishMagickMemory(svg_info));
284 static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
288 token[MaxTextExtent];
296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
297 assert(string != (const char *) NULL);
298 p=(const char *) string;
299 GetMagickToken(p,&p,token);
300 value=StringToDouble(token,(char **) NULL);
301 if (strchr(token,'%') != (char *) NULL)
309 if (svg_info->view_box.width == 0.0)
311 return(svg_info->view_box.width*value/100.0);
315 if (svg_info->view_box.height == 0.0)
317 return(svg_info->view_box.height*value/100.0);
319 alpha=value-svg_info->view_box.width;
320 beta=value-svg_info->view_box.height;
321 return(hypot(alpha,beta)/sqrt(2.0)/100.0);
323 GetMagickToken(p,&p,token);
324 if (LocaleNCompare(token,"cm",2) == 0)
325 return(DefaultResolution*svg_info->scale[0]/2.54*value);
326 if (LocaleNCompare(token,"em",2) == 0)
327 return(svg_info->pointsize*value);
328 if (LocaleNCompare(token,"ex",2) == 0)
329 return(svg_info->pointsize*value/2.0);
330 if (LocaleNCompare(token,"in",2) == 0)
331 return(DefaultResolution*svg_info->scale[0]*value);
332 if (LocaleNCompare(token,"mm",2) == 0)
333 return(DefaultResolution*svg_info->scale[0]/25.4*value);
334 if (LocaleNCompare(token,"pc",2) == 0)
335 return(DefaultResolution*svg_info->scale[0]/6.0*value);
336 if (LocaleNCompare(token,"pt",2) == 0)
337 return(svg_info->scale[0]*value);
338 if (LocaleNCompare(token,"px",2) == 0)
343 static void StripStyleTokens(char *message)
352 assert(message != (char *) NULL);
353 if (*message == '\0')
355 length=strlen(message);
357 while (isspace((int) ((unsigned char) *p)) != 0)
360 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
362 (void) CopyMagickMemory(message,p,(size_t) (q-p+1));
364 StripString(message);
367 static char **GetStyleTokens(void *context,const char *style,int *number_tokens)
379 svg_info=(SVGInfo *) context;
382 if (style == (const char *) NULL)
383 return((char **) NULL);
384 text=AcquireString(style);
385 (void) SubstituteString(&text,":","\n");
386 (void) SubstituteString(&text,";","\n");
387 tokens=StringToList(text);
388 text=DestroyString(text);
389 for (i=0; tokens[i] != (char *) NULL; i++)
390 StripStyleTokens(tokens[i]);
395 static char **GetTransformTokens(void *context,const char *text,
411 svg_info=(SVGInfo *) context;
413 if (text == (const char *) NULL)
414 return((char **) NULL);
416 Determine the number of arguments.
418 for (p=text; *p != '\0'; p++)
423 tokens=(char **) AcquireQuantumMemory(*number_tokens+2UL,sizeof(*tokens));
424 if (tokens == (char **) NULL)
426 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
427 ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
428 return((char **) NULL);
431 Convert string to an ASCII list.
435 for (q=p; *q != '\0'; q++)
437 if ((*q != '(') && (*q != ')') && (*q != '\0'))
439 tokens[i]=AcquireString(p);
440 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
441 StripString(tokens[i++]);
444 tokens[i]=AcquireString(p);
445 (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
446 StripString(tokens[i++]);
447 tokens[i]=(char *) NULL;
451 #if defined(__cplusplus) || defined(c_plusplus)
455 static int SVGIsStandalone(void *context)
461 Is this document tagged standalone?
463 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
464 svg_info=(SVGInfo *) context;
465 return(svg_info->document->standalone == 1);
468 static int SVGHasInternalSubset(void *context)
474 Does this document has an internal subset?
476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
477 " SAX.SVGHasInternalSubset()");
478 svg_info=(SVGInfo *) context;
479 return(svg_info->document->intSubset != NULL);
482 static int SVGHasExternalSubset(void *context)
488 Does this document has an external subset?
490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
491 " SAX.SVGHasExternalSubset()");
492 svg_info=(SVGInfo *) context;
493 return(svg_info->document->extSubset != NULL);
496 static void SVGInternalSubset(void *context,const xmlChar *name,
497 const xmlChar *external_id,const xmlChar *system_id)
503 Does this document has an internal subset?
505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
506 " SAX.internalSubset(%s, %s, %s)",(const char *) name,
507 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
508 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
509 svg_info=(SVGInfo *) context;
510 (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
513 static xmlParserInputPtr SVGResolveEntity(void *context,
514 const xmlChar *public_id,const xmlChar *system_id)
523 Special entity resolver, better left to the parser, it has more
524 context than the application layer. The default behaviour is to
525 not resolve the entities, in that case the ENTITY_REF nodes are
526 built in the structure (and the parameter values).
528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
529 " SAX.resolveEntity(%s, %s)",
530 (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
531 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
532 svg_info=(SVGInfo *) context;
533 stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
534 public_id,svg_info->parser);
538 static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
544 Get an entity by name.
546 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
548 svg_info=(SVGInfo *) context;
549 return(xmlGetDocEntity(svg_info->document,name));
552 static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
558 Get a parameter entity by name.
560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
561 " SAX.getParameterEntity(%s)",name);
562 svg_info=(SVGInfo *) context;
563 return(xmlGetParameterEntity(svg_info->document,name));
566 static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
567 const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
573 An entity definition has been parsed.
575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
576 " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
577 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
578 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
579 svg_info=(SVGInfo *) context;
580 if (svg_info->parser->inSubset == 1)
581 (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
584 if (svg_info->parser->inSubset == 2)
585 (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
589 static void SVGAttributeDeclaration(void *context,const xmlChar *element,
590 const xmlChar *name,int type,int value,const xmlChar *default_value,
591 xmlEnumerationPtr tree)
604 An attribute definition has been parsed.
606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
607 " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
609 svg_info=(SVGInfo *) context;
610 fullname=(xmlChar *) NULL;
611 prefix=(xmlChar *) NULL;
612 parser=svg_info->parser;
613 fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
614 if (parser->inSubset == 1)
615 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
616 element,fullname,prefix,(xmlAttributeType) type,
617 (xmlAttributeDefault) value,default_value,tree);
619 if (parser->inSubset == 2)
620 (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
621 element,fullname,prefix,(xmlAttributeType) type,
622 (xmlAttributeDefault) value,default_value,tree);
623 if (prefix != (xmlChar *) NULL)
625 if (fullname != (xmlChar *) NULL)
629 static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
630 xmlElementContentPtr content)
639 An element definition has been parsed.
641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
642 " SAX.elementDecl(%s, %d, ...)",name,type);
643 svg_info=(SVGInfo *) context;
644 parser=svg_info->parser;
645 if (parser->inSubset == 1)
646 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
647 name,(xmlElementTypeVal) type,content);
649 if (parser->inSubset == 2)
650 (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
651 name,(xmlElementTypeVal) type,content);
654 static void SVGNotationDeclaration(void *context,const xmlChar *name,
655 const xmlChar *public_id,const xmlChar *system_id)
664 What to do when a notation declaration has been parsed.
666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
667 " SAX.notationDecl(%s, %s, %s)",name,
668 public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
669 system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
670 svg_info=(SVGInfo *) context;
671 parser=svg_info->parser;
672 if (parser->inSubset == 1)
673 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
674 name,public_id,system_id);
676 if (parser->inSubset == 2)
677 (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
678 name,public_id,system_id);
681 static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
682 const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
688 What to do when an unparsed entity declaration is parsed.
690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
691 " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
692 public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
693 system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
694 svg_info=(SVGInfo *) context;
695 (void) xmlAddDocEntity(svg_info->document,name,
696 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
700 static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
706 Receive the document locator at startup, actually xmlDefaultSAXLocator.
709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
710 " SAX.setDocumentLocator()");
711 svg_info=(SVGInfo *) context;
715 static void SVGStartDocument(void *context)
724 Called when the document start being processed.
726 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
727 svg_info=(SVGInfo *) context;
728 GetExceptionInfo(svg_info->exception);
729 parser=svg_info->parser;
730 svg_info->document=xmlNewDoc(parser->version);
731 if (svg_info->document == (xmlDocPtr) NULL)
733 if (parser->encoding == NULL)
734 svg_info->document->encoding=(const xmlChar *) NULL;
736 svg_info->document->encoding=xmlStrdup(parser->encoding);
737 svg_info->document->standalone=parser->standalone;
740 static void SVGEndDocument(void *context)
746 Called when the document end has been detected.
748 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
749 svg_info=(SVGInfo *) context;
750 if (svg_info->offset != (char *) NULL)
751 svg_info->offset=DestroyString(svg_info->offset);
752 if (svg_info->stop_color != (char *) NULL)
753 svg_info->stop_color=DestroyString(svg_info->stop_color);
754 if (svg_info->scale != (double *) NULL)
755 svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
756 if (svg_info->text != (char *) NULL)
757 svg_info->text=DestroyString(svg_info->text);
758 if (svg_info->vertices != (char *) NULL)
759 svg_info->vertices=DestroyString(svg_info->vertices);
760 if (svg_info->url != (char *) NULL)
761 svg_info->url=DestroyString(svg_info->url);
762 #if defined(MAGICKCORE_XML_DELEGATE)
763 if (svg_info->document != (xmlDocPtr) NULL)
765 xmlFreeDoc(svg_info->document);
766 svg_info->document=(xmlDocPtr) NULL;
771 static void SVGStartElement(void *context,const xmlChar *name,
772 const xmlChar **attributes)
777 token[MaxTextExtent],
797 Called when an opening tag has been processed.
799 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
801 svg_info=(SVGInfo *) context;
803 svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
804 svg_info->n+1UL,sizeof(*svg_info->scale));
805 if (svg_info->scale == (double *) NULL)
807 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
808 ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
811 svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
812 color=AcquireString("none");
813 units=AcquireString("userSpaceOnUse");
814 value=(const char *) NULL;
815 if (attributes != (const xmlChar **) NULL)
816 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
818 keyword=(const char *) attributes[i];
819 value=(const char *) attributes[i+1];
825 if (LocaleCompare(keyword,"cx") == 0)
827 svg_info->element.cx=
828 GetUserSpaceCoordinateValue(svg_info,1,value);
831 if (LocaleCompare(keyword,"cy") == 0)
833 svg_info->element.cy=
834 GetUserSpaceCoordinateValue(svg_info,-1,value);
842 if (LocaleCompare(keyword,"fx") == 0)
844 svg_info->element.major=
845 GetUserSpaceCoordinateValue(svg_info,1,value);
848 if (LocaleCompare(keyword,"fy") == 0)
850 svg_info->element.minor=
851 GetUserSpaceCoordinateValue(svg_info,-1,value);
859 if (LocaleCompare(keyword,"height") == 0)
861 svg_info->bounds.height=
862 GetUserSpaceCoordinateValue(svg_info,-1,value);
870 if (LocaleCompare(keyword,"id") == 0)
872 (void) CopyMagickString(id,value,MaxTextExtent);
880 if (LocaleCompare(keyword,"r") == 0)
882 svg_info->element.angle=
883 GetUserSpaceCoordinateValue(svg_info,0,value);
891 if (LocaleCompare(keyword,"width") == 0)
893 svg_info->bounds.width=
894 GetUserSpaceCoordinateValue(svg_info,1,value);
902 if (LocaleCompare(keyword,"x") == 0)
904 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value)-
908 if (LocaleCompare(keyword,"x1") == 0)
910 svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
914 if (LocaleCompare(keyword,"x2") == 0)
916 svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
925 if (LocaleCompare(keyword,"y") == 0)
927 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value)-
931 if (LocaleCompare(keyword,"y1") == 0)
933 svg_info->segment.y1=
934 GetUserSpaceCoordinateValue(svg_info,-1,value);
937 if (LocaleCompare(keyword,"y2") == 0)
939 svg_info->segment.y2=
940 GetUserSpaceCoordinateValue(svg_info,-1,value);
949 if (strchr((char *) name,':') != (char *) NULL)
954 for ( ; *name != ':'; name++) ;
962 if (LocaleCompare((const char *) name,"circle") == 0)
964 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
967 if (LocaleCompare((const char *) name,"clipPath") == 0)
969 (void) FormatLocaleFile(svg_info->file,"push clip-path '%s'\n",id);
977 if (LocaleCompare((const char *) name,"defs") == 0)
979 (void) FormatLocaleFile(svg_info->file,"push defs\n");
987 if (LocaleCompare((const char *) name,"ellipse") == 0)
989 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
997 if (LocaleCompare((const char *) name,"g") == 0)
999 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1007 if (LocaleCompare((const char *) name,"image") == 0)
1009 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1017 if (LocaleCompare((const char *) name,"line") == 0)
1019 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1022 if (LocaleCompare((const char *) name,"linearGradient") == 0)
1024 (void) FormatLocaleFile(svg_info->file,
1025 "push gradient '%s' linear %g,%g %g,%g\n",id,
1026 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
1027 svg_info->segment.y2);
1035 if (LocaleCompare((const char *) name,"path") == 0)
1037 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1040 if (LocaleCompare((const char *) name,"pattern") == 0)
1042 (void) FormatLocaleFile(svg_info->file,
1043 "push pattern '%s' %g,%g %g,%g\n",id,
1044 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
1045 svg_info->bounds.height);
1048 if (LocaleCompare((const char *) name,"polygon") == 0)
1050 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1053 if (LocaleCompare((const char *) name,"polyline") == 0)
1055 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1063 if (LocaleCompare((const char *) name,"radialGradient") == 0)
1065 (void) FormatLocaleFile(svg_info->file,
1066 "push gradient '%s' radial %g,%g %g,%g %g\n",
1067 id,svg_info->element.cx,svg_info->element.cy,
1068 svg_info->element.major,svg_info->element.minor,
1069 svg_info->element.angle);
1072 if (LocaleCompare((const char *) name,"rect") == 0)
1074 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1082 if (LocaleCompare((const char *) name,"svg") == 0)
1084 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1092 if (LocaleCompare((const char *) name,"text") == 0)
1094 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1095 svg_info->bounds.x=0.0;
1096 svg_info->bounds.y=0.0;
1097 svg_info->bounds.width=0.0;
1098 svg_info->bounds.height=0.0;
1101 if (LocaleCompare((const char *) name,"tspan") == 0)
1103 if (*svg_info->text != '\0')
1114 text=EscapeString(svg_info->text,'\'');
1115 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
1116 svg_info->bounds.x-svg_info->center.x,svg_info->bounds.y-
1117 svg_info->center.y,text);
1118 text=DestroyString(text);
1119 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
1120 draw_info->pointsize=svg_info->pointsize;
1121 draw_info->text=AcquireString(svg_info->text);
1122 (void) ConcatenateString(&draw_info->text," ");
1123 (void) GetTypeMetrics(svg_info->image,draw_info,
1124 &metrics,svg_info->exception);
1125 svg_info->bounds.x+=metrics.width;
1126 draw_info=DestroyDrawInfo(draw_info);
1127 *svg_info->text='\0';
1129 (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
1137 if (attributes != (const xmlChar **) NULL)
1138 for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
1140 keyword=(const char *) attributes[i];
1141 value=(const char *) attributes[i+1];
1142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1143 " %s = %s",keyword,value);
1149 if (LocaleCompare(keyword,"angle") == 0)
1151 (void) FormatLocaleFile(svg_info->file,"angle %g\n",
1152 GetUserSpaceCoordinateValue(svg_info,0,value));
1160 if (LocaleCompare(keyword,"clip-path") == 0)
1162 (void) FormatLocaleFile(svg_info->file,"clip-path '%s'\n",value);
1165 if (LocaleCompare(keyword,"clip-rule") == 0)
1167 (void) FormatLocaleFile(svg_info->file,"clip-rule '%s'\n",value);
1170 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1172 (void) CloneString(&units,value);
1173 (void) FormatLocaleFile(svg_info->file,"clip-units '%s'\n",value);
1176 if (LocaleCompare(keyword,"color") == 0)
1178 (void) CloneString(&color,value);
1181 if (LocaleCompare(keyword,"cx") == 0)
1183 svg_info->element.cx=
1184 GetUserSpaceCoordinateValue(svg_info,1,value);
1187 if (LocaleCompare(keyword,"cy") == 0)
1189 svg_info->element.cy=
1190 GetUserSpaceCoordinateValue(svg_info,-1,value);
1198 if (LocaleCompare(keyword,"d") == 0)
1200 (void) CloneString(&svg_info->vertices,value);
1203 if (LocaleCompare(keyword,"dx") == 0)
1205 svg_info->bounds.x+=GetUserSpaceCoordinateValue(svg_info,1,value);
1208 if (LocaleCompare(keyword,"dy") == 0)
1210 svg_info->bounds.y+=
1211 GetUserSpaceCoordinateValue(svg_info,-1,value);
1219 if (LocaleCompare(keyword,"fill") == 0)
1221 if (LocaleCompare(value,"currentColor") == 0)
1223 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",color);
1226 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1229 if (LocaleCompare(keyword,"fillcolor") == 0)
1231 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",value);
1234 if (LocaleCompare(keyword,"fill-rule") == 0)
1236 (void) FormatLocaleFile(svg_info->file,"fill-rule '%s'\n",value);
1239 if (LocaleCompare(keyword,"fill-opacity") == 0)
1241 (void) FormatLocaleFile(svg_info->file,"fill-opacity '%s'\n",
1245 if (LocaleCompare(keyword,"font-family") == 0)
1247 (void) FormatLocaleFile(svg_info->file,"font-family '%s'\n",
1251 if (LocaleCompare(keyword,"font-stretch") == 0)
1253 (void) FormatLocaleFile(svg_info->file,"font-stretch '%s'\n",
1257 if (LocaleCompare(keyword,"font-style") == 0)
1259 (void) FormatLocaleFile(svg_info->file,"font-style '%s'\n",value);
1262 if (LocaleCompare(keyword,"font-size") == 0)
1264 svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
1265 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1266 svg_info->pointsize);
1269 if (LocaleCompare(keyword,"font-weight") == 0)
1271 (void) FormatLocaleFile(svg_info->file,"font-weight '%s'\n",
1280 if (LocaleCompare(keyword,"gradientTransform") == 0)
1287 GetAffineMatrix(&transform);
1288 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1289 tokens=GetTransformTokens(context,value,&number_tokens);
1290 for (j=0; j < (number_tokens-1); j+=2)
1292 keyword=(char *) tokens[j];
1293 if (keyword == (char *) NULL)
1295 value=(char *) tokens[j+1];
1296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1297 " %s: %s",keyword,value);
1299 GetAffineMatrix(&affine);
1305 if (LocaleCompare(keyword,"matrix") == 0)
1307 p=(const char *) value;
1308 GetMagickToken(p,&p,token);
1309 affine.sx=StringToDouble(value,(char **) NULL);
1310 GetMagickToken(p,&p,token);
1312 GetMagickToken(p,&p,token);
1313 affine.rx=StringToDouble(token,(char **) NULL);
1314 GetMagickToken(p,&p,token);
1316 GetMagickToken(p,&p,token);
1317 affine.ry=StringToDouble(token,(char **) NULL);
1318 GetMagickToken(p,&p,token);
1320 GetMagickToken(p,&p,token);
1321 affine.sy=StringToDouble(token,(char **) NULL);
1322 GetMagickToken(p,&p,token);
1324 GetMagickToken(p,&p,token);
1325 affine.tx=StringToDouble(token,(char **) NULL);
1326 GetMagickToken(p,&p,token);
1328 GetMagickToken(p,&p,token);
1329 affine.ty=StringToDouble(token,(char **) NULL);
1337 if (LocaleCompare(keyword,"rotate") == 0)
1342 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1343 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1344 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1345 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1346 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1354 if (LocaleCompare(keyword,"scale") == 0)
1356 for (p=(const char *) value; *p != '\0'; p++)
1357 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1360 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1361 affine.sy=affine.sx;
1364 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1365 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
1368 if (LocaleCompare(keyword,"skewX") == 0)
1370 affine.sx=svg_info->affine.sx;
1371 affine.ry=tan(DegreesToRadians(fmod(
1372 GetUserSpaceCoordinateValue(svg_info,1,value),
1374 affine.sy=svg_info->affine.sy;
1377 if (LocaleCompare(keyword,"skewY") == 0)
1379 affine.sx=svg_info->affine.sx;
1380 affine.rx=tan(DegreesToRadians(fmod(
1381 GetUserSpaceCoordinateValue(svg_info,-1,value),
1383 affine.sy=svg_info->affine.sy;
1391 if (LocaleCompare(keyword,"translate") == 0)
1393 for (p=(const char *) value; *p != '\0'; p++)
1394 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1397 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
1398 affine.ty=affine.tx;
1401 GetUserSpaceCoordinateValue(svg_info,-1,p+1);
1409 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
1410 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
1411 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
1412 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
1413 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
1415 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
1418 (void) FormatLocaleFile(svg_info->file,
1419 "affine %g %g %g %g %g %g\n",transform.sx,
1420 transform.rx,transform.ry,transform.sy,transform.tx,
1422 for (j=0; tokens[j] != (char *) NULL; j++)
1423 tokens[j]=DestroyString(tokens[j]);
1424 tokens=(char **) RelinquishMagickMemory(tokens);
1427 if (LocaleCompare(keyword,"gradientUnits") == 0)
1429 (void) CloneString(&units,value);
1430 (void) FormatLocaleFile(svg_info->file,"gradient-units '%s'\n",
1439 if (LocaleCompare(keyword,"height") == 0)
1441 svg_info->bounds.height=
1442 GetUserSpaceCoordinateValue(svg_info,-1,value);
1445 if (LocaleCompare(keyword,"href") == 0)
1447 (void) CloneString(&svg_info->url,value);
1455 if (LocaleCompare(keyword,"major") == 0)
1457 svg_info->element.major=
1458 GetUserSpaceCoordinateValue(svg_info,1,value);
1461 if (LocaleCompare(keyword,"minor") == 0)
1463 svg_info->element.minor=
1464 GetUserSpaceCoordinateValue(svg_info,-1,value);
1472 if (LocaleCompare(keyword,"offset") == 0)
1474 (void) CloneString(&svg_info->offset,value);
1477 if (LocaleCompare(keyword,"opacity") == 0)
1479 (void) FormatLocaleFile(svg_info->file,"opacity '%s'\n",value);
1487 if (LocaleCompare(keyword,"path") == 0)
1489 (void) CloneString(&svg_info->url,value);
1492 if (LocaleCompare(keyword,"points") == 0)
1494 (void) CloneString(&svg_info->vertices,value);
1502 if (LocaleCompare(keyword,"r") == 0)
1504 svg_info->element.major=
1505 GetUserSpaceCoordinateValue(svg_info,1,value);
1506 svg_info->element.minor=
1507 GetUserSpaceCoordinateValue(svg_info,-1,value);
1510 if (LocaleCompare(keyword,"rotate") == 0)
1515 angle=GetUserSpaceCoordinateValue(svg_info,0,value);
1516 (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
1517 svg_info->bounds.x,svg_info->bounds.y);
1518 svg_info->bounds.x=0;
1519 svg_info->bounds.y=0;
1520 (void) FormatLocaleFile(svg_info->file,"rotate %g\n",angle);
1523 if (LocaleCompare(keyword,"rx") == 0)
1525 if (LocaleCompare((const char *) name,"ellipse") == 0)
1526 svg_info->element.major=
1527 GetUserSpaceCoordinateValue(svg_info,1,value);
1530 GetUserSpaceCoordinateValue(svg_info,1,value);
1533 if (LocaleCompare(keyword,"ry") == 0)
1535 if (LocaleCompare((const char *) name,"ellipse") == 0)
1536 svg_info->element.minor=
1537 GetUserSpaceCoordinateValue(svg_info,-1,value);
1540 GetUserSpaceCoordinateValue(svg_info,-1,value);
1548 if (LocaleCompare(keyword,"stop-color") == 0)
1550 (void) CloneString(&svg_info->stop_color,value);
1553 if (LocaleCompare(keyword,"stroke") == 0)
1555 if (LocaleCompare(value,"currentColor") == 0)
1557 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",color);
1560 (void) FormatLocaleFile(svg_info->file,"stroke '%s'\n",value);
1563 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1565 (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
1566 LocaleCompare(value,"true") == 0);
1569 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1571 (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
1575 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1577 (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %s\n",
1581 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1583 (void) FormatLocaleFile(svg_info->file,"stroke-linecap '%s'\n",
1587 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1589 (void) FormatLocaleFile(svg_info->file,"stroke-linejoin '%s'\n",
1593 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1595 (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit '%s'\n",
1599 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1601 (void) FormatLocaleFile(svg_info->file,"stroke-opacity '%s'\n",
1605 if (LocaleCompare(keyword,"stroke-width") == 0)
1607 (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
1608 GetUserSpaceCoordinateValue(svg_info,1,value));
1611 if (LocaleCompare(keyword,"style") == 0)
1613 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1614 tokens=GetStyleTokens(context,value,&number_tokens);
1615 for (j=0; j < (number_tokens-1); j+=2)
1617 keyword=(char *) tokens[j];
1618 value=(char *) tokens[j+1];
1619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1620 " %s: %s",keyword,value);
1626 if (LocaleCompare(keyword,"clip-path") == 0)
1628 (void) FormatLocaleFile(svg_info->file,
1629 "clip-path '%s'\n",value);
1632 if (LocaleCompare(keyword,"clip-rule") == 0)
1634 (void) FormatLocaleFile(svg_info->file,
1635 "clip-rule '%s'\n",value);
1638 if (LocaleCompare(keyword,"clipPathUnits") == 0)
1640 (void) CloneString(&units,value);
1641 (void) FormatLocaleFile(svg_info->file,
1642 "clip-units '%s'\n",value);
1645 if (LocaleCompare(keyword,"color") == 0)
1647 (void) CloneString(&color,value);
1655 if (LocaleCompare(keyword,"fill") == 0)
1657 if (LocaleCompare(value,"currentColor") == 0)
1659 (void) FormatLocaleFile(svg_info->file,
1660 "fill '%s'\n",color);
1663 if (LocaleCompare(value,"#00000000") == 0)
1664 (void) FormatLocaleFile(svg_info->file,
1665 "fill '#000000'\n");
1667 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1671 if (LocaleCompare(keyword,"fillcolor") == 0)
1673 (void) FormatLocaleFile(svg_info->file,"fill '%s'\n",
1677 if (LocaleCompare(keyword,"fill-rule") == 0)
1679 (void) FormatLocaleFile(svg_info->file,
1680 "fill-rule '%s'\n",value);
1683 if (LocaleCompare(keyword,"fill-opacity") == 0)
1685 (void) FormatLocaleFile(svg_info->file,
1686 "fill-opacity '%s'\n",value);
1689 if (LocaleCompare(keyword,"font-family") == 0)
1691 (void) FormatLocaleFile(svg_info->file,
1692 "font-family '%s'\n",value);
1695 if (LocaleCompare(keyword,"font-stretch") == 0)
1697 (void) FormatLocaleFile(svg_info->file,
1698 "font-stretch '%s'\n",value);
1701 if (LocaleCompare(keyword,"font-style") == 0)
1703 (void) FormatLocaleFile(svg_info->file,
1704 "font-style '%s'\n",value);
1707 if (LocaleCompare(keyword,"font-size") == 0)
1709 svg_info->pointsize=GetUserSpaceCoordinateValue(
1711 (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
1712 svg_info->pointsize);
1715 if (LocaleCompare(keyword,"font-weight") == 0)
1717 (void) FormatLocaleFile(svg_info->file,
1718 "font-weight '%s'\n",value);
1726 if (LocaleCompare(keyword,"offset") == 0)
1728 (void) FormatLocaleFile(svg_info->file,"offset %g\n",
1729 GetUserSpaceCoordinateValue(svg_info,1,value));
1732 if (LocaleCompare(keyword,"opacity") == 0)
1734 (void) FormatLocaleFile(svg_info->file,
1735 "opacity '%s'\n",value);
1743 if (LocaleCompare(keyword,"stop-color") == 0)
1745 (void) CloneString(&svg_info->stop_color,value);
1748 if (LocaleCompare(keyword,"stroke") == 0)
1750 if (LocaleCompare(value,"currentColor") == 0)
1752 (void) FormatLocaleFile(svg_info->file,
1753 "stroke '%s'\n",color);
1756 if (LocaleCompare(value,"#00000000") == 0)
1757 (void) FormatLocaleFile(svg_info->file,
1758 "fill '#000000'\n");
1760 (void) FormatLocaleFile(svg_info->file,
1761 "stroke '%s'\n",value);
1764 if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
1766 (void) FormatLocaleFile(svg_info->file,
1767 "stroke-antialias %d\n",
1768 LocaleCompare(value,"true") == 0);
1771 if (LocaleCompare(keyword,"stroke-dasharray") == 0)
1773 (void) FormatLocaleFile(svg_info->file,
1774 "stroke-dasharray %s\n",value);
1777 if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
1779 (void) FormatLocaleFile(svg_info->file,
1780 "stroke-dashoffset %s\n",
1784 if (LocaleCompare(keyword,"stroke-linecap") == 0)
1786 (void) FormatLocaleFile(svg_info->file,
1787 "stroke-linecap '%s'\n",value);
1790 if (LocaleCompare(keyword,"stroke-linejoin") == 0)
1792 (void) FormatLocaleFile(svg_info->file,
1793 "stroke-linejoin '%s'\n",
1797 if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
1799 (void) FormatLocaleFile(svg_info->file,
1800 "stroke-miterlimit '%s'\n",
1804 if (LocaleCompare(keyword,"stroke-opacity") == 0)
1806 (void) FormatLocaleFile(svg_info->file,
1807 "stroke-opacity '%s'\n",value);
1810 if (LocaleCompare(keyword,"stroke-width") == 0)
1812 (void) FormatLocaleFile(svg_info->file,
1813 "stroke-width %g\n",
1814 GetUserSpaceCoordinateValue(svg_info,1,value));
1822 if (LocaleCompare(keyword,"text-align") == 0)
1824 (void) FormatLocaleFile(svg_info->file,
1825 "text-align '%s'\n",value);
1828 if (LocaleCompare(keyword,"text-anchor") == 0)
1830 (void) FormatLocaleFile(svg_info->file,
1831 "text-anchor '%s'\n",value);
1834 if (LocaleCompare(keyword,"text-decoration") == 0)
1836 if (LocaleCompare(value,"underline") == 0)
1837 (void) FormatLocaleFile(svg_info->file,
1838 "decorate underline\n");
1839 if (LocaleCompare(value,"line-through") == 0)
1840 (void) FormatLocaleFile(svg_info->file,
1841 "decorate line-through\n");
1842 if (LocaleCompare(value,"overline") == 0)
1843 (void) FormatLocaleFile(svg_info->file,
1844 "decorate overline\n");
1847 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1849 (void) FormatLocaleFile(svg_info->file,
1850 "text-antialias %d\n",
1851 LocaleCompare(value,"true") == 0);
1860 for (j=0; tokens[j] != (char *) NULL; j++)
1861 tokens[j]=DestroyString(tokens[j]);
1862 tokens=(char **) RelinquishMagickMemory(tokens);
1870 if (LocaleCompare(keyword,"text-align") == 0)
1872 (void) FormatLocaleFile(svg_info->file,"text-align '%s'\n",
1876 if (LocaleCompare(keyword,"text-anchor") == 0)
1878 (void) FormatLocaleFile(svg_info->file,"text-anchor '%s'\n",
1882 if (LocaleCompare(keyword,"text-decoration") == 0)
1884 if (LocaleCompare(value,"underline") == 0)
1885 (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
1886 if (LocaleCompare(value,"line-through") == 0)
1887 (void) FormatLocaleFile(svg_info->file,
1888 "decorate line-through\n");
1889 if (LocaleCompare(value,"overline") == 0)
1890 (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
1893 if (LocaleCompare(keyword,"text-antialiasing") == 0)
1895 (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
1896 LocaleCompare(value,"true") == 0);
1899 if (LocaleCompare(keyword,"transform") == 0)
1906 GetAffineMatrix(&transform);
1907 (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
1908 tokens=GetTransformTokens(context,value,&number_tokens);
1909 for (j=0; j < (number_tokens-1); j+=2)
1911 keyword=(char *) tokens[j];
1912 value=(char *) tokens[j+1];
1913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1914 " %s: %s",keyword,value);
1916 GetAffineMatrix(&affine);
1922 if (LocaleCompare(keyword,"matrix") == 0)
1924 p=(const char *) value;
1925 GetMagickToken(p,&p,token);
1926 affine.sx=StringToDouble(value,(char **) NULL);
1927 GetMagickToken(p,&p,token);
1929 GetMagickToken(p,&p,token);
1930 affine.rx=StringToDouble(token,(char **) NULL);
1931 GetMagickToken(p,&p,token);
1933 GetMagickToken(p,&p,token);
1934 affine.ry=StringToDouble(token,(char **) NULL);
1935 GetMagickToken(p,&p,token);
1937 GetMagickToken(p,&p,token);
1938 affine.sy=StringToDouble(token,(char **) NULL);
1939 GetMagickToken(p,&p,token);
1941 GetMagickToken(p,&p,token);
1942 affine.tx=StringToDouble(token,(char **) NULL);
1943 GetMagickToken(p,&p,token);
1945 GetMagickToken(p,&p,token);
1946 affine.ty=StringToDouble(token,(char **) NULL);
1954 if (LocaleCompare(keyword,"rotate") == 0)
1961 p=(const char *) value;
1962 GetMagickToken(p,&p,token);
1963 angle=StringToDouble(value,(char **) NULL);
1964 GetMagickToken(p,&p,token);
1966 GetMagickToken(p,&p,token);
1967 x=StringToDouble(token,(char **) NULL);
1968 GetMagickToken(p,&p,token);
1970 GetMagickToken(p,&p,token);
1971 y=StringToDouble(token,(char **) NULL);
1972 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
1973 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
1974 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
1975 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
1978 svg_info->center.x=x;
1979 svg_info->center.y=y;
1987 if (LocaleCompare(keyword,"scale") == 0)
1989 for (p=(const char *) value; *p != '\0'; p++)
1990 if ((isspace((int) ((unsigned char) *p)) != 0) ||
1993 affine.sx=GetUserSpaceCoordinateValue(svg_info,1,value);
1994 affine.sy=affine.sx;
1996 affine.sy=GetUserSpaceCoordinateValue(svg_info,-1,
1998 svg_info->scale[svg_info->n]=ExpandAffine(&affine);
2001 if (LocaleCompare(keyword,"skewX") == 0)
2003 affine.sx=svg_info->affine.sx;
2004 affine.ry=tan(DegreesToRadians(fmod(
2005 GetUserSpaceCoordinateValue(svg_info,1,value),
2007 affine.sy=svg_info->affine.sy;
2010 if (LocaleCompare(keyword,"skewY") == 0)
2012 affine.sx=svg_info->affine.sx;
2013 affine.rx=tan(DegreesToRadians(fmod(
2014 GetUserSpaceCoordinateValue(svg_info,-1,value),
2016 affine.sy=svg_info->affine.sy;
2024 if (LocaleCompare(keyword,"translate") == 0)
2026 for (p=(const char *) value; *p != '\0'; p++)
2027 if ((isspace((int) ((unsigned char) *p)) != 0) ||
2030 affine.tx=GetUserSpaceCoordinateValue(svg_info,1,value);
2031 affine.ty=affine.tx;
2033 affine.ty=GetUserSpaceCoordinateValue(svg_info,-1,
2042 transform.sx=affine.sx*current.sx+affine.ry*current.rx;
2043 transform.rx=affine.rx*current.sx+affine.sy*current.rx;
2044 transform.ry=affine.sx*current.ry+affine.ry*current.sy;
2045 transform.sy=affine.rx*current.ry+affine.sy*current.sy;
2046 transform.tx=affine.tx*current.sx+affine.ty*current.ry+
2048 transform.ty=affine.tx*current.rx+affine.ty*current.sy+
2051 (void) FormatLocaleFile(svg_info->file,
2052 "affine %g %g %g %g %g %g\n",transform.sx,transform.rx,
2053 transform.ry,transform.sy,transform.tx,transform.ty);
2054 for (j=0; tokens[j] != (char *) NULL; j++)
2055 tokens[j]=DestroyString(tokens[j]);
2056 tokens=(char **) RelinquishMagickMemory(tokens);
2064 if (LocaleCompare(keyword,"verts") == 0)
2066 (void) CloneString(&svg_info->vertices,value);
2069 if (LocaleCompare(keyword,"viewBox") == 0)
2071 p=(const char *) value;
2072 GetMagickToken(p,&p,token);
2073 svg_info->view_box.x=StringToDouble(token,(char **) NULL);
2074 GetMagickToken(p,&p,token);
2076 GetMagickToken(p,&p,token);
2077 svg_info->view_box.y=StringToDouble(token,(char **) NULL);
2078 GetMagickToken(p,&p,token);
2080 GetMagickToken(p,&p,token);
2081 svg_info->view_box.width=StringToDouble(token,
2083 if (svg_info->bounds.width == 0)
2084 svg_info->bounds.width=svg_info->view_box.width;
2085 GetMagickToken(p,&p,token);
2087 GetMagickToken(p,&p,token);
2088 svg_info->view_box.height=StringToDouble(token,
2090 if (svg_info->bounds.height == 0)
2091 svg_info->bounds.height=svg_info->view_box.height;
2099 if (LocaleCompare(keyword,"width") == 0)
2101 svg_info->bounds.width=
2102 GetUserSpaceCoordinateValue(svg_info,1,value);
2110 if (LocaleCompare(keyword,"x") == 0)
2112 svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
2115 if (LocaleCompare(keyword,"xlink:href") == 0)
2117 (void) CloneString(&svg_info->url,value);
2120 if (LocaleCompare(keyword,"x1") == 0)
2122 svg_info->segment.x1=
2123 GetUserSpaceCoordinateValue(svg_info,1,value);
2126 if (LocaleCompare(keyword,"x2") == 0)
2128 svg_info->segment.x2=
2129 GetUserSpaceCoordinateValue(svg_info,1,value);
2137 if (LocaleCompare(keyword,"y") == 0)
2139 svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
2142 if (LocaleCompare(keyword,"y1") == 0)
2144 svg_info->segment.y1=
2145 GetUserSpaceCoordinateValue(svg_info,-1,value);
2148 if (LocaleCompare(keyword,"y2") == 0)
2150 svg_info->segment.y2=
2151 GetUserSpaceCoordinateValue(svg_info,-1,value);
2160 if (LocaleCompare((const char *) name,"svg") == 0)
2162 if (svg_info->document->encoding != (const xmlChar *) NULL)
2163 (void) FormatLocaleFile(svg_info->file,"encoding \"%s\"\n",
2164 (const char *) svg_info->document->encoding);
2165 if (attributes != (const xmlChar **) NULL)
2173 if ((svg_info->view_box.width == 0.0) ||
2174 (svg_info->view_box.height == 0.0))
2175 svg_info->view_box=svg_info->bounds;
2176 svg_info->width=(size_t) floor(svg_info->bounds.width+0.5);
2177 svg_info->height=(size_t) floor(svg_info->bounds.height+0.5);
2178 (void) FormatLocaleFile(svg_info->file,"viewbox 0 0 %.20g %.20g\n",
2179 (double) svg_info->width,(double) svg_info->height);
2180 sx=(double) svg_info->width/svg_info->view_box.width;
2181 sy=(double) svg_info->height/svg_info->view_box.height;
2182 tx=svg_info->view_box.x != 0.0 ? (double) -sx*svg_info->view_box.x :
2184 ty=svg_info->view_box.y != 0.0 ? (double) -sy*svg_info->view_box.y :
2186 (void) FormatLocaleFile(svg_info->file,"affine %g 0 0 %g %g %g\n",
2190 (void) LogMagickEvent(CoderEvent,GetMagickModule()," )");
2191 units=DestroyString(units);
2192 if (color != (char *) NULL)
2193 color=DestroyString(color);
2196 static void SVGEndElement(void *context,const xmlChar *name)
2202 Called when the end of an element has been detected.
2204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2205 " SAX.endElement(%s)",name);
2206 svg_info=(SVGInfo *) context;
2207 if (strchr((char *) name,':') != (char *) NULL)
2210 Skip over namespace.
2212 for ( ; *name != ':'; name++) ;
2220 if (LocaleCompare((const char *) name,"circle") == 0)
2222 (void) FormatLocaleFile(svg_info->file,"circle %g,%g %g,%g\n",
2223 svg_info->element.cx,svg_info->element.cy,svg_info->element.cx,
2224 svg_info->element.cy+svg_info->element.minor);
2225 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2228 if (LocaleCompare((const char *) name,"clipPath") == 0)
2230 (void) FormatLocaleFile(svg_info->file,"pop clip-path\n");
2238 if (LocaleCompare((const char *) name,"defs") == 0)
2240 (void) FormatLocaleFile(svg_info->file,"pop defs\n");
2243 if (LocaleCompare((const char *) name,"desc") == 0)
2248 if (*svg_info->text == '\0')
2250 (void) fputc('#',svg_info->file);
2251 for (p=svg_info->text; *p != '\0'; p++)
2253 (void) fputc(*p,svg_info->file);
2255 (void) fputc('#',svg_info->file);
2257 (void) fputc('\n',svg_info->file);
2258 *svg_info->text='\0';
2266 if (LocaleCompare((const char *) name,"ellipse") == 0)
2271 angle=svg_info->element.angle;
2272 (void) FormatLocaleFile(svg_info->file,"ellipse %g,%g %g,%g 0,360\n",
2273 svg_info->element.cx,svg_info->element.cy,
2274 angle == 0.0 ? svg_info->element.major : svg_info->element.minor,
2275 angle == 0.0 ? svg_info->element.minor : svg_info->element.major);
2276 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2284 if (LocaleCompare((const char *) name,"g") == 0)
2286 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2294 if (LocaleCompare((const char *) name,"image") == 0)
2296 (void) FormatLocaleFile(svg_info->file,
2297 "image Over %g,%g %g,%g '%s'\n",svg_info->bounds.x,
2298 svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
2300 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2308 if (LocaleCompare((const char *) name,"line") == 0)
2310 (void) FormatLocaleFile(svg_info->file,"line %g,%g %g,%g\n",
2311 svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
2312 svg_info->segment.y2);
2313 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2316 if (LocaleCompare((const char *) name,"linearGradient") == 0)
2318 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2326 if (LocaleCompare((const char *) name,"pattern") == 0)
2328 (void) FormatLocaleFile(svg_info->file,"pop pattern\n");
2331 if (LocaleCompare((const char *) name,"path") == 0)
2333 (void) FormatLocaleFile(svg_info->file,"path '%s'\n",
2334 svg_info->vertices);
2335 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2338 if (LocaleCompare((const char *) name,"polygon") == 0)
2340 (void) FormatLocaleFile(svg_info->file,"polygon %s\n",
2341 svg_info->vertices);
2342 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2345 if (LocaleCompare((const char *) name,"polyline") == 0)
2347 (void) FormatLocaleFile(svg_info->file,"polyline %s\n",
2348 svg_info->vertices);
2349 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2357 if (LocaleCompare((const char *) name,"radialGradient") == 0)
2359 (void) FormatLocaleFile(svg_info->file,"pop gradient\n");
2362 if (LocaleCompare((const char *) name,"rect") == 0)
2364 if ((svg_info->radius.x == 0.0) && (svg_info->radius.y == 0.0))
2366 (void) FormatLocaleFile(svg_info->file,"rectangle %g,%g %g,%g\n",
2367 svg_info->bounds.x,svg_info->bounds.y,
2368 svg_info->bounds.x+svg_info->bounds.width,
2369 svg_info->bounds.y+svg_info->bounds.height);
2370 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2373 if (svg_info->radius.x == 0.0)
2374 svg_info->radius.x=svg_info->radius.y;
2375 if (svg_info->radius.y == 0.0)
2376 svg_info->radius.y=svg_info->radius.x;
2377 (void) FormatLocaleFile(svg_info->file,
2378 "roundRectangle %g,%g %g,%g %g,%g\n",
2379 svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.x+
2380 svg_info->bounds.width,svg_info->bounds.y+svg_info->bounds.height,
2381 svg_info->radius.x,svg_info->radius.y);
2382 svg_info->radius.x=0.0;
2383 svg_info->radius.y=0.0;
2384 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2392 if (LocaleCompare((const char *) name,"stop") == 0)
2394 (void) FormatLocaleFile(svg_info->file,"stop-color '%s' %s\n",
2395 svg_info->stop_color,svg_info->offset);
2398 if (LocaleCompare((const char *) name,"svg") == 0)
2400 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2408 if (LocaleCompare((const char *) name,"text") == 0)
2410 if (*svg_info->text != '\0')
2415 text=EscapeString(svg_info->text,'\'');
2416 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2417 svg_info->bounds.x,svg_info->bounds.y,text);
2418 text=DestroyString(text);
2419 *svg_info->text='\0';
2421 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2424 if (LocaleCompare((const char *) name,"tspan") == 0)
2426 if (*svg_info->text != '\0')
2437 text=EscapeString(svg_info->text,'\'');
2438 (void) FormatLocaleFile(svg_info->file,"text %g,%g '%s'\n",
2439 svg_info->bounds.x,svg_info->bounds.y,text);
2440 text=DestroyString(text);
2441 draw_info=CloneDrawInfo(svg_info->image_info,(DrawInfo *) NULL);
2442 draw_info->pointsize=svg_info->pointsize;
2443 draw_info->text=AcquireString(svg_info->text);
2444 (void) ConcatenateString(&draw_info->text," ");
2445 (void) GetTypeMetrics(svg_info->image,draw_info,&metrics,
2446 svg_info->exception);
2447 svg_info->bounds.x+=metrics.width;
2448 draw_info=DestroyDrawInfo(draw_info);
2449 *svg_info->text='\0';
2451 (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
2454 if (LocaleCompare((const char *) name,"title") == 0)
2456 if (*svg_info->text == '\0')
2458 (void) CloneString(&svg_info->title,svg_info->text);
2459 *svg_info->text='\0';
2467 *svg_info->text='\0';
2468 (void) ResetMagickMemory(&svg_info->element,0,sizeof(svg_info->element));
2469 (void) ResetMagickMemory(&svg_info->segment,0,sizeof(svg_info->segment));
2473 static void SVGCharacters(void *context,const xmlChar *c,int length)
2488 Receiving some characters from the parser.
2490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2491 " SAX.characters(%s,%.20g)",c,(double) length);
2492 svg_info=(SVGInfo *) context;
2493 text=(char *) AcquireQuantumMemory(length+1,sizeof(*text));
2494 if (text == (char *) NULL)
2497 for (i=0; i < (ssize_t) length; i++)
2501 if (svg_info->text == (char *) NULL)
2502 svg_info->text=text;
2505 (void) ConcatenateString(&svg_info->text,text);
2506 text=DestroyString(text);
2510 static void SVGReference(void *context,const xmlChar *name)
2519 Called when an entity reference is detected.
2521 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.reference(%s)",
2523 svg_info=(SVGInfo *) context;
2524 parser=svg_info->parser;
2525 if (parser == (xmlParserCtxtPtr) NULL)
2527 if (parser->node == (xmlNodePtr) NULL)
2530 (void) xmlAddChild(parser->node,xmlNewCharRef(svg_info->document,name));
2532 (void) xmlAddChild(parser->node,xmlNewReference(svg_info->document,name));
2535 static void SVGIgnorableWhitespace(void *context,const xmlChar *c,int length)
2541 Receiving some ignorable whitespaces from the parser.
2543 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2544 " SAX.ignorableWhitespace(%.30s, %d)",c,length);
2545 svg_info=(SVGInfo *) context;
2549 static void SVGProcessingInstructions(void *context,const xmlChar *target,
2550 const xmlChar *data)
2556 A processing instruction has been parsed.
2558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2559 " SAX.processingInstruction(%s, %s)",target,data);
2560 svg_info=(SVGInfo *) context;
2564 static void SVGComment(void *context,const xmlChar *value)
2570 A comment has been parsed.
2572 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.comment(%s)",
2574 svg_info=(SVGInfo *) context;
2575 if (svg_info->comment != (char *) NULL)
2576 (void) ConcatenateString(&svg_info->comment,"\n");
2577 (void) ConcatenateString(&svg_info->comment,(const char *) value);
2580 static void SVGWarning(void *context,const char *format,...)
2584 reason[MaxTextExtent];
2593 Display and format a warning messages, gives file, line, position and
2596 va_start(operands,format);
2597 svg_info=(SVGInfo *) context;
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.warning: ");
2599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2600 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2601 (void) vsprintf(reason,format,operands);
2603 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2605 message=GetExceptionMessage(errno);
2606 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
2607 DelegateWarning,reason,"`%s`",message);
2608 message=DestroyString(message);
2612 static void SVGError(void *context,const char *format,...)
2616 reason[MaxTextExtent];
2625 Display and format a error formats, gives file, line, position and
2628 va_start(operands,format);
2629 svg_info=(SVGInfo *) context;
2630 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.error: ");
2631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
2632 #if !defined(MAGICKCORE_HAVE_VSNPRINTF)
2633 (void) vsprintf(reason,format,operands);
2635 (void) vsnprintf(reason,MaxTextExtent,format,operands);
2637 message=GetExceptionMessage(errno);
2638 (void) ThrowMagickException(svg_info->exception,GetMagickModule(),CoderError,
2639 reason,"`%s`",message);
2640 message=DestroyString(message);
2644 static void SVGCDataBlock(void *context,const xmlChar *value,int length)
2656 Called when a pcdata block has been parsed.
2658 (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.pcdata(%s, %d)",
2660 svg_info=(SVGInfo *) context;
2661 parser=svg_info->parser;
2662 child=xmlGetLastChild(parser->node);
2663 if ((child != (xmlNodePtr) NULL) && (child->type == XML_CDATA_SECTION_NODE))
2665 xmlTextConcat(child,value,length);
2668 (void) xmlAddChild(parser->node,xmlNewCDataBlock(parser->myDoc,value,length));
2671 static void SVGExternalSubset(void *context,const xmlChar *name,
2672 const xmlChar *external_id,const xmlChar *system_id)
2687 Does this document has an external subset?
2689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2690 " SAX.externalSubset(%s, %s, %s)",name,
2691 (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
2692 (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
2693 svg_info=(SVGInfo *) context;
2694 parser=svg_info->parser;
2695 if (((external_id == NULL) && (system_id == NULL)) ||
2696 ((parser->validate == 0) || (parser->wellFormed == 0) ||
2697 (svg_info->document == 0)))
2699 input=SVGResolveEntity(context,external_id,system_id);
2702 (void) xmlNewDtd(svg_info->document,name,external_id,system_id);
2703 parser_context=(*parser);
2704 parser->inputTab=(xmlParserInputPtr *) xmlMalloc(5*sizeof(*parser->inputTab));
2705 if (parser->inputTab == (xmlParserInputPtr *) NULL)
2707 parser->errNo=XML_ERR_NO_MEMORY;
2708 parser->input=parser_context.input;
2709 parser->inputNr=parser_context.inputNr;
2710 parser->inputMax=parser_context.inputMax;
2711 parser->inputTab=parser_context.inputTab;
2717 xmlPushInput(parser,input);
2718 (void) xmlSwitchEncoding(parser,xmlDetectCharEncoding(parser->input->cur,4));
2719 if (input->filename == (char *) NULL)
2720 input->filename=(char *) xmlStrdup(system_id);
2723 input->base=parser->input->cur;
2724 input->cur=parser->input->cur;
2726 xmlParseExternalSubset(parser,external_id,system_id);
2727 while (parser->inputNr > 1)
2728 (void) xmlPopInput(parser);
2729 xmlFreeInputStream(parser->input);
2730 xmlFree(parser->inputTab);
2731 parser->input=parser_context.input;
2732 parser->inputNr=parser_context.inputNr;
2733 parser->inputMax=parser_context.inputMax;
2734 parser->inputTab=parser_context.inputTab;
2737 #if defined(MAGICKCORE_RSVG_DELEGATE)
2738 static void SVGSetImageSize(int *width,int *height,gpointer context)
2743 image=(Image *) context;
2744 *width=(int) (*width*image->resolution.x/72.0);
2745 *height=(int) (*height*image->resolution.y/72.0);
2749 #if defined(__cplusplus) || defined(c_plusplus)
2753 static Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
2756 filename[MaxTextExtent];
2775 message[MaxTextExtent];
2786 assert(image_info != (const ImageInfo *) NULL);
2787 assert(image_info->signature == MagickSignature);
2788 assert(exception != (ExceptionInfo *) NULL);
2789 if (image_info->debug != MagickFalse)
2790 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2791 image_info->filename);
2792 assert(exception->signature == MagickSignature);
2793 image=AcquireImage(image_info,exception);
2794 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2795 if (status == MagickFalse)
2797 image=DestroyImageList(image);
2798 return((Image *) NULL);
2800 if (LocaleCompare(image_info->magick,"MSVG") != 0)
2802 #if defined(MAGICKCORE_RSVG_DELEGATE)
2803 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2810 register unsigned char
2823 register const guchar
2846 svg_handle=rsvg_handle_new();
2847 if (svg_handle == (RsvgHandle *) NULL)
2848 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2849 rsvg_handle_set_base_uri(svg_handle,image_info->filename);
2850 rsvg_handle_set_size_callback(svg_handle,SVGSetImageSize,image,NULL);
2851 if ((image->resolution.x != 72.0) && (image->resolution.y != 72.0))
2852 rsvg_handle_set_dpi_x_y(svg_handle,image->resolution.x,
2853 image->resolution.y);
2854 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
2856 error=(GError *) NULL;
2857 (void) rsvg_handle_write(svg_handle,message,n,&error);
2858 if (error != (GError *) NULL)
2859 g_error_free(error);
2861 error=(GError *) NULL;
2862 rsvg_handle_close(svg_handle,&error);
2863 if (error != (GError *) NULL)
2864 g_error_free(error);
2865 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2866 rsvg_handle_get_dimensions(svg_handle,&dimension_info);
2867 image->columns=dimension_info.width;
2868 image->rows=dimension_info.height;
2869 pixels=(unsigned char *) NULL;
2871 pixel_info=rsvg_handle_get_pixbuf(svg_handle);
2872 rsvg_handle_free(svg_handle);
2873 image->columns=gdk_pixbuf_get_width(pixel_info);
2874 image->rows=gdk_pixbuf_get_height(pixel_info);
2876 image->matte=MagickTrue;
2877 SetImageProperty(image,"svg:base-uri",
2878 rsvg_handle_get_base_uri(svg_handle),exception);
2879 SetImageProperty(image,"svg:title",rsvg_handle_get_title(svg_handle),
2881 SetImageProperty(image,"svg:description",
2882 rsvg_handle_get_desc(svg_handle),exception);
2883 if ((image->columns == 0) || (image->rows == 0))
2885 #if !defined(MAGICKCORE_CAIRO_DELEGATE)
2886 g_object_unref(G_OBJECT(pixel_info));
2888 g_object_unref(svg_handle);
2889 ThrowReaderException(MissingDelegateError,
2890 "NoDecodeDelegateForThisImageFormat");
2892 if (image_info->ping == MagickFalse)
2894 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2895 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,4*
2896 image->rows*sizeof(*pixels));
2897 if (pixels == (unsigned char *) NULL)
2899 g_object_unref(svg_handle);
2900 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2903 (void) SetImageBackgroundColor(image,exception);
2904 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2905 cairo_surface=cairo_image_surface_create_for_data(pixels,
2906 CAIRO_FORMAT_ARGB32,image->columns,image->rows,4*image->columns);
2907 if (cairo_surface == (cairo_surface_t *) NULL)
2909 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2910 g_object_unref(svg_handle);
2911 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2913 cairo_info=cairo_create(cairo_surface);
2914 cairo_set_operator(cairo_info,CAIRO_OPERATOR_CLEAR);
2915 cairo_paint(cairo_info);
2916 cairo_set_operator(cairo_info,CAIRO_OPERATOR_OVER);
2917 rsvg_handle_render_cairo(svg_handle,cairo_info);
2918 cairo_destroy(cairo_info);
2919 cairo_surface_destroy(cairo_surface);
2920 g_object_unref(svg_handle);
2923 p=gdk_pixbuf_get_pixels(pixel_info);
2925 GetPixelInfo(image,&fill_color);
2926 for (y=0; y < (ssize_t) image->rows; y++)
2928 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2929 if (q == (Quantum *) NULL)
2931 for (x=0; x < (ssize_t) image->columns; x++)
2933 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2934 fill_color.blue=ScaleCharToQuantum(*p++);
2935 fill_color.green=ScaleCharToQuantum(*p++);
2936 fill_color.red=ScaleCharToQuantum(*p++);
2938 fill_color.red=ScaleCharToQuantum(*p++);
2939 fill_color.green=ScaleCharToQuantum(*p++);
2940 fill_color.blue=ScaleCharToQuantum(*p++);
2942 fill_color.alpha=ScaleCharToQuantum(*p++);
2943 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2948 gamma=1.0-QuantumScale*fill_color.alpha;
2949 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2950 fill_color.blue*=gamma;
2951 fill_color.green*=gamma;
2952 fill_color.red*=gamma;
2955 CompositePixelOver(image,&fill_color,fill_color.alpha,q,
2956 (MagickRealType) GetPixelAlpha(image,q),q);
2957 q+=GetPixelChannels(image);
2959 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2961 if (image->previous == (Image *) NULL)
2963 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2965 if (status == MagickFalse)
2970 #if defined(MAGICKCORE_CAIRO_DELEGATE)
2971 if (pixels != (unsigned char *) NULL)
2972 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2974 g_object_unref(G_OBJECT(pixel_info));
2976 (void) CloseBlob(image);
2977 return(GetFirstImageInList(image));
2984 unique_file=AcquireUniqueFileResource(filename);
2985 if (unique_file != -1)
2986 file=fdopen(unique_file,"w");
2987 if ((unique_file == -1) || (file == (FILE *) NULL))
2989 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
2990 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2992 image=DestroyImageList(image);
2993 return((Image *) NULL);
2998 svg_info=AcquireSVGInfo();
2999 if (svg_info == (SVGInfo *) NULL)
3000 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3001 svg_info->file=file;
3002 svg_info->exception=exception;
3003 svg_info->image=image;
3004 svg_info->image_info=image_info;
3005 svg_info->bounds.width=image->columns;
3006 svg_info->bounds.height=image->rows;
3007 if (image_info->size != (char *) NULL)
3008 (void) CloneString(&svg_info->size,image_info->size);
3009 if (image->debug != MagickFalse)
3010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"begin SAX");
3012 (void) xmlSubstituteEntitiesDefault(1);
3013 (void) ResetMagickMemory(&sax_modules,0,sizeof(sax_modules));
3014 sax_modules.internalSubset=SVGInternalSubset;
3015 sax_modules.isStandalone=SVGIsStandalone;
3016 sax_modules.hasInternalSubset=SVGHasInternalSubset;
3017 sax_modules.hasExternalSubset=SVGHasExternalSubset;
3018 sax_modules.resolveEntity=SVGResolveEntity;
3019 sax_modules.getEntity=SVGGetEntity;
3020 sax_modules.entityDecl=SVGEntityDeclaration;
3021 sax_modules.notationDecl=SVGNotationDeclaration;
3022 sax_modules.attributeDecl=SVGAttributeDeclaration;
3023 sax_modules.elementDecl=SVGElementDeclaration;
3024 sax_modules.unparsedEntityDecl=SVGUnparsedEntityDeclaration;
3025 sax_modules.setDocumentLocator=SVGSetDocumentLocator;
3026 sax_modules.startDocument=SVGStartDocument;
3027 sax_modules.endDocument=SVGEndDocument;
3028 sax_modules.startElement=SVGStartElement;
3029 sax_modules.endElement=SVGEndElement;
3030 sax_modules.reference=SVGReference;
3031 sax_modules.characters=SVGCharacters;
3032 sax_modules.ignorableWhitespace=SVGIgnorableWhitespace;
3033 sax_modules.processingInstruction=SVGProcessingInstructions;
3034 sax_modules.comment=SVGComment;
3035 sax_modules.warning=SVGWarning;
3036 sax_modules.error=SVGError;
3037 sax_modules.fatalError=SVGError;
3038 sax_modules.getParameterEntity=SVGGetParameterEntity;
3039 sax_modules.cdataBlock=SVGCDataBlock;
3040 sax_modules.externalSubset=SVGExternalSubset;
3041 sax_handler=(&sax_modules);
3042 n=ReadBlob(image,MaxTextExtent,message);
3045 svg_info->parser=xmlCreatePushParserCtxt(sax_handler,svg_info,(char *)
3046 message,n,image->filename);
3047 while ((n=ReadBlob(image,MaxTextExtent,message)) != 0)
3049 status=xmlParseChunk(svg_info->parser,(char *) message,(int) n,0);
3054 (void) xmlParseChunk(svg_info->parser,(char *) message,0,1);
3055 xmlFreeParserCtxt(svg_info->parser);
3056 if (image->debug != MagickFalse)
3057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");
3059 (void) fclose(file);
3060 (void) CloseBlob(image);
3061 image->columns=svg_info->width;
3062 image->rows=svg_info->height;
3063 if (exception->severity >= ErrorException)
3065 image=DestroyImage(image);
3066 return((Image *) NULL);
3068 if (image_info->ping == MagickFalse)
3076 image=DestroyImage(image);
3077 image=(Image *) NULL;
3078 read_info=CloneImageInfo(image_info);
3079 SetImageInfoBlob(read_info,(void *) NULL,0);
3080 if (read_info->density != (char *) NULL)
3081 read_info->density=DestroyString(read_info->density);
3082 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"mvg:%s",
3084 image=ReadImage(read_info,exception);
3085 read_info=DestroyImageInfo(read_info);
3086 if (image != (Image *) NULL)
3087 (void) CopyMagickString(image->filename,image_info->filename,
3091 Relinquish resources.
3093 if (image != (Image *) NULL)
3095 if (svg_info->title != (char *) NULL)
3096 (void) SetImageProperty(image,"svg:title",svg_info->title,exception);
3097 if (svg_info->comment != (char *) NULL)
3098 (void) SetImageProperty(image,"svg:comment",svg_info->comment,
3101 svg_info=DestroySVGInfo(svg_info);
3102 (void) RelinquishUniqueFileResource(filename);
3103 return(GetFirstImageInList(image));
3108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3112 % R e g i s t e r S V G I m a g e %
3116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3118 % RegisterSVGImage() adds attributes for the SVG image format to
3119 % the list of supported formats. The attributes include the image format
3120 % tag, a method to read and/or write the format, whether the format
3121 % supports the saving of more than one frame to the same file or blob,
3122 % whether the format supports native in-memory I/O, and a brief
3123 % description of the format.
3125 % The format of the RegisterSVGImage method is:
3127 % size_t RegisterSVGImage(void)
3130 ModuleExport size_t RegisterSVGImage(void)
3133 version[MaxTextExtent];
3139 #if defined(LIBXML_DOTTED_VERSION)
3140 (void) CopyMagickString(version,"XML " LIBXML_DOTTED_VERSION,MaxTextExtent);
3142 #if defined(MAGICKCORE_RSVG_DELEGATE)
3144 (void) FormatLocaleString(version,MaxTextExtent,"RSVG %d.%d.%d",
3145 LIBRSVG_MAJOR_VERSION,LIBRSVG_MINOR_VERSION,LIBRSVG_MICRO_VERSION);
3147 entry=SetMagickInfo("SVG");
3148 #if defined(MAGICKCORE_XML_DELEGATE)
3149 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3151 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3152 entry->blob_support=MagickFalse;
3153 entry->seekable_stream=MagickFalse;
3154 entry->description=ConstantString("Scalable Vector Graphics");
3155 if (*version != '\0')
3156 entry->version=ConstantString(version);
3157 entry->magick=(IsImageFormatHandler *) IsSVG;
3158 entry->module=ConstantString("SVG");
3159 (void) RegisterMagickInfo(entry);
3160 entry=SetMagickInfo("SVGZ");
3161 #if defined(MAGICKCORE_XML_DELEGATE)
3162 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3164 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3165 entry->blob_support=MagickFalse;
3166 entry->seekable_stream=MagickFalse;
3167 entry->description=ConstantString("Compressed Scalable Vector Graphics");
3168 if (*version != '\0')
3169 entry->version=ConstantString(version);
3170 entry->magick=(IsImageFormatHandler *) IsSVG;
3171 entry->module=ConstantString("SVG");
3172 (void) RegisterMagickInfo(entry);
3173 entry=SetMagickInfo("MSVG");
3174 #if defined(MAGICKCORE_XML_DELEGATE)
3175 entry->decoder=(DecodeImageHandler *) ReadSVGImage;
3177 entry->encoder=(EncodeImageHandler *) WriteSVGImage;
3178 entry->blob_support=MagickFalse;
3179 entry->seekable_stream=MagickFalse;
3180 entry->description=ConstantString("ImageMagick's own SVG internal renderer");
3181 entry->magick=(IsImageFormatHandler *) IsSVG;
3182 entry->module=ConstantString("SVG");
3183 (void) RegisterMagickInfo(entry);
3184 return(MagickImageCoderSignature);
3188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3192 % U n r e g i s t e r S V G I m a g e %
3196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3198 % UnregisterSVGImage() removes format registrations made by the
3199 % SVG module from the list of supported formats.
3201 % The format of the UnregisterSVGImage method is:
3203 % UnregisterSVGImage(void)
3206 ModuleExport void UnregisterSVGImage(void)
3208 (void) UnregisterMagickInfo("SVGZ");
3209 (void) UnregisterMagickInfo("SVG");
3210 (void) UnregisterMagickInfo("MSVG");
3211 #if defined(MAGICKCORE_RSVG_DELEGATE)
3217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3221 % W r i t e S V G I m a g e %
3225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3227 % WriteSVGImage() writes a image in the SVG - XML based W3C standard
3230 % The format of the WriteSVGImage method is:
3232 % MagickBooleanType WriteSVGImage(const ImageInfo *image_info,
3233 % Image *image,ExceptionInfo *exception)
3235 % A description of each parameter follows.
3237 % o image_info: the image info.
3239 % o image: The image.
3241 % o exception: return any errors or warnings in this structure.
3245 static void AffineToTransform(Image *image,AffineMatrix *affine)
3248 transform[MaxTextExtent];
3250 if ((fabs(affine->tx) < MagickEpsilon) && (fabs(affine->ty) < MagickEpsilon))
3252 if ((fabs(affine->rx) < MagickEpsilon) &&
3253 (fabs(affine->ry) < MagickEpsilon))
3255 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3256 (fabs(affine->sy-1.0) < MagickEpsilon))
3258 (void) WriteBlobString(image,"\">\n");
3261 (void) FormatLocaleString(transform,MaxTextExtent,
3262 "\" transform=\"scale(%g,%g)\">\n",affine->sx,affine->sy);
3263 (void) WriteBlobString(image,transform);
3268 if ((fabs(affine->sx-affine->sy) < MagickEpsilon) &&
3269 (fabs(affine->rx+affine->ry) < MagickEpsilon) &&
3270 (fabs(affine->sx*affine->sx+affine->rx*affine->rx-1.0) <
3276 theta=(180.0/MagickPI)*atan2(affine->rx,affine->sx);
3277 (void) FormatLocaleString(transform,MaxTextExtent,
3278 "\" transform=\"rotate(%g)\">\n",theta);
3279 (void) WriteBlobString(image,transform);
3286 if ((fabs(affine->sx-1.0) < MagickEpsilon) &&
3287 (fabs(affine->rx) < MagickEpsilon) &&
3288 (fabs(affine->ry) < MagickEpsilon) &&
3289 (fabs(affine->sy-1.0) < MagickEpsilon))
3291 (void) FormatLocaleString(transform,MaxTextExtent,
3292 "\" transform=\"translate(%g,%g)\">\n",affine->tx,affine->ty);
3293 (void) WriteBlobString(image,transform);
3297 (void) FormatLocaleString(transform,MaxTextExtent,
3298 "\" transform=\"matrix(%g %g %g %g %g %g)\">\n",
3299 affine->sx,affine->rx,affine->ry,affine->sy,affine->tx,affine->ty);
3300 (void) WriteBlobString(image,transform);
3303 static MagickBooleanType IsPoint(const char *point)
3311 value=strtol(point,&p,10);
3313 return(p != point ? MagickTrue : MagickFalse);
3316 static MagickBooleanType TraceSVGImage(Image *image,ExceptionInfo *exception)
3321 register const Quantum
3327 #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
3332 at_fitting_opts_type
3351 Trace image and write as SVG.
3353 fitting_options=at_fitting_opts_new();
3354 output_options=at_output_opts_new();
3355 type=GetImageType(image,exception);
3357 if ((type == BilevelType) || (type == GrayscaleType))
3359 trace=at_bitmap_new(image->columns,image->rows,number_planes);
3361 for (y=0; y < (ssize_t) image->rows; y++)
3363 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3364 if (p == (const Quantum *) NULL)
3366 for (x=0; x < (ssize_t) image->columns; x++)
3368 trace->bitmap[i++]=GetPixelRed(image,p);
3369 if (number_planes == 3)
3371 trace->bitmap[i++]=GetPixelGreen(image,p);
3372 trace->bitmap[i++]=GetPixelBlue(image,p);
3374 p+=GetPixelChannels(image);
3377 splines=at_splines_new_full(trace,fitting_options,NULL,NULL,NULL,NULL,NULL,
3379 at_splines_write(at_output_get_handler_by_suffix((char *) "svg"),
3380 GetBlobFileHandle(image),image->filename,output_options,splines,NULL,
3385 at_splines_free(splines);
3386 at_bitmap_free(trace);
3387 at_output_opts_free(output_options);
3388 at_fitting_opts_free(fitting_options);
3393 message[MaxTextExtent],
3394 tuple[MaxTextExtent];
3399 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3400 (void) WriteBlobString(image,
3401 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3402 (void) WriteBlobString(image,
3403 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3404 (void) FormatLocaleString(message,MaxTextExtent,
3405 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,
3406 (double) image->rows);
3407 (void) WriteBlobString(image,message);
3408 GetPixelInfo(image,&pixel);
3409 for (y=0; y < (ssize_t) image->rows; y++)
3411 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3412 if (p == (const Quantum *) NULL)
3414 for (x=0; x < (ssize_t) image->columns; x++)
3416 GetPixelInfoPixel(image,p,&pixel);
3417 (void) QueryColorname(image,&pixel,SVGCompliance,tuple,exception);
3418 (void) FormatLocaleString(message,MaxTextExtent,
3419 " <circle cx=\"%.20g\" cy=\"%.20g\" r=\"1\" fill=\"%s\"/>\n",
3420 (double) x,(double) y,tuple);
3421 (void) WriteBlobString(image,message);
3422 p+=GetPixelChannels(image);
3425 (void) WriteBlobString(image,"</svg>\n");
3431 static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
3432 ExceptionInfo *exception)
3434 #define BezierQuantum 200
3440 keyword[MaxTextExtent],
3441 message[MaxTextExtent],
3442 name[MaxTextExtent],
3444 type[MaxTextExtent];
3486 Open output image file.
3488 assert(image_info != (const ImageInfo *) NULL);
3489 assert(image_info->signature == MagickSignature);
3490 assert(image != (Image *) NULL);
3491 assert(image->signature == MagickSignature);
3492 if (image->debug != MagickFalse)
3493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3494 assert(exception != (ExceptionInfo *) NULL);
3495 assert(exception->signature == MagickSignature);
3496 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3497 if (status == MagickFalse)
3499 value=GetImageArtifact(image,"SVG");
3500 if (value != (char *) NULL)
3502 (void) WriteBlobString(image,value);
3503 (void) CloseBlob(image);
3506 value=GetImageArtifact(image,"MVG");
3507 if (value == (char *) NULL)
3508 return(TraceSVGImage(image,exception));
3512 (void) WriteBlobString(image,"<?xml version=\"1.0\" standalone=\"no\"?>\n");
3513 (void) WriteBlobString(image,
3514 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n");
3515 (void) WriteBlobString(image,
3516 " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
3517 (void) FormatLocaleString(message,MaxTextExtent,
3518 "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) image->columns,(double)
3520 (void) WriteBlobString(image,message);
3522 Allocate primitive info memory.
3525 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory(number_points,
3526 sizeof(*primitive_info));
3527 if (primitive_info == (PrimitiveInfo *) NULL)
3528 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3529 GetAffineMatrix(&affine);
3530 token=AcquireString(value);
3534 for (q=(const char *) value; *q != '\0'; )
3537 Interpret graphic primitive.
3539 GetMagickToken(q,&q,keyword);
3540 if (*keyword == '\0')
3542 if (*keyword == '#')
3547 if (active != MagickFalse)
3549 AffineToTransform(image,&affine);
3552 (void) WriteBlobString(image,"<desc>");
3553 (void) WriteBlobString(image,keyword+1);
3554 for ( ; (*q != '\n') && (*q != '\0'); q++)
3557 case '<': (void) WriteBlobString(image,"<"); break;
3558 case '>': (void) WriteBlobString(image,">"); break;
3559 case '&': (void) WriteBlobString(image,"&"); break;
3560 default: (void) WriteBlobByte(image,*q); break;
3562 (void) WriteBlobString(image,"</desc>\n");
3565 primitive_type=UndefinedPrimitive;
3573 if (LocaleCompare("affine",keyword) == 0)
3575 GetMagickToken(q,&q,token);
3576 affine.sx=StringToDouble(token,(char **) NULL);
3577 GetMagickToken(q,&q,token);
3579 GetMagickToken(q,&q,token);
3580 affine.rx=StringToDouble(token,(char **) NULL);
3581 GetMagickToken(q,&q,token);
3583 GetMagickToken(q,&q,token);
3584 affine.ry=StringToDouble(token,(char **) NULL);
3585 GetMagickToken(q,&q,token);
3587 GetMagickToken(q,&q,token);
3588 affine.sy=StringToDouble(token,(char **) NULL);
3589 GetMagickToken(q,&q,token);
3591 GetMagickToken(q,&q,token);
3592 affine.tx=StringToDouble(token,(char **) NULL);
3593 GetMagickToken(q,&q,token);
3595 GetMagickToken(q,&q,token);
3596 affine.ty=StringToDouble(token,(char **) NULL);
3599 if (LocaleCompare("angle",keyword) == 0)
3601 GetMagickToken(q,&q,token);
3602 affine.rx=StringToDouble(token,(char **) NULL);
3603 affine.ry=StringToDouble(token,(char **) NULL);
3606 if (LocaleCompare("arc",keyword) == 0)
3608 primitive_type=ArcPrimitive;
3617 if (LocaleCompare("bezier",keyword) == 0)
3619 primitive_type=BezierPrimitive;
3628 if (LocaleCompare("clip-path",keyword) == 0)
3630 GetMagickToken(q,&q,token);
3631 (void) FormatLocaleString(message,MaxTextExtent,
3632 "clip-path:url(#%s);",token);
3633 (void) WriteBlobString(image,message);
3636 if (LocaleCompare("clip-rule",keyword) == 0)
3638 GetMagickToken(q,&q,token);
3639 (void) FormatLocaleString(message,MaxTextExtent,
3640 "clip-rule:%s;",token);
3641 (void) WriteBlobString(image,message);
3644 if (LocaleCompare("clip-units",keyword) == 0)
3646 GetMagickToken(q,&q,token);
3647 (void) FormatLocaleString(message,MaxTextExtent,
3648 "clipPathUnits=%s;",token);
3649 (void) WriteBlobString(image,message);
3652 if (LocaleCompare("circle",keyword) == 0)
3654 primitive_type=CirclePrimitive;
3657 if (LocaleCompare("color",keyword) == 0)
3659 primitive_type=ColorPrimitive;
3668 if (LocaleCompare("decorate",keyword) == 0)
3670 GetMagickToken(q,&q,token);
3671 (void) FormatLocaleString(message,MaxTextExtent,
3672 "text-decoration:%s;",token);
3673 (void) WriteBlobString(image,message);
3682 if (LocaleCompare("ellipse",keyword) == 0)
3684 primitive_type=EllipsePrimitive;
3693 if (LocaleCompare("fill",keyword) == 0)
3695 GetMagickToken(q,&q,token);
3696 (void) FormatLocaleString(message,MaxTextExtent,"fill:%s;",
3698 (void) WriteBlobString(image,message);
3701 if (LocaleCompare("fill-rule",keyword) == 0)
3703 GetMagickToken(q,&q,token);
3704 (void) FormatLocaleString(message,MaxTextExtent,
3705 "fill-rule:%s;",token);
3706 (void) WriteBlobString(image,message);
3709 if (LocaleCompare("fill-opacity",keyword) == 0)
3711 GetMagickToken(q,&q,token);
3712 (void) FormatLocaleString(message,MaxTextExtent,
3713 "fill-opacity:%s;",token);
3714 (void) WriteBlobString(image,message);
3717 if (LocaleCompare("font-family",keyword) == 0)
3719 GetMagickToken(q,&q,token);
3720 (void) FormatLocaleString(message,MaxTextExtent,
3721 "font-family:%s;",token);
3722 (void) WriteBlobString(image,message);
3725 if (LocaleCompare("font-stretch",keyword) == 0)
3727 GetMagickToken(q,&q,token);
3728 (void) FormatLocaleString(message,MaxTextExtent,
3729 "font-stretch:%s;",token);
3730 (void) WriteBlobString(image,message);
3733 if (LocaleCompare("font-style",keyword) == 0)
3735 GetMagickToken(q,&q,token);
3736 (void) FormatLocaleString(message,MaxTextExtent,
3737 "font-style:%s;",token);
3738 (void) WriteBlobString(image,message);
3741 if (LocaleCompare("font-size",keyword) == 0)
3743 GetMagickToken(q,&q,token);
3744 (void) FormatLocaleString(message,MaxTextExtent,
3745 "font-size:%s;",token);
3746 (void) WriteBlobString(image,message);
3749 if (LocaleCompare("font-weight",keyword) == 0)
3751 GetMagickToken(q,&q,token);
3752 (void) FormatLocaleString(message,MaxTextExtent,
3753 "font-weight:%s;",token);
3754 (void) WriteBlobString(image,message);
3763 if (LocaleCompare("gradient-units",keyword) == 0)
3765 GetMagickToken(q,&q,token);
3768 if (LocaleCompare("text-align",keyword) == 0)
3770 GetMagickToken(q,&q,token);
3771 (void) FormatLocaleString(message,MaxTextExtent,
3772 "text-align %s ",token);
3773 (void) WriteBlobString(image,message);
3776 if (LocaleCompare("text-anchor",keyword) == 0)
3778 GetMagickToken(q,&q,token);
3779 (void) FormatLocaleString(message,MaxTextExtent,
3780 "text-anchor %s ",token);
3781 (void) WriteBlobString(image,message);
3790 if (LocaleCompare("image",keyword) == 0)
3792 GetMagickToken(q,&q,token);
3793 primitive_type=ImagePrimitive;
3802 if (LocaleCompare("line",keyword) == 0)
3804 primitive_type=LinePrimitive;
3813 if (LocaleCompare("matte",keyword) == 0)
3815 primitive_type=MattePrimitive;
3824 if (LocaleCompare("opacity",keyword) == 0)
3826 GetMagickToken(q,&q,token);
3827 (void) FormatLocaleString(message,MaxTextExtent,"opacity %s ",
3829 (void) WriteBlobString(image,message);
3838 if (LocaleCompare("path",keyword) == 0)
3840 primitive_type=PathPrimitive;
3843 if (LocaleCompare("point",keyword) == 0)
3845 primitive_type=PointPrimitive;
3848 if (LocaleCompare("polyline",keyword) == 0)
3850 primitive_type=PolylinePrimitive;
3853 if (LocaleCompare("polygon",keyword) == 0)
3855 primitive_type=PolygonPrimitive;
3858 if (LocaleCompare("pop",keyword) == 0)
3860 GetMagickToken(q,&q,token);
3861 if (LocaleCompare("clip-path",token) == 0)
3863 (void) WriteBlobString(image,"</clipPath>\n");
3866 if (LocaleCompare("defs",token) == 0)
3868 (void) WriteBlobString(image,"</defs>\n");
3871 if (LocaleCompare("gradient",token) == 0)
3873 (void) FormatLocaleString(message,MaxTextExtent,
3874 "</%sGradient>\n",type);
3875 (void) WriteBlobString(image,message);
3878 if (LocaleCompare("graphic-context",token) == 0)
3882 ThrowWriterException(DrawError,
3883 "UnbalancedGraphicContextPushPop");
3884 (void) WriteBlobString(image,"</g>\n");
3886 if (LocaleCompare("pattern",token) == 0)
3888 (void) WriteBlobString(image,"</pattern>\n");
3891 if (LocaleCompare("defs",token) == 0)
3892 (void) WriteBlobString(image,"</g>\n");
3895 if (LocaleCompare("push",keyword) == 0)
3897 GetMagickToken(q,&q,token);
3898 if (LocaleCompare("clip-path",token) == 0)
3900 GetMagickToken(q,&q,token);
3901 (void) FormatLocaleString(message,MaxTextExtent,
3902 "<clipPath id=\"%s\">\n",token);
3903 (void) WriteBlobString(image,message);
3906 if (LocaleCompare("defs",token) == 0)
3908 (void) WriteBlobString(image,"<defs>\n");
3911 if (LocaleCompare("gradient",token) == 0)
3913 GetMagickToken(q,&q,token);
3914 (void) CopyMagickString(name,token,MaxTextExtent);
3915 GetMagickToken(q,&q,token);
3916 (void) CopyMagickString(type,token,MaxTextExtent);
3917 GetMagickToken(q,&q,token);
3918 svg_info.segment.x1=StringToDouble(token,(char **) NULL);
3919 svg_info.element.cx=StringToDouble(token,(char **) NULL);
3920 GetMagickToken(q,&q,token);
3922 GetMagickToken(q,&q,token);
3923 svg_info.segment.y1=StringToDouble(token,(char **) NULL);
3924 svg_info.element.cy=StringToDouble(token,(char **) NULL);
3925 GetMagickToken(q,&q,token);
3927 GetMagickToken(q,&q,token);
3928 svg_info.segment.x2=StringToDouble(token,(char **) NULL);
3929 svg_info.element.major=StringToDouble(token,
3931 GetMagickToken(q,&q,token);
3933 GetMagickToken(q,&q,token);
3934 svg_info.segment.y2=StringToDouble(token,(char **) NULL);
3935 svg_info.element.minor=StringToDouble(token,
3937 (void) FormatLocaleString(message,MaxTextExtent,
3938 "<%sGradient id=\"%s\" x1=\"%g\" y1=\"%g\" x2=\"%g\" "
3939 "y2=\"%g\">\n",type,name,svg_info.segment.x1,
3940 svg_info.segment.y1,svg_info.segment.x2,svg_info.segment.y2);
3941 if (LocaleCompare(type,"radial") == 0)
3943 GetMagickToken(q,&q,token);
3945 GetMagickToken(q,&q,token);
3946 svg_info.element.angle=StringToDouble(token,
3948 (void) FormatLocaleString(message,MaxTextExtent,
3949 "<%sGradient id=\"%s\" cx=\"%g\" cy=\"%g\" r=\"%g\" "
3950 "fx=\"%g\" fy=\"%g\">\n",type,name,
3951 svg_info.element.cx,svg_info.element.cy,
3952 svg_info.element.angle,svg_info.element.major,
3953 svg_info.element.minor);
3955 (void) WriteBlobString(image,message);
3958 if (LocaleCompare("graphic-context",token) == 0)
3963 AffineToTransform(image,&affine);
3966 (void) WriteBlobString(image,"<g style=\"");
3969 if (LocaleCompare("pattern",token) == 0)
3971 GetMagickToken(q,&q,token);
3972 (void) CopyMagickString(name,token,MaxTextExtent);
3973 GetMagickToken(q,&q,token);
3974 svg_info.bounds.x=StringToDouble(token,(char **) NULL);
3975 GetMagickToken(q,&q,token);
3977 GetMagickToken(q,&q,token);
3978 svg_info.bounds.y=StringToDouble(token,(char **) NULL);
3979 GetMagickToken(q,&q,token);
3981 GetMagickToken(q,&q,token);
3982 svg_info.bounds.width=StringToDouble(token,
3984 GetMagickToken(q,&q,token);
3986 GetMagickToken(q,&q,token);
3987 svg_info.bounds.height=StringToDouble(token,
3989 (void) FormatLocaleString(message,MaxTextExtent,
3990 "<pattern id=\"%s\" x=\"%g\" y=\"%g\" width=\"%g\" "
3991 "height=\"%g\">\n",name,svg_info.bounds.x,
3992 svg_info.bounds.y,svg_info.bounds.width,
3993 svg_info.bounds.height);
3994 (void) WriteBlobString(image,message);
4005 if (LocaleCompare("rectangle",keyword) == 0)
4007 primitive_type=RectanglePrimitive;
4010 if (LocaleCompare("roundRectangle",keyword) == 0)
4012 primitive_type=RoundRectanglePrimitive;
4015 if (LocaleCompare("rotate",keyword) == 0)
4017 GetMagickToken(q,&q,token);
4018 (void) FormatLocaleString(message,MaxTextExtent,"rotate(%s) ",
4020 (void) WriteBlobString(image,message);
4029 if (LocaleCompare("scale",keyword) == 0)
4031 GetMagickToken(q,&q,token);
4032 affine.sx=StringToDouble(token,(char **) NULL);
4033 GetMagickToken(q,&q,token);
4035 GetMagickToken(q,&q,token);
4036 affine.sy=StringToDouble(token,(char **) NULL);
4039 if (LocaleCompare("skewX",keyword) == 0)
4041 GetMagickToken(q,&q,token);
4042 (void) FormatLocaleString(message,MaxTextExtent,"skewX(%s) ",
4044 (void) WriteBlobString(image,message);
4047 if (LocaleCompare("skewY",keyword) == 0)
4049 GetMagickToken(q,&q,token);
4050 (void) FormatLocaleString(message,MaxTextExtent,"skewY(%s) ",
4052 (void) WriteBlobString(image,message);
4055 if (LocaleCompare("stop-color",keyword) == 0)
4058 color[MaxTextExtent];
4060 GetMagickToken(q,&q,token);
4061 (void) CopyMagickString(color,token,MaxTextExtent);
4062 GetMagickToken(q,&q,token);
4063 (void) FormatLocaleString(message,MaxTextExtent,
4064 " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
4065 (void) WriteBlobString(image,message);
4068 if (LocaleCompare("stroke",keyword) == 0)
4070 GetMagickToken(q,&q,token);
4071 (void) FormatLocaleString(message,MaxTextExtent,"stroke:%s;",
4073 (void) WriteBlobString(image,message);
4076 if (LocaleCompare("stroke-antialias",keyword) == 0)
4078 GetMagickToken(q,&q,token);
4079 (void) FormatLocaleString(message,MaxTextExtent,
4080 "stroke-antialias:%s;",token);
4081 (void) WriteBlobString(image,message);
4084 if (LocaleCompare("stroke-dasharray",keyword) == 0)
4092 GetMagickToken(p,&p,token);
4093 for (k=0; IsPoint(token); k++)
4094 GetMagickToken(p,&p,token);
4095 (void) WriteBlobString(image,"stroke-dasharray:");
4096 for (j=0; j < k; j++)
4098 GetMagickToken(q,&q,token);
4099 (void) FormatLocaleString(message,MaxTextExtent,"%s ",
4101 (void) WriteBlobString(image,message);
4103 (void) WriteBlobString(image,";");
4106 GetMagickToken(q,&q,token);
4107 (void) FormatLocaleString(message,MaxTextExtent,
4108 "stroke-dasharray:%s;",token);
4109 (void) WriteBlobString(image,message);
4112 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
4114 GetMagickToken(q,&q,token);
4115 (void) FormatLocaleString(message,MaxTextExtent,
4116 "stroke-dashoffset:%s;",token);
4117 (void) WriteBlobString(image,message);
4120 if (LocaleCompare("stroke-linecap",keyword) == 0)
4122 GetMagickToken(q,&q,token);
4123 (void) FormatLocaleString(message,MaxTextExtent,
4124 "stroke-linecap:%s;",token);
4125 (void) WriteBlobString(image,message);
4128 if (LocaleCompare("stroke-linejoin",keyword) == 0)
4130 GetMagickToken(q,&q,token);
4131 (void) FormatLocaleString(message,MaxTextExtent,
4132 "stroke-linejoin:%s;",token);
4133 (void) WriteBlobString(image,message);
4136 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
4138 GetMagickToken(q,&q,token);
4139 (void) FormatLocaleString(message,MaxTextExtent,
4140 "stroke-miterlimit:%s;",token);
4141 (void) WriteBlobString(image,message);
4144 if (LocaleCompare("stroke-opacity",keyword) == 0)
4146 GetMagickToken(q,&q,token);
4147 (void) FormatLocaleString(message,MaxTextExtent,
4148 "stroke-opacity:%s;",token);
4149 (void) WriteBlobString(image,message);
4152 if (LocaleCompare("stroke-width",keyword) == 0)
4154 GetMagickToken(q,&q,token);
4155 (void) FormatLocaleString(message,MaxTextExtent,
4156 "stroke-width:%s;",token);
4157 (void) WriteBlobString(image,message);
4166 if (LocaleCompare("text",keyword) == 0)
4168 primitive_type=TextPrimitive;
4171 if (LocaleCompare("text-antialias",keyword) == 0)
4173 GetMagickToken(q,&q,token);
4174 (void) FormatLocaleString(message,MaxTextExtent,
4175 "text-antialias:%s;",token);
4176 (void) WriteBlobString(image,message);
4179 if (LocaleCompare("tspan",keyword) == 0)
4181 primitive_type=TextPrimitive;
4184 if (LocaleCompare("translate",keyword) == 0)
4186 GetMagickToken(q,&q,token);
4187 affine.tx=StringToDouble(token,(char **) NULL);
4188 GetMagickToken(q,&q,token);
4190 GetMagickToken(q,&q,token);
4191 affine.ty=StringToDouble(token,(char **) NULL);
4200 if (LocaleCompare("viewbox",keyword) == 0)
4202 GetMagickToken(q,&q,token);
4204 GetMagickToken(q,&q,token);
4205 GetMagickToken(q,&q,token);
4207 GetMagickToken(q,&q,token);
4208 GetMagickToken(q,&q,token);
4210 GetMagickToken(q,&q,token);
4211 GetMagickToken(q,&q,token);
4223 if (status == MagickFalse)
4225 if (primitive_type == UndefinedPrimitive)
4228 Parse the primitive attributes.
4232 for (x=0; *q != '\0'; x++)
4237 if (IsPoint(q) == MagickFalse)
4239 GetMagickToken(q,&q,token);
4240 point.x=StringToDouble(token,(char **) NULL);
4241 GetMagickToken(q,&q,token);
4243 GetMagickToken(q,&q,token);
4244 point.y=StringToDouble(token,(char **) NULL);
4245 GetMagickToken(q,(const char **) NULL,token);
4247 GetMagickToken(q,&q,token);
4248 primitive_info[i].primitive=primitive_type;
4249 primitive_info[i].point=point;
4250 primitive_info[i].coordinates=0;
4251 primitive_info[i].method=FloodfillMethod;
4253 if (i < (ssize_t) (number_points-6*BezierQuantum-360))
4255 number_points+=6*BezierQuantum+360;
4256 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4257 number_points,sizeof(*primitive_info));
4258 if (primitive_info == (PrimitiveInfo *) NULL)
4260 (void) ThrowMagickException(exception,GetMagickModule(),
4261 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
4265 primitive_info[j].primitive=primitive_type;
4266 primitive_info[j].coordinates=x;
4267 primitive_info[j].method=FloodfillMethod;
4268 primitive_info[j].text=(char *) NULL;
4271 AffineToTransform(image,&affine);
4275 switch (primitive_type)
4277 case PointPrimitive:
4280 if (primitive_info[j].coordinates != 1)
4289 if (primitive_info[j].coordinates != 2)
4294 (void) FormatLocaleString(message,MaxTextExtent,
4295 " <line x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\"/>\n",
4296 primitive_info[j].point.x,primitive_info[j].point.y,
4297 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4298 (void) WriteBlobString(image,message);
4301 case RectanglePrimitive:
4303 if (primitive_info[j].coordinates != 2)
4308 (void) FormatLocaleString(message,MaxTextExtent,
4309 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\"/>\n",
4310 primitive_info[j].point.x,primitive_info[j].point.y,
4311 primitive_info[j+1].point.x-primitive_info[j].point.x,
4312 primitive_info[j+1].point.y-primitive_info[j].point.y);
4313 (void) WriteBlobString(image,message);
4316 case RoundRectanglePrimitive:
4318 if (primitive_info[j].coordinates != 3)
4323 (void) FormatLocaleString(message,MaxTextExtent,
4324 " <rect x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" rx=\"%g\" "
4325 "ry=\"%g\"/>\n",primitive_info[j].point.x,
4326 primitive_info[j].point.y,primitive_info[j+1].point.x-
4327 primitive_info[j].point.x,primitive_info[j+1].point.y-
4328 primitive_info[j].point.y,primitive_info[j+2].point.x,
4329 primitive_info[j+2].point.y);
4330 (void) WriteBlobString(image,message);
4335 if (primitive_info[j].coordinates != 3)
4342 case EllipsePrimitive:
4344 if (primitive_info[j].coordinates != 3)
4349 (void) FormatLocaleString(message,MaxTextExtent,
4350 " <ellipse cx=\"%g\" cy=\"%g\" rx=\"%g\" ry=\"%g\"/>\n",
4351 primitive_info[j].point.x,primitive_info[j].point.y,
4352 primitive_info[j+1].point.x,primitive_info[j+1].point.y);
4353 (void) WriteBlobString(image,message);
4356 case CirclePrimitive:
4362 if (primitive_info[j].coordinates != 2)
4367 alpha=primitive_info[j+1].point.x-primitive_info[j].point.x;
4368 beta=primitive_info[j+1].point.y-primitive_info[j].point.y;
4369 (void) FormatLocaleString(message,MaxTextExtent,
4370 " <circle cx=\"%g\" cy=\"%g\" r=\"%g\"/>\n",
4371 primitive_info[j].point.x,primitive_info[j].point.y,
4373 (void) WriteBlobString(image,message);
4376 case PolylinePrimitive:
4378 if (primitive_info[j].coordinates < 2)
4383 (void) CopyMagickString(message," <polyline points=\"",MaxTextExtent);
4384 (void) WriteBlobString(image,message);
4385 length=strlen(message);
4388 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4389 primitive_info[j].point.x,primitive_info[j].point.y);
4390 length+=strlen(message);
4393 (void) WriteBlobString(image,"\n ");
4394 length=strlen(message)+5;
4396 (void) WriteBlobString(image,message);
4398 (void) WriteBlobString(image,"\"/>\n");
4401 case PolygonPrimitive:
4403 if (primitive_info[j].coordinates < 3)
4408 primitive_info[i]=primitive_info[j];
4409 primitive_info[i].coordinates=0;
4410 primitive_info[j].coordinates++;
4412 (void) CopyMagickString(message," <polygon points=\"",MaxTextExtent);
4413 (void) WriteBlobString(image,message);
4414 length=strlen(message);
4417 (void) FormatLocaleString(message,MaxTextExtent,"%g,%g ",
4418 primitive_info[j].point.x,primitive_info[j].point.y);
4419 length+=strlen(message);
4422 (void) WriteBlobString(image,"\n ");
4423 length=strlen(message)+5;
4425 (void) WriteBlobString(image,message);
4427 (void) WriteBlobString(image,"\"/>\n");
4430 case BezierPrimitive:
4432 if (primitive_info[j].coordinates < 3)
4444 GetMagickToken(q,&q,token);
4445 number_attributes=1;
4446 for (p=token; *p != '\0'; p++)
4447 if (isalpha((int) *p))
4448 number_attributes++;
4449 if (i > (ssize_t) (number_points-6*BezierQuantum*number_attributes-1))
4451 number_points+=6*BezierQuantum*number_attributes;
4452 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
4453 number_points,sizeof(*primitive_info));
4454 if (primitive_info == (PrimitiveInfo *) NULL)
4456 (void) ThrowMagickException(exception,GetMagickModule(),
4457 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4462 (void) WriteBlobString(image," <path d=\"");
4463 (void) WriteBlobString(image,token);
4464 (void) WriteBlobString(image,"\"/>\n");
4467 case ColorPrimitive:
4468 case MattePrimitive:
4470 if (primitive_info[j].coordinates != 1)
4475 GetMagickToken(q,&q,token);
4476 if (LocaleCompare("point",token) == 0)
4477 primitive_info[j].method=PointMethod;
4478 if (LocaleCompare("replace",token) == 0)
4479 primitive_info[j].method=ReplaceMethod;
4480 if (LocaleCompare("floodfill",token) == 0)
4481 primitive_info[j].method=FloodfillMethod;
4482 if (LocaleCompare("filltoborder",token) == 0)
4483 primitive_info[j].method=FillToBorderMethod;
4484 if (LocaleCompare("reset",token) == 0)
4485 primitive_info[j].method=ResetMethod;
4493 if (primitive_info[j].coordinates != 1)
4498 GetMagickToken(q,&q,token);
4499 (void) FormatLocaleString(message,MaxTextExtent,
4500 " <text x=\"%g\" y=\"%g\">",primitive_info[j].point.x,
4501 primitive_info[j].point.y);
4502 (void) WriteBlobString(image,message);
4503 for (p=token; *p != '\0'; p++)
4506 case '<': (void) WriteBlobString(image,"<"); break;
4507 case '>': (void) WriteBlobString(image,">"); break;
4508 case '&': (void) WriteBlobString(image,"&"); break;
4509 default: (void) WriteBlobByte(image,*p); break;
4511 (void) WriteBlobString(image,"</text>\n");
4514 case ImagePrimitive:
4516 if (primitive_info[j].coordinates != 2)
4521 GetMagickToken(q,&q,token);
4522 (void) FormatLocaleString(message,MaxTextExtent,
4523 " <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
4524 "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
4525 primitive_info[j].point.y,primitive_info[j+1].point.x,
4526 primitive_info[j+1].point.y,token);
4527 (void) WriteBlobString(image,message);
4531 if (primitive_info == (PrimitiveInfo *) NULL)
4533 primitive_info[i].primitive=UndefinedPrimitive;
4534 if (status == MagickFalse)
4537 (void) WriteBlobString(image,"</svg>\n");
4539 Relinquish resources.
4541 token=DestroyString(token);
4542 if (primitive_info != (PrimitiveInfo *) NULL)
4543 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
4544 (void) CloseBlob(image);