PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/coders/svg.c

https://gitlab.com/ImageMagick/ImageMagick
C | 5200 lines | 4638 code | 232 blank | 330 comment | 1185 complexity | da0aa52f29a1ea23277eaf81b8e011e3 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % %
  5. % %
  6. % SSSSS V V GGGG %
  7. % SS V V G %
  8. % SSS V V G GG %
  9. % SS V V G G %
  10. % SSSSS V GGG %
  11. % %
  12. % %
  13. % Read/Write Scalable Vector Graphics Format %
  14. % %
  15. % Software Design %
  16. % Cristy %
  17. % William Radcliffe %
  18. % March 2000 %
  19. % %
  20. % %
  21. % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
  22. % dedicated to making software imaging solutions freely available. %
  23. % %
  24. % You may not use this file except in compliance with the License. You may %
  25. % obtain a copy of the License at %
  26. % %
  27. % https://imagemagick.org/script/license.php %
  28. % %
  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. %
  34. % %
  35. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  36. %
  37. %
  38. */
  39. /*
  40. Include declarations.
  41. */
  42. #include "MagickCore/studio.h"
  43. #include "MagickCore/annotate.h"
  44. #include "MagickCore/artifact.h"
  45. #include "MagickCore/attribute.h"
  46. #include "MagickCore/blob.h"
  47. #include "MagickCore/blob-private.h"
  48. #include "MagickCore/cache.h"
  49. #include "MagickCore/constitute.h"
  50. #include "MagickCore/composite-private.h"
  51. #include "MagickCore/delegate.h"
  52. #include "MagickCore/delegate-private.h"
  53. #include "MagickCore/draw.h"
  54. #include "MagickCore/exception.h"
  55. #include "MagickCore/exception-private.h"
  56. #include "MagickCore/gem.h"
  57. #include "MagickCore/image.h"
  58. #include "MagickCore/image-private.h"
  59. #include "MagickCore/list.h"
  60. #include "MagickCore/log.h"
  61. #include "MagickCore/magick.h"
  62. #include "MagickCore/memory_.h"
  63. #include "MagickCore/memory-private.h"
  64. #include "MagickCore/module.h"
  65. #include "MagickCore/monitor.h"
  66. #include "MagickCore/monitor-private.h"
  67. #include "MagickCore/quantum-private.h"
  68. #include "MagickCore/pixel-accessor.h"
  69. #include "MagickCore/property.h"
  70. #include "MagickCore/resource_.h"
  71. #include "MagickCore/static.h"
  72. #include "MagickCore/string_.h"
  73. #include "MagickCore/string-private.h"
  74. #include "MagickCore/token.h"
  75. #include "MagickCore/utility.h"
  76. #if defined(MAGICKCORE_XML_DELEGATE)
  77. # if defined(MAGICKCORE_WINDOWS_SUPPORT)
  78. # if !defined(__MINGW32__)
  79. # include <win32config.h>
  80. # endif
  81. # endif
  82. # include <libxml/xmlmemory.h>
  83. # include <libxml/parserInternals.h>
  84. # include <libxml/xmlerror.h>
  85. #endif
  86. #if defined(MAGICKCORE_AUTOTRACE_DELEGATE)
  87. #include "autotrace/autotrace.h"
  88. #endif
  89. #if defined(MAGICKCORE_RSVG_DELEGATE)
  90. #include "librsvg/rsvg.h"
  91. #if !defined(LIBRSVG_CHECK_VERSION)
  92. #include "librsvg/rsvg-cairo.h"
  93. #include "librsvg/librsvg-features.h"
  94. #elif !LIBRSVG_CHECK_VERSION(2,36,2)
  95. #include "librsvg/rsvg-cairo.h"
  96. #include "librsvg/librsvg-features.h"
  97. #endif
  98. #endif
  99. /*
  100. Define declarations.
  101. */
  102. #define DefaultSVGDensity 96.0
  103. /*
  104. Typedef declarations.
  105. */
  106. typedef struct _BoundingBox
  107. {
  108. double
  109. x,
  110. y,
  111. width,
  112. height;
  113. } BoundingBox;
  114. typedef struct _ElementInfo
  115. {
  116. double
  117. cx,
  118. cy,
  119. major,
  120. minor,
  121. angle;
  122. } ElementInfo;
  123. typedef struct _SVGInfo
  124. {
  125. FILE
  126. *file;
  127. ExceptionInfo
  128. *exception;
  129. Image
  130. *image;
  131. const ImageInfo
  132. *image_info;
  133. AffineMatrix
  134. affine;
  135. size_t
  136. width,
  137. height;
  138. char
  139. *size,
  140. *title,
  141. *comment;
  142. int
  143. n;
  144. double
  145. *scale,
  146. pointsize;
  147. ElementInfo
  148. element;
  149. SegmentInfo
  150. segment;
  151. BoundingBox
  152. bounds,
  153. text_offset,
  154. view_box;
  155. PointInfo
  156. radius;
  157. char
  158. *stop_color,
  159. *offset,
  160. *text,
  161. *vertices,
  162. *url;
  163. #if defined(MAGICKCORE_XML_DELEGATE)
  164. xmlParserCtxtPtr
  165. parser;
  166. xmlDocPtr
  167. document;
  168. #endif
  169. ssize_t
  170. svgDepth;
  171. } SVGInfo;
  172. /*
  173. Static declarations.
  174. */
  175. static char
  176. SVGDensityGeometry[] = "96.0x96.0";
  177. /*
  178. Forward declarations.
  179. */
  180. static MagickBooleanType
  181. WriteSVGImage(const ImageInfo *,Image *,ExceptionInfo *);
  182. /*
  183. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  184. % %
  185. % %
  186. % %
  187. % I s S V G %
  188. % %
  189. % %
  190. % %
  191. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  192. %
  193. % IsSVG()() returns MagickTrue if the image format type, identified by the
  194. % magick string, is SVG.
  195. %
  196. % The format of the IsSVG method is:
  197. %
  198. % MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
  199. %
  200. % A description of each parameter follows:
  201. %
  202. % o magick: compare image format pattern against these bytes.
  203. %
  204. % o length: Specifies the length of the magick string.
  205. %
  206. */
  207. static MagickBooleanType IsSVG(const unsigned char *magick,const size_t length)
  208. {
  209. if (length < 4)
  210. return(MagickFalse);
  211. if (LocaleNCompare((const char *) magick+1,"svg",3) == 0)
  212. return(MagickTrue);
  213. if (length < 5)
  214. return(MagickFalse);
  215. if (LocaleNCompare((const char *) magick+1,"?xml",4) == 0)
  216. return(MagickTrue);
  217. return(MagickFalse);
  218. }
  219. /*
  220. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  221. % %
  222. % %
  223. % %
  224. % R e a d S V G I m a g e %
  225. % %
  226. % %
  227. % %
  228. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  229. %
  230. % ReadSVGImage() reads a Scalable Vector Gaphics file and returns it. It
  231. % allocates the memory necessary for the new Image structure and returns a
  232. % pointer to the new image.
  233. %
  234. % The format of the ReadSVGImage method is:
  235. %
  236. % Image *ReadSVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
  237. %
  238. % A description of each parameter follows:
  239. %
  240. % o image_info: the image info.
  241. %
  242. % o exception: return any errors or warnings in this structure.
  243. %
  244. */
  245. static Image *RenderSVGImage(const ImageInfo *image_info,Image *image,
  246. ExceptionInfo *exception)
  247. {
  248. char
  249. background[MagickPathExtent],
  250. command[MagickPathExtent],
  251. *density,
  252. input_filename[MagickPathExtent],
  253. opacity[MagickPathExtent],
  254. output_filename[MagickPathExtent],
  255. unique[MagickPathExtent];
  256. const DelegateInfo
  257. *delegate_info;
  258. Image
  259. *next;
  260. int
  261. status;
  262. struct stat
  263. attributes;
  264. /*
  265. Our best hope for compliance with the SVG standard.
  266. */
  267. delegate_info=GetDelegateInfo("svg:decode",(char *) NULL,exception);
  268. if (delegate_info == (const DelegateInfo *) NULL)
  269. return((Image *) NULL);
  270. status=AcquireUniqueSymbolicLink(image->filename,input_filename);
  271. (void) AcquireUniqueFilename(output_filename);
  272. (void) AcquireUniqueFilename(unique);
  273. density=AcquireString("");
  274. (void) FormatLocaleString(density,MagickPathExtent,"%.20g,%.20g",
  275. image->resolution.x,image->resolution.y);
  276. (void) FormatLocaleString(background,MagickPathExtent,
  277. "rgb(%.20g%%,%.20g%%,%.20g%%)",
  278. 100.0*QuantumScale*image->background_color.red,
  279. 100.0*QuantumScale*image->background_color.green,
  280. 100.0*QuantumScale*image->background_color.blue);
  281. (void) FormatLocaleString(opacity,MagickPathExtent,"%.20g",QuantumScale*
  282. image->background_color.alpha);
  283. (void) FormatLocaleString(command,MagickPathExtent,
  284. GetDelegateCommands(delegate_info),input_filename,output_filename,density,
  285. background,opacity,unique);
  286. density=DestroyString(density);
  287. status=ExternalDelegateCommand(MagickFalse,image_info->verbose,command,
  288. (char *) NULL,exception);
  289. (void) RelinquishUniqueFileResource(unique);
  290. (void) RelinquishUniqueFileResource(input_filename);
  291. if ((status == 0) && (stat(output_filename,&attributes) == 0) &&
  292. (attributes.st_size > 0))
  293. {
  294. Image
  295. *svg_image;
  296. ImageInfo
  297. *read_info;
  298. read_info=CloneImageInfo(image_info);
  299. (void) CopyMagickString(read_info->filename,output_filename,
  300. MagickPathExtent);
  301. svg_image=ReadImage(read_info,exception);
  302. read_info=DestroyImageInfo(read_info);
  303. if (svg_image != (Image *) NULL)
  304. {
  305. (void) RelinquishUniqueFileResource(output_filename);
  306. for (next=GetFirstImageInList(svg_image); next != (Image *) NULL; )
  307. {
  308. (void) CopyMagickString(next->filename,image->filename,
  309. MaxTextExtent);
  310. (void) CopyMagickString(next->magick,image->magick,MaxTextExtent);
  311. next=GetNextImageInList(next);
  312. }
  313. return(svg_image);
  314. }
  315. }
  316. (void) RelinquishUniqueFileResource(output_filename);
  317. return((Image *) NULL);
  318. }
  319. #if defined(MAGICKCORE_XML_DELEGATE)
  320. static SVGInfo *AcquireSVGInfo(void)
  321. {
  322. SVGInfo
  323. *svg_info;
  324. svg_info=(SVGInfo *) AcquireMagickMemory(sizeof(*svg_info));
  325. if (svg_info == (SVGInfo *) NULL)
  326. return((SVGInfo *) NULL);
  327. (void) memset(svg_info,0,sizeof(*svg_info));
  328. svg_info->text=AcquireString("");
  329. svg_info->scale=(double *) AcquireCriticalMemory(sizeof(*svg_info->scale));
  330. GetAffineMatrix(&svg_info->affine);
  331. svg_info->scale[0]=ExpandAffine(&svg_info->affine);
  332. return(svg_info);
  333. }
  334. static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
  335. {
  336. if (svg_info->text != (char *) NULL)
  337. svg_info->text=DestroyString(svg_info->text);
  338. if (svg_info->scale != (double *) NULL)
  339. svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
  340. if (svg_info->title != (char *) NULL)
  341. svg_info->title=DestroyString(svg_info->title);
  342. if (svg_info->comment != (char *) NULL)
  343. svg_info->comment=DestroyString(svg_info->comment);
  344. return((SVGInfo *) RelinquishMagickMemory(svg_info));
  345. }
  346. static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
  347. const char *string)
  348. {
  349. char
  350. *next_token,
  351. token[MagickPathExtent];
  352. const char
  353. *p;
  354. double
  355. value;
  356. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",string);
  357. assert(string != (const char *) NULL);
  358. p=(const char *) string;
  359. GetNextToken(p,&p,MagickPathExtent,token);
  360. value=StringToDouble(token,&next_token);
  361. if (strchr(token,'%') != (char *) NULL)
  362. {
  363. double
  364. alpha,
  365. beta;
  366. if (type > 0)
  367. {
  368. if (svg_info->view_box.width == 0.0)
  369. return(0.0);
  370. return(svg_info->view_box.width*value/100.0);
  371. }
  372. if (type < 0)
  373. {
  374. if (svg_info->view_box.height == 0.0)
  375. return(0.0);
  376. return(svg_info->view_box.height*value/100.0);
  377. }
  378. alpha=value-svg_info->view_box.width;
  379. beta=value-svg_info->view_box.height;
  380. return(hypot(alpha,beta)/sqrt(2.0)/100.0);
  381. }
  382. GetNextToken(p,&p,MagickPathExtent,token);
  383. if (LocaleNCompare(token,"cm",2) == 0)
  384. return(DefaultSVGDensity*svg_info->scale[0]/2.54*value);
  385. if (LocaleNCompare(token,"em",2) == 0)
  386. return(svg_info->pointsize*value);
  387. if (LocaleNCompare(token,"ex",2) == 0)
  388. return(svg_info->pointsize*value/2.0);
  389. if (LocaleNCompare(token,"in",2) == 0)
  390. return(DefaultSVGDensity*svg_info->scale[0]*value);
  391. if (LocaleNCompare(token,"mm",2) == 0)
  392. return(DefaultSVGDensity*svg_info->scale[0]/25.4*value);
  393. if (LocaleNCompare(token,"pc",2) == 0)
  394. return(DefaultSVGDensity*svg_info->scale[0]/6.0*value);
  395. if (LocaleNCompare(token,"pt",2) == 0)
  396. return(svg_info->scale[0]*value);
  397. if (LocaleNCompare(token,"px",2) == 0)
  398. return(value);
  399. return(value);
  400. }
  401. #if defined(__cplusplus) || defined(c_plusplus)
  402. extern "C" {
  403. #endif
  404. static int SVGIsStandalone(void *context)
  405. {
  406. SVGInfo
  407. *svg_info;
  408. /*
  409. Is this document tagged standalone?
  410. */
  411. (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGIsStandalone()");
  412. svg_info=(SVGInfo *) context;
  413. return(svg_info->document->standalone == 1);
  414. }
  415. static int SVGHasInternalSubset(void *context)
  416. {
  417. SVGInfo
  418. *svg_info;
  419. /*
  420. Does this document has an internal subset?
  421. */
  422. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  423. " SAX.SVGHasInternalSubset()");
  424. svg_info=(SVGInfo *) context;
  425. return(svg_info->document->intSubset != NULL);
  426. }
  427. static int SVGHasExternalSubset(void *context)
  428. {
  429. SVGInfo
  430. *svg_info;
  431. /*
  432. Does this document has an external subset?
  433. */
  434. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  435. " SAX.SVGHasExternalSubset()");
  436. svg_info=(SVGInfo *) context;
  437. return(svg_info->document->extSubset != NULL);
  438. }
  439. static void SVGInternalSubset(void *context,const xmlChar *name,
  440. const xmlChar *external_id,const xmlChar *system_id)
  441. {
  442. SVGInfo
  443. *svg_info;
  444. /*
  445. Does this document has an internal subset?
  446. */
  447. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  448. " SAX.internalSubset(%s, %s, %s)",(const char *) name,
  449. (external_id != (const xmlChar *) NULL ? (const char *) external_id : "none"),
  450. (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
  451. svg_info=(SVGInfo *) context;
  452. (void) xmlCreateIntSubset(svg_info->document,name,external_id,system_id);
  453. }
  454. static xmlParserInputPtr SVGResolveEntity(void *context,
  455. const xmlChar *public_id,const xmlChar *system_id)
  456. {
  457. SVGInfo
  458. *svg_info;
  459. xmlParserInputPtr
  460. stream;
  461. /*
  462. Special entity resolver, better left to the parser, it has more
  463. context than the application layer. The default behaviour is to
  464. not resolve the entities, in that case the ENTITY_REF nodes are
  465. built in the structure (and the parameter values).
  466. */
  467. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  468. " SAX.resolveEntity(%s, %s)",
  469. (public_id != (const xmlChar *) NULL ? (const char *) public_id : "none"),
  470. (system_id != (const xmlChar *) NULL ? (const char *) system_id : "none"));
  471. svg_info=(SVGInfo *) context;
  472. stream=xmlLoadExternalEntity((const char *) system_id,(const char *)
  473. public_id,svg_info->parser);
  474. return(stream);
  475. }
  476. static xmlEntityPtr SVGGetEntity(void *context,const xmlChar *name)
  477. {
  478. SVGInfo
  479. *svg_info;
  480. /*
  481. Get an entity by name.
  482. */
  483. (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.SVGGetEntity(%s)",
  484. name);
  485. svg_info=(SVGInfo *) context;
  486. return(xmlGetDocEntity(svg_info->document,name));
  487. }
  488. static xmlEntityPtr SVGGetParameterEntity(void *context,const xmlChar *name)
  489. {
  490. SVGInfo
  491. *svg_info;
  492. /*
  493. Get a parameter entity by name.
  494. */
  495. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  496. " SAX.getParameterEntity(%s)",name);
  497. svg_info=(SVGInfo *) context;
  498. return(xmlGetParameterEntity(svg_info->document,name));
  499. }
  500. static void SVGEntityDeclaration(void *context,const xmlChar *name,int type,
  501. const xmlChar *public_id,const xmlChar *system_id,xmlChar *content)
  502. {
  503. SVGInfo
  504. *svg_info;
  505. /*
  506. An entity definition has been parsed.
  507. */
  508. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  509. " SAX.entityDecl(%s, %d, %s, %s, %s)",name,type,
  510. public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
  511. system_id != (xmlChar *) NULL ? (const char *) system_id : "none",content);
  512. svg_info=(SVGInfo *) context;
  513. if (svg_info->parser->inSubset == 1)
  514. (void) xmlAddDocEntity(svg_info->document,name,type,public_id,system_id,
  515. content);
  516. else
  517. if (svg_info->parser->inSubset == 2)
  518. (void) xmlAddDtdEntity(svg_info->document,name,type,public_id,system_id,
  519. content);
  520. }
  521. static void SVGAttributeDeclaration(void *context,const xmlChar *element,
  522. const xmlChar *name,int type,int value,const xmlChar *default_value,
  523. xmlEnumerationPtr tree)
  524. {
  525. SVGInfo
  526. *svg_info;
  527. xmlChar
  528. *fullname,
  529. *prefix;
  530. xmlParserCtxtPtr
  531. parser;
  532. /*
  533. An attribute definition has been parsed.
  534. */
  535. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  536. " SAX.attributeDecl(%s, %s, %d, %d, %s, ...)",element,name,type,value,
  537. default_value);
  538. svg_info=(SVGInfo *) context;
  539. fullname=(xmlChar *) NULL;
  540. prefix=(xmlChar *) NULL;
  541. parser=svg_info->parser;
  542. fullname=(xmlChar *) xmlSplitQName(parser,name,&prefix);
  543. if (parser->inSubset == 1)
  544. (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->intSubset,
  545. element,fullname,prefix,(xmlAttributeType) type,
  546. (xmlAttributeDefault) value,default_value,tree);
  547. else
  548. if (parser->inSubset == 2)
  549. (void) xmlAddAttributeDecl(&parser->vctxt,svg_info->document->extSubset,
  550. element,fullname,prefix,(xmlAttributeType) type,
  551. (xmlAttributeDefault) value,default_value,tree);
  552. if (prefix != (xmlChar *) NULL)
  553. xmlFree(prefix);
  554. if (fullname != (xmlChar *) NULL)
  555. xmlFree(fullname);
  556. }
  557. static void SVGElementDeclaration(void *context,const xmlChar *name,int type,
  558. xmlElementContentPtr content)
  559. {
  560. SVGInfo
  561. *svg_info;
  562. xmlParserCtxtPtr
  563. parser;
  564. /*
  565. An element definition has been parsed.
  566. */
  567. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  568. " SAX.elementDecl(%s, %d, ...)",name,type);
  569. svg_info=(SVGInfo *) context;
  570. parser=svg_info->parser;
  571. if (parser->inSubset == 1)
  572. (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->intSubset,
  573. name,(xmlElementTypeVal) type,content);
  574. else
  575. if (parser->inSubset == 2)
  576. (void) xmlAddElementDecl(&parser->vctxt,svg_info->document->extSubset,
  577. name,(xmlElementTypeVal) type,content);
  578. }
  579. static void SVGStripString(const MagickBooleanType trim,char *message)
  580. {
  581. register char
  582. *p,
  583. *q;
  584. size_t
  585. length;
  586. assert(message != (char *) NULL);
  587. if (*message == '\0')
  588. return;
  589. /*
  590. Remove comment.
  591. */
  592. q=message;
  593. for (p=message; *p != '\0'; p++)
  594. {
  595. if ((*p == '/') && (*(p+1) == '*'))
  596. {
  597. for ( ; *p != '\0'; p++)
  598. if ((*p == '*') && (*(p+1) == '/'))
  599. {
  600. p+=2;
  601. break;
  602. }
  603. if (*p == '\0')
  604. break;
  605. }
  606. *q++=(*p);
  607. }
  608. *q='\0';
  609. length=strlen(message);
  610. if ((trim != MagickFalse) && (length != 0))
  611. {
  612. /*
  613. Remove whitespace.
  614. */
  615. p=message;
  616. while (isspace((int) ((unsigned char) *p)) != 0)
  617. p++;
  618. if ((*p == '\'') || (*p == '"'))
  619. p++;
  620. q=message+length-1;
  621. while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
  622. q--;
  623. if (q > p)
  624. if ((*q == '\'') || (*q == '"'))
  625. q--;
  626. (void) memmove(message,p,(size_t) (q-p+1));
  627. message[q-p+1]='\0';
  628. }
  629. /*
  630. Convert newlines to a space.
  631. */
  632. for (p=message; *p != '\0'; p++)
  633. if (*p == '\n')
  634. *p=' ';
  635. }
  636. static char **SVGKeyValuePairs(void *context,const int key_sentinel,
  637. const int value_sentinel,const char *text,size_t *number_tokens)
  638. {
  639. char
  640. **tokens;
  641. register const char
  642. *p,
  643. *q;
  644. register ssize_t
  645. i;
  646. size_t
  647. extent;
  648. SVGInfo
  649. *svg_info;
  650. svg_info=(SVGInfo *) context;
  651. *number_tokens=0;
  652. if (text == (const char *) NULL)
  653. return((char **) NULL);
  654. extent=8;
  655. tokens=(char **) AcquireQuantumMemory(extent+2UL,sizeof(*tokens));
  656. if (tokens == (char **) NULL)
  657. {
  658. (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
  659. ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
  660. return((char **) NULL);
  661. }
  662. /*
  663. Convert string to an ASCII list.
  664. */
  665. i=0;
  666. p=text;
  667. for (q=p; *q != '\0'; q++)
  668. {
  669. if ((*q != key_sentinel) && (*q != value_sentinel) && (*q != '\0'))
  670. continue;
  671. if (i == (ssize_t) extent)
  672. {
  673. extent<<=1;
  674. tokens=(char **) ResizeQuantumMemory(tokens,extent+2,sizeof(*tokens));
  675. if (tokens == (char **) NULL)
  676. {
  677. (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
  678. ResourceLimitError,"MemoryAllocationFailed","`%s'",text);
  679. return((char **) NULL);
  680. }
  681. }
  682. tokens[i]=AcquireString(p);
  683. (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
  684. SVGStripString(MagickTrue,tokens[i]);
  685. i++;
  686. p=q+1;
  687. }
  688. tokens[i]=AcquireString(p);
  689. (void) CopyMagickString(tokens[i],p,(size_t) (q-p+1));
  690. SVGStripString(MagickTrue,tokens[i++]);
  691. tokens[i]=(char *) NULL;
  692. *number_tokens=(size_t) i;
  693. return(tokens);
  694. }
  695. static void SVGNotationDeclaration(void *context,const xmlChar *name,
  696. const xmlChar *public_id,const xmlChar *system_id)
  697. {
  698. SVGInfo
  699. *svg_info;
  700. xmlParserCtxtPtr
  701. parser;
  702. /*
  703. What to do when a notation declaration has been parsed.
  704. */
  705. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  706. " SAX.notationDecl(%s, %s, %s)",name,
  707. public_id != (const xmlChar *) NULL ? (const char *) public_id : "none",
  708. system_id != (const xmlChar *) NULL ? (const char *) system_id : "none");
  709. svg_info=(SVGInfo *) context;
  710. parser=svg_info->parser;
  711. if (parser->inSubset == 1)
  712. (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
  713. name,public_id,system_id);
  714. else
  715. if (parser->inSubset == 2)
  716. (void) xmlAddNotationDecl(&parser->vctxt,svg_info->document->intSubset,
  717. name,public_id,system_id);
  718. }
  719. static void SVGProcessStyleElement(void *context,const xmlChar *name,
  720. const char *style)
  721. {
  722. char
  723. background[MagickPathExtent],
  724. *color,
  725. *keyword,
  726. *units,
  727. *value;
  728. char
  729. **tokens;
  730. register ssize_t
  731. i;
  732. size_t
  733. number_tokens;
  734. SVGInfo
  735. *svg_info;
  736. (void) LogMagickEvent(CoderEvent,GetMagickModule()," ");
  737. svg_info=(SVGInfo *) context;
  738. tokens=SVGKeyValuePairs(context,':',';',style,&number_tokens);
  739. if (tokens == (char **) NULL)
  740. return;
  741. for (i=0; i < (ssize_t) (number_tokens-1); i+=2)
  742. {
  743. keyword=(char *) tokens[i];
  744. value=(char *) tokens[i+1];
  745. if (LocaleCompare(keyword,"font-size") != 0)
  746. continue;
  747. svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
  748. (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
  749. svg_info->pointsize);
  750. }
  751. color=AcquireString("none");
  752. units=AcquireString("userSpaceOnUse");
  753. for (i=0; i < (ssize_t) (number_tokens-1); i+=2)
  754. {
  755. keyword=(char *) tokens[i];
  756. value=(char *) tokens[i+1];
  757. (void) LogMagickEvent(CoderEvent,GetMagickModule()," %s: %s",keyword,
  758. value);
  759. switch (*keyword)
  760. {
  761. case 'B':
  762. case 'b':
  763. {
  764. if (LocaleCompare((const char *) name,"background") == 0)
  765. {
  766. if (LocaleCompare((const char *) name,"svg") == 0)
  767. (void) CopyMagickString(background,value,MagickPathExtent);
  768. break;
  769. }
  770. break;
  771. }
  772. case 'C':
  773. case 'c':
  774. {
  775. if (LocaleCompare(keyword,"clip-path") == 0)
  776. {
  777. (void) FormatLocaleFile(svg_info->file,"clip-path \"%s\"\n",value);
  778. break;
  779. }
  780. if (LocaleCompare(keyword,"clip-rule") == 0)
  781. {
  782. (void) FormatLocaleFile(svg_info->file,"clip-rule \"%s\"\n",value);
  783. break;
  784. }
  785. if (LocaleCompare(keyword,"clipPathUnits") == 0)
  786. {
  787. (void) CloneString(&units,value);
  788. (void) FormatLocaleFile(svg_info->file,"clip-units \"%s\"\n",
  789. value);
  790. break;
  791. }
  792. if (LocaleCompare(keyword,"color") == 0)
  793. {
  794. (void) CloneString(&color,value);
  795. break;
  796. }
  797. break;
  798. }
  799. case 'F':
  800. case 'f':
  801. {
  802. if (LocaleCompare(keyword,"fill") == 0)
  803. {
  804. if (LocaleCompare(value,"currentColor") == 0)
  805. {
  806. (void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",color);
  807. break;
  808. }
  809. if (LocaleCompare(value,"#000000ff") == 0)
  810. (void) FormatLocaleFile(svg_info->file,"fill '#000000'\n");
  811. else
  812. (void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
  813. break;
  814. }
  815. if (LocaleCompare(keyword,"fillcolor") == 0)
  816. {
  817. (void) FormatLocaleFile(svg_info->file,"fill \"%s\"\n",value);
  818. break;
  819. }
  820. if (LocaleCompare(keyword,"fill-rule") == 0)
  821. {
  822. (void) FormatLocaleFile(svg_info->file,"fill-rule \"%s\"\n",value);
  823. break;
  824. }
  825. if (LocaleCompare(keyword,"fill-opacity") == 0)
  826. {
  827. (void) FormatLocaleFile(svg_info->file,"fill-opacity \"%s\"\n",
  828. value);
  829. break;
  830. }
  831. if (LocaleCompare(keyword,"font") == 0)
  832. {
  833. char
  834. family[MagickPathExtent],
  835. size[MagickPathExtent],
  836. style[MagickPathExtent];
  837. if (sscanf(value,"%2048s %2048s %2048s",style,size,family) != 3)
  838. break;
  839. if (GetUserSpaceCoordinateValue(svg_info,0,style) == 0)
  840. (void) FormatLocaleFile(svg_info->file,"font-style \"%s\"\n",
  841. style);
  842. else
  843. if (sscanf(value,"%2048s %2048s",size,family) != 2)
  844. break;
  845. (void) FormatLocaleFile(svg_info->file,"font-size \"%s\"\n",size);
  846. (void) FormatLocaleFile(svg_info->file,"font-family \"%s\"\n",
  847. family);
  848. break;
  849. }
  850. if (LocaleCompare(keyword,"font-family") == 0)
  851. {
  852. (void) FormatLocaleFile(svg_info->file,"font-family \"%s\"\n",
  853. value);
  854. break;
  855. }
  856. if (LocaleCompare(keyword,"font-stretch") == 0)
  857. {
  858. (void) FormatLocaleFile(svg_info->file,"font-stretch \"%s\"\n",
  859. value);
  860. break;
  861. }
  862. if (LocaleCompare(keyword,"font-style") == 0)
  863. {
  864. (void) FormatLocaleFile(svg_info->file,"font-style \"%s\"\n",value);
  865. break;
  866. }
  867. if (LocaleCompare(keyword,"font-size") == 0)
  868. {
  869. svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
  870. (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
  871. svg_info->pointsize);
  872. break;
  873. }
  874. if (LocaleCompare(keyword,"font-weight") == 0)
  875. {
  876. (void) FormatLocaleFile(svg_info->file,"font-weight \"%s\"\n",
  877. value);
  878. break;
  879. }
  880. break;
  881. }
  882. case 'K':
  883. case 'k':
  884. {
  885. if (LocaleCompare(keyword,"kerning") == 0)
  886. {
  887. (void) FormatLocaleFile(svg_info->file,"kerning \"%s\"\n",value);
  888. break;
  889. }
  890. break;
  891. }
  892. case 'L':
  893. case 'l':
  894. {
  895. if (LocaleCompare(keyword,"letter-spacing") == 0)
  896. {
  897. (void) FormatLocaleFile(svg_info->file,"letter-spacing \"%s\"\n",
  898. value);
  899. break;
  900. }
  901. break;
  902. }
  903. case 'M':
  904. case 'm':
  905. {
  906. if (LocaleCompare(keyword,"mask") == 0)
  907. {
  908. (void) FormatLocaleFile(svg_info->file,"mask \"%s\"\n",value);
  909. break;
  910. }
  911. break;
  912. }
  913. case 'O':
  914. case 'o':
  915. {
  916. if (LocaleCompare(keyword,"offset") == 0)
  917. {
  918. (void) FormatLocaleFile(svg_info->file,"offset %g\n",
  919. GetUserSpaceCoordinateValue(svg_info,1,value));
  920. break;
  921. }
  922. if (LocaleCompare(keyword,"opacity") == 0)
  923. {
  924. (void) FormatLocaleFile(svg_info->file,"opacity \"%s\"\n",value);
  925. break;
  926. }
  927. break;
  928. }
  929. case 'S':
  930. case 's':
  931. {
  932. if (LocaleCompare(keyword,"stop-color") == 0)
  933. {
  934. (void) CloneString(&svg_info->stop_color,value);
  935. break;
  936. }
  937. if (LocaleCompare(keyword,"stroke") == 0)
  938. {
  939. if (LocaleCompare(value,"currentColor") == 0)
  940. {
  941. (void) FormatLocaleFile(svg_info->file,"stroke \"%s\"\n",color);
  942. break;
  943. }
  944. if (LocaleCompare(value,"#000000ff") == 0)
  945. (void) FormatLocaleFile(svg_info->file,"fill '#000000'\n");
  946. else
  947. (void) FormatLocaleFile(svg_info->file,
  948. "stroke \"%s\"\n",value);
  949. break;
  950. }
  951. if (LocaleCompare(keyword,"stroke-antialiasing") == 0)
  952. {
  953. (void) FormatLocaleFile(svg_info->file,"stroke-antialias %d\n",
  954. LocaleCompare(value,"true") == 0);
  955. break;
  956. }
  957. if (LocaleCompare(keyword,"stroke-dasharray") == 0)
  958. {
  959. (void) FormatLocaleFile(svg_info->file,"stroke-dasharray %s\n",
  960. value);
  961. break;
  962. }
  963. if (LocaleCompare(keyword,"stroke-dashoffset") == 0)
  964. {
  965. (void) FormatLocaleFile(svg_info->file,"stroke-dashoffset %g\n",
  966. GetUserSpaceCoordinateValue(svg_info,1,value));
  967. break;
  968. }
  969. if (LocaleCompare(keyword,"stroke-linecap") == 0)
  970. {
  971. (void) FormatLocaleFile(svg_info->file,"stroke-linecap \"%s\"\n",
  972. value);
  973. break;
  974. }
  975. if (LocaleCompare(keyword,"stroke-linejoin") == 0)
  976. {
  977. (void) FormatLocaleFile(svg_info->file,"stroke-linejoin \"%s\"\n",
  978. value);
  979. break;
  980. }
  981. if (LocaleCompare(keyword,"stroke-miterlimit") == 0)
  982. {
  983. (void) FormatLocaleFile(svg_info->file,"stroke-miterlimit \"%s\"\n",
  984. value);
  985. break;
  986. }
  987. if (LocaleCompare(keyword,"stroke-opacity") == 0)
  988. {
  989. (void) FormatLocaleFile(svg_info->file,"stroke-opacity \"%s\"\n",
  990. value);
  991. break;
  992. }
  993. if (LocaleCompare(keyword,"stroke-width") == 0)
  994. {
  995. (void) FormatLocaleFile(svg_info->file,"stroke-width %g\n",
  996. GetUserSpaceCoordinateValue(svg_info,1,value));
  997. break;
  998. }
  999. break;
  1000. }
  1001. case 't':
  1002. case 'T':
  1003. {
  1004. if (LocaleCompare(keyword,"text-align") == 0)
  1005. {
  1006. (void) FormatLocaleFile(svg_info->file,"text-align \"%s\"\n",value);
  1007. break;
  1008. }
  1009. if (LocaleCompare(keyword,"text-anchor") == 0)
  1010. {
  1011. (void) FormatLocaleFile(svg_info->file,"text-anchor \"%s\"\n",
  1012. value);
  1013. break;
  1014. }
  1015. if (LocaleCompare(keyword,"text-decoration") == 0)
  1016. {
  1017. if (LocaleCompare(value,"underline") == 0)
  1018. (void) FormatLocaleFile(svg_info->file,"decorate underline\n");
  1019. if (LocaleCompare(value,"line-through") == 0)
  1020. (void) FormatLocaleFile(svg_info->file,"decorate line-through\n");
  1021. if (LocaleCompare(value,"overline") == 0)
  1022. (void) FormatLocaleFile(svg_info->file,"decorate overline\n");
  1023. break;
  1024. }
  1025. if (LocaleCompare(keyword,"text-antialiasing") == 0)
  1026. {
  1027. (void) FormatLocaleFile(svg_info->file,"text-antialias %d\n",
  1028. LocaleCompare(value,"true") == 0);
  1029. break;
  1030. }
  1031. break;
  1032. }
  1033. default:
  1034. break;
  1035. }
  1036. }
  1037. if (units != (char *) NULL)
  1038. units=DestroyString(units);
  1039. if (color != (char *) NULL)
  1040. color=DestroyString(color);
  1041. for (i=0; tokens[i] != (char *) NULL; i++)
  1042. tokens[i]=DestroyString(tokens[i]);
  1043. tokens=(char **) RelinquishMagickMemory(tokens);
  1044. }
  1045. static void SVGUnparsedEntityDeclaration(void *context,const xmlChar *name,
  1046. const xmlChar *public_id,const xmlChar *system_id,const xmlChar *notation)
  1047. {
  1048. SVGInfo
  1049. *svg_info;
  1050. /*
  1051. What to do when an unparsed entity declaration is parsed.
  1052. */
  1053. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  1054. " SAX.unparsedEntityDecl(%s, %s, %s, %s)",name,
  1055. public_id != (xmlChar *) NULL ? (const char *) public_id : "none",
  1056. system_id != (xmlChar *) NULL ? (const char *) system_id : "none",notation);
  1057. svg_info=(SVGInfo *) context;
  1058. (void) xmlAddDocEntity(svg_info->document,name,
  1059. XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,public_id,system_id,notation);
  1060. }
  1061. static void SVGSetDocumentLocator(void *context,xmlSAXLocatorPtr location)
  1062. {
  1063. SVGInfo
  1064. *svg_info;
  1065. /*
  1066. Receive the document locator at startup, actually xmlDefaultSAXLocator.
  1067. */
  1068. (void) location;
  1069. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  1070. " SAX.setDocumentLocator()");
  1071. svg_info=(SVGInfo *) context;
  1072. (void) svg_info;
  1073. }
  1074. static void SVGStartDocument(void *context)
  1075. {
  1076. SVGInfo
  1077. *svg_info;
  1078. xmlParserCtxtPtr
  1079. parser;
  1080. /*
  1081. Called when the document start being processed.
  1082. */
  1083. (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startDocument()");
  1084. svg_info=(SVGInfo *) context;
  1085. parser=svg_info->parser;
  1086. svg_info->document=xmlNewDoc(parser->version);
  1087. if (svg_info->document == (xmlDocPtr) NULL)
  1088. return;
  1089. if (parser->encoding == NULL)
  1090. svg_info->document->encoding=(const xmlChar *) NULL;
  1091. else
  1092. svg_info->document->encoding=xmlStrdup(parser->encoding);
  1093. svg_info->document->standalone=parser->standalone;
  1094. }
  1095. static void SVGEndDocument(void *context)
  1096. {
  1097. SVGInfo
  1098. *svg_info;
  1099. /*
  1100. Called when the document end has been detected.
  1101. */
  1102. (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.endDocument()");
  1103. svg_info=(SVGInfo *) context;
  1104. if (svg_info->offset != (char *) NULL)
  1105. svg_info->offset=DestroyString(svg_info->offset);
  1106. if (svg_info->stop_color != (char *) NULL)
  1107. svg_info->stop_color=DestroyString(svg_info->stop_color);
  1108. if (svg_info->scale != (double *) NULL)
  1109. svg_info->scale=(double *) RelinquishMagickMemory(svg_info->scale);
  1110. if (svg_info->text != (char *) NULL)
  1111. svg_info->text=DestroyString(svg_info->text);
  1112. if (svg_info->vertices != (char *) NULL)
  1113. svg_info->vertices=DestroyString(svg_info->vertices);
  1114. if (svg_info->url != (char *) NULL)
  1115. svg_info->url=DestroyString(svg_info->url);
  1116. #if defined(MAGICKCORE_XML_DELEGATE)
  1117. if (svg_info->document != (xmlDocPtr) NULL)
  1118. {
  1119. xmlFreeDoc(svg_info->document);
  1120. svg_info->document=(xmlDocPtr) NULL;
  1121. }
  1122. #endif
  1123. }
  1124. static void SVGStartElement(void *context,const xmlChar *name,
  1125. const xmlChar **attributes)
  1126. {
  1127. #define PushGraphicContext(id) \
  1128. { \
  1129. if (*id == '\0') \
  1130. (void) FormatLocaleFile(svg_info->file,"push graphic-context\n"); \
  1131. else \
  1132. (void) FormatLocaleFile(svg_info->file,"push graphic-context \"%s\"\n", \
  1133. id); \
  1134. }
  1135. char
  1136. *color,
  1137. background[MagickPathExtent],
  1138. id[MagickPathExtent],
  1139. *next_token,
  1140. token[MagickPathExtent],
  1141. **tokens,
  1142. *units;
  1143. const char
  1144. *keyword,
  1145. *p,
  1146. *value;
  1147. register ssize_t
  1148. i,
  1149. j;
  1150. size_t
  1151. number_tokens;
  1152. SVGInfo
  1153. *svg_info;
  1154. /*
  1155. Called when an opening tag has been processed.
  1156. */
  1157. (void) LogMagickEvent(CoderEvent,GetMagickModule()," SAX.startElement(%s",
  1158. name);
  1159. svg_info=(SVGInfo *) context;
  1160. svg_info->n++;
  1161. svg_info->scale=(double *) ResizeQuantumMemory(svg_info->scale,
  1162. svg_info->n+1UL,sizeof(*svg_info->scale));
  1163. if (svg_info->scale == (double *) NULL)
  1164. {
  1165. (void) ThrowMagickException(svg_info->exception,GetMagickModule(),
  1166. ResourceLimitError,"MemoryAllocationFailed","`%s'",name);
  1167. return;
  1168. }
  1169. svg_info->scale[svg_info->n]=svg_info->scale[svg_info->n-1];
  1170. color=AcquireString("none");
  1171. units=AcquireString("userSpaceOnUse");
  1172. *id='\0';
  1173. *token='\0';
  1174. *background='\0';
  1175. value=(const char *) NULL;
  1176. if ((LocaleCompare((char *) name,"image") == 0) ||
  1177. (LocaleCompare((char *) name,"pattern") == 0) ||
  1178. (LocaleCompare((char *) name,"rect") == 0) ||
  1179. (LocaleCompare((char *) name,"text") == 0) ||
  1180. (LocaleCompare((char *) name,"use") == 0))
  1181. {
  1182. svg_info->bounds.x=0.0;
  1183. svg_info->bounds.y=0.0;
  1184. }
  1185. if (attributes != (const xmlChar **) NULL)
  1186. for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
  1187. {
  1188. keyword=(const char *) attributes[i];
  1189. value=(const char *) attributes[i+1];
  1190. switch (*keyword)
  1191. {
  1192. case 'C':
  1193. case 'c':
  1194. {
  1195. if (LocaleCompare(keyword,"cx") == 0)
  1196. {
  1197. svg_info->element.cx=
  1198. GetUserSpaceCoordinateValue(svg_info,1,value);
  1199. break;
  1200. }
  1201. if (LocaleCompare(keyword,"cy") == 0)
  1202. {
  1203. svg_info->element.cy=
  1204. GetUserSpaceCoordinateValue(svg_info,-1,value);
  1205. break;
  1206. }
  1207. break;
  1208. }
  1209. case 'F':
  1210. case 'f':
  1211. {
  1212. if (LocaleCompare(keyword,"fx") == 0)
  1213. {
  1214. svg_info->element.major=
  1215. GetUserSpaceCoordinateValue(svg_info,1,value);
  1216. break;
  1217. }
  1218. if (LocaleCompare(keyword,"fy") == 0)
  1219. {
  1220. svg_info->element.minor=
  1221. GetUserSpaceCoordinateValue(svg_info,-1,value);
  1222. break;
  1223. }
  1224. break;
  1225. }
  1226. case 'H':
  1227. case 'h':
  1228. {
  1229. if (LocaleCompare(keyword,"height") == 0)
  1230. {
  1231. svg_info->bounds.height=
  1232. GetUserSpaceCoordinateValue(svg_info,-1,value);
  1233. break;
  1234. }
  1235. break;
  1236. }
  1237. case 'I':
  1238. case 'i':
  1239. {
  1240. if (LocaleCompare(keyword,"id") == 0)
  1241. {
  1242. (void) CopyMagickString(id,value,MagickPathExtent);
  1243. break;
  1244. }
  1245. break;
  1246. }
  1247. case 'R':
  1248. case 'r':
  1249. {
  1250. if (LocaleCompare(keyword,"r") == 0)
  1251. {
  1252. svg_info->element.angle=
  1253. GetUserSpaceCoordinateValue(svg_info,0,value);
  1254. break;
  1255. }
  1256. break;
  1257. }
  1258. case 'W':
  1259. case 'w':
  1260. {
  1261. if (LocaleCompare(keyword,"width") == 0)
  1262. {
  1263. svg_info->bounds.width=
  1264. GetUserSpaceCoordinateValue(svg_info,1,value);
  1265. break;
  1266. }
  1267. break;
  1268. }
  1269. case 'X':
  1270. case 'x':
  1271. {
  1272. if (LocaleCompare(keyword,"x") == 0)
  1273. {
  1274. svg_info->bounds.x=GetUserSpaceCoordinateValue(svg_info,1,value);
  1275. break;
  1276. }
  1277. if (LocaleCompare(keyword,"x1") == 0)
  1278. {
  1279. svg_info->segment.x1=GetUserSpaceCoordinateValue(svg_info,1,
  1280. value);
  1281. break;
  1282. }
  1283. if (LocaleCompare(keyword,"x2") == 0)
  1284. {
  1285. svg_info->segment.x2=GetUserSpaceCoordinateValue(svg_info,1,
  1286. value);
  1287. break;
  1288. }
  1289. break;
  1290. }
  1291. case 'Y':
  1292. case 'y':
  1293. {
  1294. if (LocaleCompare(keyword,"y") == 0)
  1295. {
  1296. svg_info->bounds.y=GetUserSpaceCoordinateValue(svg_info,-1,value);
  1297. break;
  1298. }
  1299. if (LocaleCompare(keyword,"y1") == 0)
  1300. {
  1301. svg_info->segment.y1=GetUserSpaceCoordinateValue(svg_info,-1,
  1302. value);
  1303. break;
  1304. }
  1305. if (LocaleCompare(keyword,"y2") == 0)
  1306. {
  1307. svg_info->segment.y2=GetUserSpaceCoordinateValue(svg_info,-1,
  1308. value);
  1309. break;
  1310. }
  1311. break;
  1312. }
  1313. default:
  1314. break;
  1315. }
  1316. }
  1317. if (strchr((char *) name,':') != (char *) NULL)
  1318. {
  1319. /*
  1320. Skip over namespace.
  1321. */
  1322. for ( ; *name != ':'; name++) ;
  1323. name++;
  1324. }
  1325. switch (*name)
  1326. {
  1327. case 'C':
  1328. case 'c':
  1329. {
  1330. if (LocaleCompare((const char *) name,"circle") == 0)
  1331. {
  1332. PushGraphicContext(id);
  1333. break;
  1334. }
  1335. if (LocaleCompare((const char *) name,"clipPath") == 0)
  1336. {
  1337. (void) FormatLocaleFile(svg_info->file,"push clip-path \"%s\"\n",id);
  1338. break;
  1339. }
  1340. break;
  1341. }
  1342. case 'D':
  1343. case 'd':
  1344. {
  1345. if (LocaleCompare((const char *) name,"defs") == 0)
  1346. {
  1347. (void) FormatLocaleFile(svg_info->file,"push defs\n");
  1348. break;
  1349. }
  1350. break;
  1351. }
  1352. case 'E':
  1353. case 'e':
  1354. {
  1355. if (LocaleCompare((const char *) name,"ellipse") == 0)
  1356. {
  1357. PushGraphicContext(id);
  1358. break;
  1359. }
  1360. break;
  1361. }
  1362. case 'F':
  1363. case 'f':
  1364. {
  1365. if (LocaleCompare((const char *) name,"foreignObject") == 0)
  1366. {
  1367. PushGraphicContext(id);
  1368. break;
  1369. }
  1370. break;
  1371. }
  1372. case 'G':
  1373. case 'g':
  1374. {
  1375. if (LocaleCompare((const char *) name,"g") == 0)
  1376. {
  1377. PushGraphicContext(id);
  1378. break;
  1379. }
  1380. break;
  1381. }
  1382. case 'I':
  1383. case 'i':
  1384. {
  1385. if (LocaleCompare((const char *) name,"image") == 0)
  1386. {
  1387. PushGraphicContext(id);
  1388. break;
  1389. }
  1390. break;
  1391. }
  1392. case 'L':
  1393. case 'l':
  1394. {
  1395. if (LocaleCompare((const char *) name,"line") == 0)
  1396. {
  1397. PushGraphicContext(id);
  1398. break;
  1399. }
  1400. if (LocaleCompare((const char *) name,"linearGradient") == 0)
  1401. {
  1402. (void) FormatLocaleFile(svg_info->file,
  1403. "push gradient \"%s\" linear %g,%g %g,%g\n",id,
  1404. svg_info->segment.x1,svg_info->segment.y1,svg_info->segment.x2,
  1405. svg_info->segment.y2);
  1406. break;
  1407. }
  1408. break;
  1409. }
  1410. case 'M':
  1411. case 'm':
  1412. {
  1413. if (LocaleCompare((const char *) name,"mask") == 0)
  1414. {
  1415. (void) FormatLocaleFile(svg_info->file,"push mask \"%s\"\n",id);
  1416. break;
  1417. }
  1418. break;
  1419. }
  1420. case 'P':
  1421. case 'p':
  1422. {
  1423. if (LocaleCompare((const char *) name,"path") == 0)
  1424. {
  1425. PushGraphicContext(id);
  1426. break;
  1427. }
  1428. if (LocaleCompare((const char *) name,"pattern") == 0)
  1429. {
  1430. (void) FormatLocaleFile(svg_info->file,
  1431. "push pattern \"%s\" %g,%g %g,%g\n",id,
  1432. svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width,
  1433. svg_info->bounds.height);
  1434. break;
  1435. }
  1436. if (LocaleCompare((const char *) name,"polygon") == 0)
  1437. {
  1438. PushGraphicContext(id);
  1439. break;
  1440. }
  1441. if (LocaleCompare((const char *) name,"polyline") == 0)
  1442. {
  1443. PushGraphicContext(id);
  1444. break;
  1445. }
  1446. break;
  1447. }
  1448. case 'R':
  1449. case 'r':
  1450. {
  1451. if (LocaleCompare((const char *) name,"radialGradient") == 0)
  1452. {
  1453. (void) FormatLocaleFile(svg_info->file,
  1454. "push gradient \"%s\" radial %g,%g %g,%g %g\n",
  1455. id,svg_info->element.cx,svg_info->element.cy,
  1456. svg_info->element.major,svg_info->element.minor,
  1457. svg_info->element.angle);
  1458. break;
  1459. }
  1460. if (LocaleCompare((const char *) name,"rect") == 0)
  1461. {
  1462. PushGraphicContext(id);
  1463. break;
  1464. }
  1465. break;
  1466. }
  1467. case 'S':
  1468. case 's':
  1469. {
  1470. if (LocaleCompare((char *) name,"style") == 0)
  1471. break;
  1472. if (LocaleCompare((const char *) name,"svg") == 0)
  1473. {
  1474. svg_info->svgDepth++;
  1475. PushGraphicContext(id);
  1476. (void) FormatLocaleFile(svg_info->file,"compliance \"SVG\"\n");
  1477. (void) FormatLocaleFile(svg_info->file,"fill \"black\"\n");
  1478. (void) FormatLocaleFile(svg_info->file,"fill-opacity 1\n");
  1479. (void) FormatLocaleFile(svg_info->file,"stroke \"none\"\n");
  1480. (void) FormatLocaleFile(svg_info->file,"stroke-width 1\n");
  1481. (void) FormatLocaleFile(svg_info->file,"stroke-opacity 1\n");
  1482. (void) FormatLocaleFile(svg_info->file,"fill-rule nonzero\n");
  1483. break;
  1484. }
  1485. if (LocaleCompare((const char *) name,"symbol") == 0)
  1486. {
  1487. (void) FormatLocaleFile(svg_info->file,"push symbol\n");
  1488. break;
  1489. }
  1490. break;
  1491. }
  1492. case 'T':
  1493. case 't':
  1494. {
  1495. if (LocaleCompare((const char *) name,"text") == 0)
  1496. {
  1497. PushGraphicContext(id);
  1498. (void) FormatLocaleFile(svg_info->file,"class \"text\"\n");
  1499. svg_info->text_offset.x=svg_info->bounds.x;
  1500. svg_info->text_offset.y=svg_info->bounds.y;
  1501. svg_info->bounds.x=0.0;
  1502. svg_info->bounds.y=0.0;
  1503. svg_info->bounds.width=0.0;
  1504. svg_info->bounds.height=0.0;
  1505. break;
  1506. }
  1507. if (LocaleCompare((const char *) name,"tspan") == 0)
  1508. {
  1509. if (*svg_info->text != '\0')
  1510. {
  1511. char
  1512. *text;
  1513. SVGStripString(MagickTrue,svg_info->text);
  1514. text=EscapeString(svg_info->text,'\"');
  1515. (void) FormatLocaleFile(svg_info->file,"text %g,%g \"%s\"\n",
  1516. svg_info->text_offset.x,svg_info->text_offset.y,text);
  1517. text=DestroyString(text);
  1518. *svg_info->text='\0';
  1519. }
  1520. PushGraphicContext(id);
  1521. break;
  1522. }
  1523. break;
  1524. }
  1525. case 'U':
  1526. case 'u':
  1527. {
  1528. if (LocaleCompare((char *) name,"use") == 0)
  1529. {
  1530. PushGraphicContext(id);
  1531. break;
  1532. }
  1533. break;
  1534. }
  1535. default:
  1536. break;
  1537. }
  1538. if (attributes != (const xmlChar **) NULL)
  1539. for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
  1540. {
  1541. keyword=(const char *) attributes[i];
  1542. value=(const char *) attributes[i+1];
  1543. (void) LogMagickEvent(CoderEvent,GetMagickModule(),
  1544. " %s = %s",keyword,value);
  1545. switch (*keyword)
  1546. {
  1547. case 'A':
  1548. case 'a':
  1549. {
  1550. if (LocaleCompare(keyword,"angle") == 0)
  1551. {
  1552. (void) FormatLocaleFile(svg_info->file,"angle %g\n",
  1553. GetUserSpaceCoordinateValue(svg_info,0,value));
  1554. break;
  1555. }
  1556. break;
  1557. }
  1558. case 'C':
  1559. case 'c':
  1560. {
  1561. if (LocaleCompare(keyword,"class") == 0)
  1562. {
  1563. const char
  1564. *p;
  1565. for (p=value; ; )
  1566. {
  1567. GetNextToken(p,&p,MagickPathExtent,token);
  1568. if (*token == ',')
  1569. GetNextToken(p,&p,MagickPathExtent,token);
  1570. if (*token != '\0')
  1571. {
  1572. (void) FormatLocaleFile(svg_info->file,"class \"%s\"\n",
  1573. value);
  1574. break;
  1575. }
  1576. }
  1577. break;
  1578. }
  1579. if (LocaleCompare(keyword,"clip-path") == 0)
  1580. {
  1581. (void) FormatLocaleFile(svg_info->file,"clip-path \"%s\"\n",
  1582. value);
  1583. break;
  1584. }
  1585. if (LocaleCompare(keyword,"clip-rule") == 0)
  1586. {
  1587. (void) FormatLocaleFile(svg_info->file,"clip-rule \"%s\"\n",
  1588. value);
  1589. break;
  1590. }
  1591. if (LocaleCompare(keyword,"clipPathUnits") == 0)
  1592. {
  1593. (void) CloneString(&units,value);
  1594. (void) FormatLocaleFile(svg_info->file,"clip-units \"%s\"\n",
  1595. value);
  1596. break;
  1597. }
  1598. if (LocaleCompare(keyword,"color") == 0)
  1599. {
  1600. (void) CloneString(&color,value);
  1601. break;
  1602. }
  1603. if (LocaleCompare(keyword,"cx") == 0)
  1604. {
  1605. svg_info->element.cx=
  1606. GetUserSpaceCoordinateValue(svg_info,1,value);
  1607. break;
  1608. }
  1609. if (LocaleCompare(keyword,"cy") == 0)
  1610. {
  1611. svg_info->element.cy=
  1612. GetUserSpaceCoordinateValue(svg_info,-1,value);
  1613. break;
  1614. }
  1615. break;
  1616. }
  1617. case 'D':
  1618. case 'd':
  1619. {
  1620. if (LocaleCompare(keyword,"d") == 0)
  1621. {
  1622. (void) CloneString(&svg_info->vertices,value);
  1623. break;
  1624. }
  1625. if (Locale

Large files files are truncated, but you can click here to view the full file