PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 1ms

/MagickCore/draw.c

https://gitlab.com/ImageMagick/ImageMagick
C | 7487 lines | 6298 code | 331 blank | 858 comment | 1382 complexity | 21ae1370ce1858972c291d10c68a9f34 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. % DDDD RRRR AAA W W %
  7. % D D R R A A W W %
  8. % D D RRRR AAAAA W W W %
  9. % D D R RN A A WW WW %
  10. % DDDD R R A A W W %
  11. % %
  12. % %
  13. % MagickCore Image Drawing Methods %
  14. % %
  15. % %
  16. % Software Design %
  17. % Cristy %
  18. % July 1998 %
  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. % Bill Radcliffe of Corbis (www.corbis.com) contributed the polygon
  38. % rendering code based on Paul Heckbert's "Concave Polygon Scan Conversion",
  39. % Graphics Gems, 1990. Leonard Rosenthal and David Harr of Appligent
  40. % (www.appligent.com) contributed the dash pattern, linecap stroking
  41. % algorithm, and minor rendering improvements.
  42. %
  43. */
  44. /*
  45. Include declarations.
  46. */
  47. #include "MagickCore/studio.h"
  48. #include "MagickCore/annotate.h"
  49. #include "MagickCore/artifact.h"
  50. #include "MagickCore/blob.h"
  51. #include "MagickCore/cache.h"
  52. #include "MagickCore/cache-private.h"
  53. #include "MagickCore/cache-view.h"
  54. #include "MagickCore/channel.h"
  55. #include "MagickCore/color.h"
  56. #include "MagickCore/colorspace-private.h"
  57. #include "MagickCore/composite.h"
  58. #include "MagickCore/composite-private.h"
  59. #include "MagickCore/constitute.h"
  60. #include "MagickCore/draw.h"
  61. #include "MagickCore/draw-private.h"
  62. #include "MagickCore/enhance.h"
  63. #include "MagickCore/exception.h"
  64. #include "MagickCore/exception-private.h"
  65. #include "MagickCore/gem.h"
  66. #include "MagickCore/geometry.h"
  67. #include "MagickCore/image-private.h"
  68. #include "MagickCore/list.h"
  69. #include "MagickCore/log.h"
  70. #include "MagickCore/memory-private.h"
  71. #include "MagickCore/monitor.h"
  72. #include "MagickCore/monitor-private.h"
  73. #include "MagickCore/option.h"
  74. #include "MagickCore/paint.h"
  75. #include "MagickCore/pixel-accessor.h"
  76. #include "MagickCore/pixel-private.h"
  77. #include "MagickCore/property.h"
  78. #include "MagickCore/resample.h"
  79. #include "MagickCore/resample-private.h"
  80. #include "MagickCore/resource_.h"
  81. #include "MagickCore/splay-tree.h"
  82. #include "MagickCore/string_.h"
  83. #include "MagickCore/string-private.h"
  84. #include "MagickCore/thread-private.h"
  85. #include "MagickCore/token.h"
  86. #include "MagickCore/transform-private.h"
  87. #include "MagickCore/utility.h"
  88. /*
  89. Define declarations.
  90. */
  91. #define BezierQuantum 200
  92. #define PrimitiveExtentPad 2048
  93. #define MaxBezierCoordinates 4194304
  94. #define ThrowPointExpectedException(token,exception) \
  95. { \
  96. (void) ThrowMagickException(exception,GetMagickModule(),DrawError, \
  97. "NonconformingDrawingPrimitiveDefinition","`%s'",token); \
  98. status=MagickFalse; \
  99. break; \
  100. }
  101. /*
  102. Typedef declarations.
  103. */
  104. typedef struct _EdgeInfo
  105. {
  106. SegmentInfo
  107. bounds;
  108. double
  109. scanline;
  110. PointInfo
  111. *points;
  112. size_t
  113. number_points;
  114. ssize_t
  115. direction;
  116. MagickBooleanType
  117. ghostline;
  118. size_t
  119. highwater;
  120. } EdgeInfo;
  121. typedef struct _ElementInfo
  122. {
  123. double
  124. cx,
  125. cy,
  126. major,
  127. minor,
  128. angle;
  129. } ElementInfo;
  130. typedef struct _MVGInfo
  131. {
  132. PrimitiveInfo
  133. **primitive_info;
  134. size_t
  135. *extent;
  136. ssize_t
  137. offset;
  138. PointInfo
  139. point;
  140. ExceptionInfo
  141. *exception;
  142. } MVGInfo;
  143. typedef struct _PolygonInfo
  144. {
  145. EdgeInfo
  146. *edges;
  147. size_t
  148. number_edges;
  149. } PolygonInfo;
  150. typedef enum
  151. {
  152. MoveToCode,
  153. OpenCode,
  154. GhostlineCode,
  155. LineToCode,
  156. EndCode
  157. } PathInfoCode;
  158. typedef struct _PathInfo
  159. {
  160. PointInfo
  161. point;
  162. PathInfoCode
  163. code;
  164. } PathInfo;
  165. /*
  166. Forward declarations.
  167. */
  168. static Image
  169. *DrawClippingMask(Image *,const DrawInfo *,const char *,const char *,
  170. ExceptionInfo *);
  171. static MagickBooleanType
  172. DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *,
  173. ExceptionInfo *),
  174. RenderMVGContent(Image *,const DrawInfo *,const size_t,ExceptionInfo *),
  175. TraceArc(MVGInfo *,const PointInfo,const PointInfo,const PointInfo),
  176. TraceArcPath(MVGInfo *,const PointInfo,const PointInfo,const PointInfo,
  177. const double,const MagickBooleanType,const MagickBooleanType),
  178. TraceBezier(MVGInfo *,const size_t),
  179. TraceCircle(MVGInfo *,const PointInfo,const PointInfo),
  180. TraceEllipse(MVGInfo *,const PointInfo,const PointInfo,const PointInfo),
  181. TraceLine(PrimitiveInfo *,const PointInfo,const PointInfo),
  182. TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo),
  183. TraceRoundRectangle(MVGInfo *,const PointInfo,const PointInfo,PointInfo),
  184. TraceSquareLinecap(PrimitiveInfo *,const size_t,const double);
  185. static PrimitiveInfo
  186. *TraceStrokePolygon(const Image *,const DrawInfo *,const PrimitiveInfo *);
  187. static size_t
  188. TracePath(MVGInfo *,const char *,ExceptionInfo *);
  189. /*
  190. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  191. % %
  192. % %
  193. % %
  194. % A c q u i r e D r a w I n f o %
  195. % %
  196. % %
  197. % %
  198. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  199. %
  200. % AcquireDrawInfo() returns a DrawInfo structure properly initialized.
  201. %
  202. % The format of the AcquireDrawInfo method is:
  203. %
  204. % DrawInfo *AcquireDrawInfo(void)
  205. %
  206. */
  207. MagickExport DrawInfo *AcquireDrawInfo(void)
  208. {
  209. DrawInfo
  210. *draw_info;
  211. draw_info=(DrawInfo *) AcquireCriticalMemory(sizeof(*draw_info));
  212. GetDrawInfo((ImageInfo *) NULL,draw_info);
  213. return(draw_info);
  214. }
  215. /*
  216. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  217. % %
  218. % %
  219. % %
  220. % C l o n e D r a w I n f o %
  221. % %
  222. % %
  223. % %
  224. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  225. %
  226. % CloneDrawInfo() makes a copy of the given draw_info structure. If NULL
  227. % is specified, a new DrawInfo structure is created initialized to default
  228. % values.
  229. %
  230. % The format of the CloneDrawInfo method is:
  231. %
  232. % DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
  233. % const DrawInfo *draw_info)
  234. %
  235. % A description of each parameter follows:
  236. %
  237. % o image_info: the image info.
  238. %
  239. % o draw_info: the draw info.
  240. %
  241. */
  242. MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
  243. const DrawInfo *draw_info)
  244. {
  245. DrawInfo
  246. *clone_info;
  247. ExceptionInfo
  248. *exception;
  249. clone_info=(DrawInfo *) AcquireCriticalMemory(sizeof(*clone_info));
  250. GetDrawInfo(image_info,clone_info);
  251. if (draw_info == (DrawInfo *) NULL)
  252. return(clone_info);
  253. exception=AcquireExceptionInfo();
  254. if (draw_info->primitive != (char *) NULL)
  255. (void) CloneString(&clone_info->primitive,draw_info->primitive);
  256. if (draw_info->geometry != (char *) NULL)
  257. (void) CloneString(&clone_info->geometry,draw_info->geometry);
  258. clone_info->compliance=draw_info->compliance;
  259. clone_info->viewbox=draw_info->viewbox;
  260. clone_info->affine=draw_info->affine;
  261. clone_info->gravity=draw_info->gravity;
  262. clone_info->fill=draw_info->fill;
  263. clone_info->stroke=draw_info->stroke;
  264. clone_info->stroke_width=draw_info->stroke_width;
  265. if (draw_info->fill_pattern != (Image *) NULL)
  266. clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue,
  267. exception);
  268. if (draw_info->stroke_pattern != (Image *) NULL)
  269. clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0,
  270. MagickTrue,exception);
  271. clone_info->stroke_antialias=draw_info->stroke_antialias;
  272. clone_info->text_antialias=draw_info->text_antialias;
  273. clone_info->fill_rule=draw_info->fill_rule;
  274. clone_info->linecap=draw_info->linecap;
  275. clone_info->linejoin=draw_info->linejoin;
  276. clone_info->miterlimit=draw_info->miterlimit;
  277. clone_info->dash_offset=draw_info->dash_offset;
  278. clone_info->decorate=draw_info->decorate;
  279. clone_info->compose=draw_info->compose;
  280. if (draw_info->text != (char *) NULL)
  281. (void) CloneString(&clone_info->text,draw_info->text);
  282. if (draw_info->font != (char *) NULL)
  283. (void) CloneString(&clone_info->font,draw_info->font);
  284. if (draw_info->metrics != (char *) NULL)
  285. (void) CloneString(&clone_info->metrics,draw_info->metrics);
  286. if (draw_info->family != (char *) NULL)
  287. (void) CloneString(&clone_info->family,draw_info->family);
  288. clone_info->style=draw_info->style;
  289. clone_info->stretch=draw_info->stretch;
  290. clone_info->weight=draw_info->weight;
  291. if (draw_info->encoding != (char *) NULL)
  292. (void) CloneString(&clone_info->encoding,draw_info->encoding);
  293. clone_info->pointsize=draw_info->pointsize;
  294. clone_info->kerning=draw_info->kerning;
  295. clone_info->interline_spacing=draw_info->interline_spacing;
  296. clone_info->interword_spacing=draw_info->interword_spacing;
  297. clone_info->direction=draw_info->direction;
  298. if (draw_info->density != (char *) NULL)
  299. (void) CloneString(&clone_info->density,draw_info->density);
  300. clone_info->align=draw_info->align;
  301. clone_info->undercolor=draw_info->undercolor;
  302. clone_info->border_color=draw_info->border_color;
  303. if (draw_info->server_name != (char *) NULL)
  304. (void) CloneString(&clone_info->server_name,draw_info->server_name);
  305. if (draw_info->dash_pattern != (double *) NULL)
  306. {
  307. register ssize_t
  308. x;
  309. for (x=0; fabs(draw_info->dash_pattern[x]) >= MagickEpsilon; x++) ;
  310. clone_info->dash_pattern=(double *) AcquireQuantumMemory((size_t) (2*x+2),
  311. sizeof(*clone_info->dash_pattern));
  312. if (clone_info->dash_pattern == (double *) NULL)
  313. ThrowFatalException(ResourceLimitFatalError,
  314. "UnableToAllocateDashPattern");
  315. (void) memset(clone_info->dash_pattern,0,(size_t) (2*x+2)*
  316. sizeof(*clone_info->dash_pattern));
  317. (void) memcpy(clone_info->dash_pattern,draw_info->dash_pattern,(size_t)
  318. (x+1)*sizeof(*clone_info->dash_pattern));
  319. }
  320. clone_info->gradient=draw_info->gradient;
  321. if (draw_info->gradient.stops != (StopInfo *) NULL)
  322. {
  323. size_t
  324. number_stops;
  325. number_stops=clone_info->gradient.number_stops;
  326. clone_info->gradient.stops=(StopInfo *) AcquireQuantumMemory((size_t)
  327. number_stops,sizeof(*clone_info->gradient.stops));
  328. if (clone_info->gradient.stops == (StopInfo *) NULL)
  329. ThrowFatalException(ResourceLimitFatalError,
  330. "UnableToAllocateDashPattern");
  331. (void) memcpy(clone_info->gradient.stops,draw_info->gradient.stops,
  332. (size_t) number_stops*sizeof(*clone_info->gradient.stops));
  333. }
  334. clone_info->bounds=draw_info->bounds;
  335. clone_info->fill_alpha=draw_info->fill_alpha;
  336. clone_info->stroke_alpha=draw_info->stroke_alpha;
  337. clone_info->element_reference=draw_info->element_reference;
  338. clone_info->clip_path=draw_info->clip_path;
  339. clone_info->clip_units=draw_info->clip_units;
  340. if (draw_info->clip_mask != (char *) NULL)
  341. (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
  342. if (draw_info->clipping_mask != (Image *) NULL)
  343. clone_info->clipping_mask=CloneImage(draw_info->clipping_mask,0,0,
  344. MagickTrue,exception);
  345. if (draw_info->composite_mask != (Image *) NULL)
  346. clone_info->composite_mask=CloneImage(draw_info->composite_mask,0,0,
  347. MagickTrue,exception);
  348. clone_info->render=draw_info->render;
  349. clone_info->debug=IsEventLogging();
  350. exception=DestroyExceptionInfo(exception);
  351. return(clone_info);
  352. }
  353. /*
  354. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  355. % %
  356. % %
  357. % %
  358. + C o n v e r t P a t h T o P o l y g o n %
  359. % %
  360. % %
  361. % %
  362. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  363. %
  364. % ConvertPathToPolygon() converts a path to the more efficient sorted
  365. % rendering form.
  366. %
  367. % The format of the ConvertPathToPolygon method is:
  368. %
  369. % PolygonInfo *ConvertPathToPolygon(const PathInfo *path_info)
  370. %
  371. % A description of each parameter follows:
  372. %
  373. % o Method ConvertPathToPolygon returns the path in a more efficient sorted
  374. % rendering form of type PolygonInfo.
  375. %
  376. % o draw_info: Specifies a pointer to an DrawInfo structure.
  377. %
  378. % o path_info: Specifies a pointer to an PathInfo structure.
  379. %
  380. %
  381. */
  382. #if defined(__cplusplus) || defined(c_plusplus)
  383. extern "C" {
  384. #endif
  385. static int DrawCompareEdges(const void *p_edge,const void *q_edge)
  386. {
  387. #define DrawCompareEdge(p,q) \
  388. { \
  389. if (((p)-(q)) < 0.0) \
  390. return(-1); \
  391. if (((p)-(q)) > 0.0) \
  392. return(1); \
  393. }
  394. register const PointInfo
  395. *p,
  396. *q;
  397. /*
  398. Edge sorting for right-handed coordinate system.
  399. */
  400. p=((const EdgeInfo *) p_edge)->points;
  401. q=((const EdgeInfo *) q_edge)->points;
  402. DrawCompareEdge(p[0].y,q[0].y);
  403. DrawCompareEdge(p[0].x,q[0].x);
  404. DrawCompareEdge((p[1].x-p[0].x)*(q[1].y-q[0].y),(p[1].y-p[0].y)*
  405. (q[1].x-q[0].x));
  406. DrawCompareEdge(p[1].y,q[1].y);
  407. DrawCompareEdge(p[1].x,q[1].x);
  408. return(0);
  409. }
  410. #if defined(__cplusplus) || defined(c_plusplus)
  411. }
  412. #endif
  413. static void LogPolygonInfo(const PolygonInfo *polygon_info)
  414. {
  415. register EdgeInfo
  416. *p;
  417. register ssize_t
  418. i,
  419. j;
  420. (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin active-edge");
  421. p=polygon_info->edges;
  422. for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
  423. {
  424. (void) LogMagickEvent(DrawEvent,GetMagickModule()," edge %.20g:",
  425. (double) i);
  426. (void) LogMagickEvent(DrawEvent,GetMagickModule()," direction: %s",
  427. p->direction != MagickFalse ? "down" : "up");
  428. (void) LogMagickEvent(DrawEvent,GetMagickModule()," ghostline: %s",
  429. p->ghostline != MagickFalse ? "transparent" : "opaque");
  430. (void) LogMagickEvent(DrawEvent,GetMagickModule(),
  431. " bounds: %g,%g - %g,%g",p->bounds.x1,p->bounds.y1,
  432. p->bounds.x2,p->bounds.y2);
  433. for (j=0; j < (ssize_t) p->number_points; j++)
  434. (void) LogMagickEvent(DrawEvent,GetMagickModule()," %g,%g",
  435. p->points[j].x,p->points[j].y);
  436. p++;
  437. }
  438. (void) LogMagickEvent(DrawEvent,GetMagickModule()," end active-edge");
  439. }
  440. static void ReversePoints(PointInfo *points,const size_t number_points)
  441. {
  442. PointInfo
  443. point;
  444. register ssize_t
  445. i;
  446. for (i=0; i < (ssize_t) (number_points >> 1); i++)
  447. {
  448. point=points[i];
  449. points[i]=points[number_points-(i+1)];
  450. points[number_points-(i+1)]=point;
  451. }
  452. }
  453. static PolygonInfo *ConvertPathToPolygon(const PathInfo *path_info)
  454. {
  455. long
  456. direction,
  457. next_direction;
  458. PointInfo
  459. point,
  460. *points;
  461. PolygonInfo
  462. *polygon_info;
  463. SegmentInfo
  464. bounds;
  465. register ssize_t
  466. i,
  467. n;
  468. MagickBooleanType
  469. ghostline;
  470. size_t
  471. edge,
  472. number_edges,
  473. number_points;
  474. /*
  475. Convert a path to the more efficient sorted rendering form.
  476. */
  477. polygon_info=(PolygonInfo *) AcquireMagickMemory(sizeof(*polygon_info));
  478. if (polygon_info == (PolygonInfo *) NULL)
  479. return((PolygonInfo *) NULL);
  480. number_edges=16;
  481. polygon_info->edges=(EdgeInfo *) AcquireQuantumMemory(number_edges,
  482. sizeof(*polygon_info->edges));
  483. if (polygon_info->edges == (EdgeInfo *) NULL)
  484. return((PolygonInfo *) NULL);
  485. (void) memset(polygon_info->edges,0,number_edges*
  486. sizeof(*polygon_info->edges));
  487. direction=0;
  488. edge=0;
  489. ghostline=MagickFalse;
  490. n=0;
  491. number_points=0;
  492. points=(PointInfo *) NULL;
  493. (void) memset(&point,0,sizeof(point));
  494. (void) memset(&bounds,0,sizeof(bounds));
  495. polygon_info->edges[edge].number_points=(size_t) n;
  496. polygon_info->edges[edge].scanline=0.0;
  497. polygon_info->edges[edge].highwater=0;
  498. polygon_info->edges[edge].ghostline=ghostline;
  499. polygon_info->edges[edge].direction=(ssize_t) direction;
  500. polygon_info->edges[edge].points=points;
  501. polygon_info->edges[edge].bounds=bounds;
  502. polygon_info->number_edges=0;
  503. for (i=0; path_info[i].code != EndCode; i++)
  504. {
  505. if ((path_info[i].code == MoveToCode) || (path_info[i].code == OpenCode) ||
  506. (path_info[i].code == GhostlineCode))
  507. {
  508. /*
  509. Move to.
  510. */
  511. if ((points != (PointInfo *) NULL) && (n >= 2))
  512. {
  513. if (edge == number_edges)
  514. {
  515. number_edges<<=1;
  516. polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
  517. polygon_info->edges,(size_t) number_edges,
  518. sizeof(*polygon_info->edges));
  519. if (polygon_info->edges == (EdgeInfo *) NULL)
  520. return((PolygonInfo *) NULL);
  521. }
  522. polygon_info->edges[edge].number_points=(size_t) n;
  523. polygon_info->edges[edge].scanline=(-1.0);
  524. polygon_info->edges[edge].highwater=0;
  525. polygon_info->edges[edge].ghostline=ghostline;
  526. polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
  527. if (direction < 0)
  528. ReversePoints(points,(size_t) n);
  529. polygon_info->edges[edge].points=points;
  530. polygon_info->edges[edge].bounds=bounds;
  531. polygon_info->edges[edge].bounds.y1=points[0].y;
  532. polygon_info->edges[edge].bounds.y2=points[n-1].y;
  533. points=(PointInfo *) NULL;
  534. ghostline=MagickFalse;
  535. edge++;
  536. }
  537. if (points == (PointInfo *) NULL)
  538. {
  539. number_points=16;
  540. points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
  541. sizeof(*points));
  542. if (points == (PointInfo *) NULL)
  543. return((PolygonInfo *) NULL);
  544. }
  545. ghostline=path_info[i].code == GhostlineCode ? MagickTrue : MagickFalse;
  546. point=path_info[i].point;
  547. points[0]=point;
  548. bounds.x1=point.x;
  549. bounds.x2=point.x;
  550. direction=0;
  551. n=1;
  552. continue;
  553. }
  554. /*
  555. Line to.
  556. */
  557. next_direction=((path_info[i].point.y > point.y) ||
  558. ((fabs(path_info[i].point.y-point.y) < MagickEpsilon) &&
  559. (path_info[i].point.x > point.x))) ? 1 : -1;
  560. if ((points != (PointInfo *) NULL) && (direction != 0) &&
  561. (direction != next_direction))
  562. {
  563. /*
  564. New edge.
  565. */
  566. point=points[n-1];
  567. if (edge == number_edges)
  568. {
  569. number_edges<<=1;
  570. polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
  571. polygon_info->edges,(size_t) number_edges,
  572. sizeof(*polygon_info->edges));
  573. if (polygon_info->edges == (EdgeInfo *) NULL)
  574. return((PolygonInfo *) NULL);
  575. }
  576. polygon_info->edges[edge].number_points=(size_t) n;
  577. polygon_info->edges[edge].scanline=(-1.0);
  578. polygon_info->edges[edge].highwater=0;
  579. polygon_info->edges[edge].ghostline=ghostline;
  580. polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
  581. if (direction < 0)
  582. ReversePoints(points,(size_t) n);
  583. polygon_info->edges[edge].points=points;
  584. polygon_info->edges[edge].bounds=bounds;
  585. polygon_info->edges[edge].bounds.y1=points[0].y;
  586. polygon_info->edges[edge].bounds.y2=points[n-1].y;
  587. number_points=16;
  588. points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
  589. sizeof(*points));
  590. if (points == (PointInfo *) NULL)
  591. return((PolygonInfo *) NULL);
  592. n=1;
  593. ghostline=MagickFalse;
  594. points[0]=point;
  595. bounds.x1=point.x;
  596. bounds.x2=point.x;
  597. edge++;
  598. }
  599. direction=next_direction;
  600. if (points == (PointInfo *) NULL)
  601. continue;
  602. if (n == (ssize_t) number_points)
  603. {
  604. number_points<<=1;
  605. points=(PointInfo *) ResizeQuantumMemory(points,(size_t) number_points,
  606. sizeof(*points));
  607. if (points == (PointInfo *) NULL)
  608. return((PolygonInfo *) NULL);
  609. }
  610. point=path_info[i].point;
  611. points[n]=point;
  612. if (point.x < bounds.x1)
  613. bounds.x1=point.x;
  614. if (point.x > bounds.x2)
  615. bounds.x2=point.x;
  616. n++;
  617. }
  618. if (points != (PointInfo *) NULL)
  619. {
  620. if (n < 2)
  621. points=(PointInfo *) RelinquishMagickMemory(points);
  622. else
  623. {
  624. if (edge == number_edges)
  625. {
  626. number_edges<<=1;
  627. polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
  628. polygon_info->edges,(size_t) number_edges,
  629. sizeof(*polygon_info->edges));
  630. if (polygon_info->edges == (EdgeInfo *) NULL)
  631. return((PolygonInfo *) NULL);
  632. }
  633. polygon_info->edges[edge].number_points=(size_t) n;
  634. polygon_info->edges[edge].scanline=(-1.0);
  635. polygon_info->edges[edge].highwater=0;
  636. polygon_info->edges[edge].ghostline=ghostline;
  637. polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
  638. if (direction < 0)
  639. ReversePoints(points,(size_t) n);
  640. polygon_info->edges[edge].points=points;
  641. polygon_info->edges[edge].bounds=bounds;
  642. polygon_info->edges[edge].bounds.y1=points[0].y;
  643. polygon_info->edges[edge].bounds.y2=points[n-1].y;
  644. ghostline=MagickFalse;
  645. edge++;
  646. }
  647. }
  648. polygon_info->number_edges=edge;
  649. qsort(polygon_info->edges,(size_t) polygon_info->number_edges,
  650. sizeof(*polygon_info->edges),DrawCompareEdges);
  651. if (IsEventLogging() != MagickFalse)
  652. LogPolygonInfo(polygon_info);
  653. return(polygon_info);
  654. }
  655. /*
  656. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  657. % %
  658. % %
  659. % %
  660. + C o n v e r t P r i m i t i v e T o P a t h %
  661. % %
  662. % %
  663. % %
  664. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  665. %
  666. % ConvertPrimitiveToPath() converts a PrimitiveInfo structure into a vector
  667. % path structure.
  668. %
  669. % The format of the ConvertPrimitiveToPath method is:
  670. %
  671. % PathInfo *ConvertPrimitiveToPath(const DrawInfo *draw_info,
  672. % const PrimitiveInfo *primitive_info)
  673. %
  674. % A description of each parameter follows:
  675. %
  676. % o Method ConvertPrimitiveToPath returns a vector path structure of type
  677. % PathInfo.
  678. %
  679. % o draw_info: a structure of type DrawInfo.
  680. %
  681. % o primitive_info: Specifies a pointer to an PrimitiveInfo structure.
  682. %
  683. %
  684. */
  685. static void LogPathInfo(const PathInfo *path_info)
  686. {
  687. register const PathInfo
  688. *p;
  689. (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin vector-path");
  690. for (p=path_info; p->code != EndCode; p++)
  691. (void) LogMagickEvent(DrawEvent,GetMagickModule(),
  692. " %g,%g %s",p->point.x,p->point.y,p->code == GhostlineCode ?
  693. "moveto ghostline" : p->code == OpenCode ? "moveto open" :
  694. p->code == MoveToCode ? "moveto" : p->code == LineToCode ? "lineto" :
  695. "?");
  696. (void) LogMagickEvent(DrawEvent,GetMagickModule()," end vector-path");
  697. }
  698. static PathInfo *ConvertPrimitiveToPath(const PrimitiveInfo *primitive_info)
  699. {
  700. MagickBooleanType
  701. closed_subpath;
  702. PathInfo
  703. *path_info;
  704. PathInfoCode
  705. code;
  706. PointInfo
  707. p,
  708. q;
  709. register ssize_t
  710. i,
  711. n;
  712. ssize_t
  713. coordinates,
  714. start;
  715. /*
  716. Converts a PrimitiveInfo structure into a vector path structure.
  717. */
  718. switch (primitive_info->primitive)
  719. {
  720. case AlphaPrimitive:
  721. case ColorPrimitive:
  722. case ImagePrimitive:
  723. case PointPrimitive:
  724. case TextPrimitive:
  725. return((PathInfo *) NULL);
  726. default:
  727. break;
  728. }
  729. for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
  730. path_info=(PathInfo *) AcquireQuantumMemory((size_t) (3UL*i+1UL),
  731. sizeof(*path_info));
  732. if (path_info == (PathInfo *) NULL)
  733. return((PathInfo *) NULL);
  734. coordinates=0;
  735. closed_subpath=MagickFalse;
  736. n=0;
  737. p.x=(-1.0);
  738. p.y=(-1.0);
  739. q.x=(-1.0);
  740. q.y=(-1.0);
  741. start=0;
  742. for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
  743. {
  744. code=LineToCode;
  745. if (coordinates <= 0)
  746. {
  747. /*
  748. New subpath.
  749. */
  750. coordinates=(ssize_t) primitive_info[i].coordinates;
  751. p=primitive_info[i].point;
  752. start=n;
  753. code=MoveToCode;
  754. closed_subpath=primitive_info[i].closed_subpath;
  755. }
  756. coordinates--;
  757. if ((code == MoveToCode) || (coordinates <= 0) ||
  758. (fabs(q.x-primitive_info[i].point.x) >= MagickEpsilon) ||
  759. (fabs(q.y-primitive_info[i].point.y) >= MagickEpsilon))
  760. {
  761. /*
  762. Eliminate duplicate points.
  763. */
  764. path_info[n].code=code;
  765. path_info[n].point=primitive_info[i].point;
  766. q=primitive_info[i].point;
  767. n++;
  768. }
  769. if (coordinates > 0)
  770. continue; /* next point in current subpath */
  771. if (closed_subpath != MagickFalse)
  772. {
  773. closed_subpath=MagickFalse;
  774. continue;
  775. }
  776. /*
  777. Mark the p point as open if the subpath is not closed.
  778. */
  779. path_info[start].code=OpenCode;
  780. path_info[n].code=GhostlineCode;
  781. path_info[n].point=primitive_info[i].point;
  782. n++;
  783. path_info[n].code=LineToCode;
  784. path_info[n].point=p;
  785. n++;
  786. }
  787. path_info[n].code=EndCode;
  788. path_info[n].point.x=0.0;
  789. path_info[n].point.y=0.0;
  790. if (IsEventLogging() != MagickFalse)
  791. LogPathInfo(path_info);
  792. path_info=(PathInfo *) ResizeQuantumMemory(path_info,(size_t) (n+1),
  793. sizeof(*path_info));
  794. return(path_info);
  795. }
  796. /*
  797. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  798. % %
  799. % %
  800. % %
  801. % D e s t r o y D r a w I n f o %
  802. % %
  803. % %
  804. % %
  805. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  806. %
  807. % DestroyDrawInfo() deallocates memory associated with an DrawInfo structure.
  808. %
  809. % The format of the DestroyDrawInfo method is:
  810. %
  811. % DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
  812. %
  813. % A description of each parameter follows:
  814. %
  815. % o draw_info: the draw info.
  816. %
  817. */
  818. MagickExport DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
  819. {
  820. assert(draw_info != (DrawInfo *) NULL);
  821. if (draw_info->debug != MagickFalse)
  822. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  823. assert(draw_info->signature == MagickCoreSignature);
  824. if (draw_info->primitive != (char *) NULL)
  825. draw_info->primitive=DestroyString(draw_info->primitive);
  826. if (draw_info->text != (char *) NULL)
  827. draw_info->text=DestroyString(draw_info->text);
  828. if (draw_info->geometry != (char *) NULL)
  829. draw_info->geometry=DestroyString(draw_info->geometry);
  830. if (draw_info->fill_pattern != (Image *) NULL)
  831. draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
  832. if (draw_info->stroke_pattern != (Image *) NULL)
  833. draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
  834. if (draw_info->font != (char *) NULL)
  835. draw_info->font=DestroyString(draw_info->font);
  836. if (draw_info->metrics != (char *) NULL)
  837. draw_info->metrics=DestroyString(draw_info->metrics);
  838. if (draw_info->family != (char *) NULL)
  839. draw_info->family=DestroyString(draw_info->family);
  840. if (draw_info->encoding != (char *) NULL)
  841. draw_info->encoding=DestroyString(draw_info->encoding);
  842. if (draw_info->density != (char *) NULL)
  843. draw_info->density=DestroyString(draw_info->density);
  844. if (draw_info->server_name != (char *) NULL)
  845. draw_info->server_name=(char *)
  846. RelinquishMagickMemory(draw_info->server_name);
  847. if (draw_info->dash_pattern != (double *) NULL)
  848. draw_info->dash_pattern=(double *) RelinquishMagickMemory(
  849. draw_info->dash_pattern);
  850. if (draw_info->gradient.stops != (StopInfo *) NULL)
  851. draw_info->gradient.stops=(StopInfo *) RelinquishMagickMemory(
  852. draw_info->gradient.stops);
  853. if (draw_info->clip_mask != (char *) NULL)
  854. draw_info->clip_mask=DestroyString(draw_info->clip_mask);
  855. if (draw_info->clipping_mask != (Image *) NULL)
  856. draw_info->clipping_mask=DestroyImage(draw_info->clipping_mask);
  857. if (draw_info->composite_mask != (Image *) NULL)
  858. draw_info->composite_mask=DestroyImage(draw_info->composite_mask);
  859. draw_info->signature=(~MagickCoreSignature);
  860. draw_info=(DrawInfo *) RelinquishMagickMemory(draw_info);
  861. return(draw_info);
  862. }
  863. /*
  864. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  865. % %
  866. % %
  867. % %
  868. + D e s t r o y E d g e %
  869. % %
  870. % %
  871. % %
  872. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  873. %
  874. % DestroyEdge() destroys the specified polygon edge.
  875. %
  876. % The format of the DestroyEdge method is:
  877. %
  878. % ssize_t DestroyEdge(PolygonInfo *polygon_info,const int edge)
  879. %
  880. % A description of each parameter follows:
  881. %
  882. % o polygon_info: Specifies a pointer to an PolygonInfo structure.
  883. %
  884. % o edge: the polygon edge number to destroy.
  885. %
  886. */
  887. static size_t DestroyEdge(PolygonInfo *polygon_info,
  888. const size_t edge)
  889. {
  890. assert(edge < polygon_info->number_edges);
  891. polygon_info->edges[edge].points=(PointInfo *) RelinquishMagickMemory(
  892. polygon_info->edges[edge].points);
  893. polygon_info->number_edges--;
  894. if (edge < polygon_info->number_edges)
  895. (void) memmove(polygon_info->edges+edge,polygon_info->edges+edge+1,
  896. (size_t) (polygon_info->number_edges-edge)*sizeof(*polygon_info->edges));
  897. return(polygon_info->number_edges);
  898. }
  899. /*
  900. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  901. % %
  902. % %
  903. % %
  904. + D e s t r o y P o l y g o n I n f o %
  905. % %
  906. % %
  907. % %
  908. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  909. %
  910. % DestroyPolygonInfo() destroys the PolygonInfo data structure.
  911. %
  912. % The format of the DestroyPolygonInfo method is:
  913. %
  914. % PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
  915. %
  916. % A description of each parameter follows:
  917. %
  918. % o polygon_info: Specifies a pointer to an PolygonInfo structure.
  919. %
  920. */
  921. static PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
  922. {
  923. register ssize_t
  924. i;
  925. for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
  926. polygon_info->edges[i].points=(PointInfo *)
  927. RelinquishMagickMemory(polygon_info->edges[i].points);
  928. polygon_info->edges=(EdgeInfo *) RelinquishMagickMemory(polygon_info->edges);
  929. return((PolygonInfo *) RelinquishMagickMemory(polygon_info));
  930. }
  931. /*
  932. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  933. % %
  934. % %
  935. % %
  936. % D r a w A f f i n e I m a g e %
  937. % %
  938. % %
  939. % %
  940. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  941. %
  942. % DrawAffineImage() composites the source over the destination image as
  943. % dictated by the affine transform.
  944. %
  945. % The format of the DrawAffineImage method is:
  946. %
  947. % MagickBooleanType DrawAffineImage(Image *image,const Image *source,
  948. % const AffineMatrix *affine,ExceptionInfo *exception)
  949. %
  950. % A description of each parameter follows:
  951. %
  952. % o image: the image.
  953. %
  954. % o source: the source image.
  955. %
  956. % o affine: the affine transform.
  957. %
  958. % o exception: return any errors or warnings in this structure.
  959. %
  960. */
  961. static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
  962. const double y,const SegmentInfo *edge)
  963. {
  964. double
  965. intercept,
  966. z;
  967. register double
  968. x;
  969. SegmentInfo
  970. inverse_edge;
  971. /*
  972. Determine left and right edges.
  973. */
  974. inverse_edge.x1=edge->x1;
  975. inverse_edge.y1=edge->y1;
  976. inverse_edge.x2=edge->x2;
  977. inverse_edge.y2=edge->y2;
  978. z=affine->ry*y+affine->tx;
  979. if (affine->sx >= MagickEpsilon)
  980. {
  981. intercept=(-z/affine->sx);
  982. x=intercept;
  983. if (x > inverse_edge.x1)
  984. inverse_edge.x1=x;
  985. intercept=(-z+(double) image->columns)/affine->sx;
  986. x=intercept;
  987. if (x < inverse_edge.x2)
  988. inverse_edge.x2=x;
  989. }
  990. else
  991. if (affine->sx < -MagickEpsilon)
  992. {
  993. intercept=(-z+(double) image->columns)/affine->sx;
  994. x=intercept;
  995. if (x > inverse_edge.x1)
  996. inverse_edge.x1=x;
  997. intercept=(-z/affine->sx);
  998. x=intercept;
  999. if (x < inverse_edge.x2)
  1000. inverse_edge.x2=x;
  1001. }
  1002. else
  1003. if ((z < 0.0) || ((size_t) floor(z+0.5) >= image->columns))
  1004. {
  1005. inverse_edge.x2=edge->x1;
  1006. return(inverse_edge);
  1007. }
  1008. /*
  1009. Determine top and bottom edges.
  1010. */
  1011. z=affine->sy*y+affine->ty;
  1012. if (affine->rx >= MagickEpsilon)
  1013. {
  1014. intercept=(-z/affine->rx);
  1015. x=intercept;
  1016. if (x > inverse_edge.x1)
  1017. inverse_edge.x1=x;
  1018. intercept=(-z+(double) image->rows)/affine->rx;
  1019. x=intercept;
  1020. if (x < inverse_edge.x2)
  1021. inverse_edge.x2=x;
  1022. }
  1023. else
  1024. if (affine->rx < -MagickEpsilon)
  1025. {
  1026. intercept=(-z+(double) image->rows)/affine->rx;
  1027. x=intercept;
  1028. if (x > inverse_edge.x1)
  1029. inverse_edge.x1=x;
  1030. intercept=(-z/affine->rx);
  1031. x=intercept;
  1032. if (x < inverse_edge.x2)
  1033. inverse_edge.x2=x;
  1034. }
  1035. else
  1036. if ((z < 0.0) || ((size_t) floor(z+0.5) >= image->rows))
  1037. {
  1038. inverse_edge.x2=edge->x2;
  1039. return(inverse_edge);
  1040. }
  1041. return(inverse_edge);
  1042. }
  1043. static AffineMatrix InverseAffineMatrix(const AffineMatrix *affine)
  1044. {
  1045. AffineMatrix
  1046. inverse_affine;
  1047. double
  1048. determinant;
  1049. determinant=PerceptibleReciprocal(affine->sx*affine->sy-affine->rx*
  1050. affine->ry);
  1051. inverse_affine.sx=determinant*affine->sy;
  1052. inverse_affine.rx=determinant*(-affine->rx);
  1053. inverse_affine.ry=determinant*(-affine->ry);
  1054. inverse_affine.sy=determinant*affine->sx;
  1055. inverse_affine.tx=(-affine->tx)*inverse_affine.sx-affine->ty*
  1056. inverse_affine.ry;
  1057. inverse_affine.ty=(-affine->tx)*inverse_affine.rx-affine->ty*
  1058. inverse_affine.sy;
  1059. return(inverse_affine);
  1060. }
  1061. MagickExport MagickBooleanType DrawAffineImage(Image *image,
  1062. const Image *source,const AffineMatrix *affine,ExceptionInfo *exception)
  1063. {
  1064. AffineMatrix
  1065. inverse_affine;
  1066. CacheView
  1067. *image_view,
  1068. *source_view;
  1069. MagickBooleanType
  1070. status;
  1071. PixelInfo
  1072. zero;
  1073. PointInfo
  1074. extent[4],
  1075. min,
  1076. max;
  1077. register ssize_t
  1078. i;
  1079. SegmentInfo
  1080. edge;
  1081. ssize_t
  1082. start,
  1083. stop,
  1084. y;
  1085. /*
  1086. Determine bounding box.
  1087. */
  1088. assert(image != (Image *) NULL);
  1089. assert(image->signature == MagickCoreSignature);
  1090. if (image->debug != MagickFalse)
  1091. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  1092. assert(source != (const Image *) NULL);
  1093. assert(source->signature == MagickCoreSignature);
  1094. assert(affine != (AffineMatrix *) NULL);
  1095. extent[0].x=0.0;
  1096. extent[0].y=0.0;
  1097. extent[1].x=(double) source->columns-1.0;
  1098. extent[1].y=0.0;
  1099. extent[2].x=(double) source->columns-1.0;
  1100. extent[2].y=(double) source->rows-1.0;
  1101. extent[3].x=0.0;
  1102. extent[3].y=(double) source->rows-1.0;
  1103. for (i=0; i < 4; i++)
  1104. {
  1105. PointInfo
  1106. point;
  1107. point=extent[i];
  1108. extent[i].x=point.x*affine->sx+point.y*affine->ry+affine->tx;
  1109. extent[i].y=point.x*affine->rx+point.y*affine->sy+affine->ty;
  1110. }
  1111. min=extent[0];
  1112. max=extent[0];
  1113. for (i=1; i < 4; i++)
  1114. {
  1115. if (min.x > extent[i].x)
  1116. min.x=extent[i].x;
  1117. if (min.y > extent[i].y)
  1118. min.y=extent[i].y;
  1119. if (max.x < extent[i].x)
  1120. max.x=extent[i].x;
  1121. if (max.y < extent[i].y)
  1122. max.y=extent[i].y;
  1123. }
  1124. /*
  1125. Affine transform image.
  1126. */
  1127. if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
  1128. return(MagickFalse);
  1129. status=MagickTrue;
  1130. edge.x1=MagickMax(min.x,0.0);
  1131. edge.y1=MagickMax(min.y,0.0);
  1132. edge.x2=MagickMin(max.x,(double) image->columns-1.0);
  1133. edge.y2=MagickMin(max.y,(double) image->rows-1.0);
  1134. inverse_affine=InverseAffineMatrix(affine);
  1135. GetPixelInfo(image,&zero);
  1136. start=(ssize_t) ceil(edge.y1-0.5);
  1137. stop=(ssize_t) floor(edge.y2+0.5);
  1138. source_view=AcquireVirtualCacheView(source,exception);
  1139. image_view=AcquireAuthenticCacheView(image,exception);
  1140. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  1141. #pragma omp parallel for schedule(static) shared(status) \
  1142. magick_number_threads(source,image,stop-start,1)
  1143. #endif
  1144. for (y=start; y <= stop; y++)
  1145. {
  1146. PixelInfo
  1147. composite,
  1148. pixel;
  1149. PointInfo
  1150. point;
  1151. register ssize_t
  1152. x;
  1153. register Quantum
  1154. *magick_restrict q;
  1155. SegmentInfo
  1156. inverse_edge;
  1157. ssize_t
  1158. x_offset;
  1159. inverse_edge=AffineEdge(source,&inverse_affine,(double) y,&edge);
  1160. if (inverse_edge.x2 < inverse_edge.x1)
  1161. continue;
  1162. q=GetCacheViewAuthenticPixels(image_view,(ssize_t) ceil(inverse_edge.x1-
  1163. 0.5),y,(size_t) (floor(inverse_edge.x2+0.5)-ceil(inverse_edge.x1-0.5)+1),
  1164. 1,exception);
  1165. if (q == (Quantum *) NULL)
  1166. continue;
  1167. pixel=zero;
  1168. composite=zero;
  1169. x_offset=0;
  1170. for (x=(ssize_t) ceil(inverse_edge.x1-0.5); x <= (ssize_t) floor(inverse_edge.x2+0.5); x++)
  1171. {
  1172. point.x=(double) x*inverse_affine.sx+y*inverse_affine.ry+
  1173. inverse_affine.tx;
  1174. point.y=(double) x*inverse_affine.rx+y*inverse_affine.sy+
  1175. inverse_affine.ty;
  1176. status=InterpolatePixelInfo(source,source_view,UndefinedInterpolatePixel,
  1177. point.x,point.y,&pixel,exception);
  1178. if (status == MagickFalse)
  1179. break;
  1180. GetPixelInfoPixel(image,q,&composite);
  1181. CompositePixelInfoOver(&pixel,pixel.alpha,&composite,composite.alpha,
  1182. &composite);
  1183. SetPixelViaPixelInfo(image,&composite,q);
  1184. x_offset++;
  1185. q+=GetPixelChannels(image);
  1186. }
  1187. if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
  1188. status=MagickFalse;
  1189. }
  1190. source_view=DestroyCacheView(source_view);
  1191. image_view=DestroyCacheView(image_view);
  1192. return(status);
  1193. }
  1194. /*
  1195. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1196. % %
  1197. % %
  1198. % %
  1199. + D r a w B o u n d i n g R e c t a n g l e s %
  1200. % %
  1201. % %
  1202. % %
  1203. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1204. %
  1205. % DrawBoundingRectangles() draws the bounding rectangles on the image. This
  1206. % is only useful for developers debugging the rendering algorithm.
  1207. %
  1208. % The format of the DrawBoundingRectangles method is:
  1209. %
  1210. % MagickBooleanType DrawBoundingRectangles(Image *image,
  1211. % const DrawInfo *draw_info,PolygonInfo *polygon_info,
  1212. % ExceptionInfo *exception)
  1213. %
  1214. % A description of each parameter follows:
  1215. %
  1216. % o image: the image.
  1217. %
  1218. % o draw_info: the draw info.
  1219. %
  1220. % o polygon_info: Specifies a pointer to a PolygonInfo structure.
  1221. %
  1222. % o exception: return any errors or warnings in this structure.
  1223. %
  1224. */
  1225. static inline double SaneStrokeWidth(const Image *image,
  1226. const DrawInfo *draw_info)
  1227. {
  1228. return(MagickMin((double) draw_info->stroke_width,
  1229. (2.0*sqrt(2.0)+MagickEpsilon)*MagickMax(image->columns,image->rows)));
  1230. }
  1231. static MagickBooleanType DrawBoundingRectangles(Image *image,
  1232. const DrawInfo *draw_info,const PolygonInfo *polygon_info,
  1233. ExceptionInfo *exception)
  1234. {
  1235. double
  1236. mid;
  1237. DrawInfo
  1238. *clone_info;
  1239. MagickStatusType
  1240. status;
  1241. PointInfo
  1242. end,
  1243. resolution,
  1244. start;
  1245. PrimitiveInfo
  1246. primitive_info[6];
  1247. register ssize_t
  1248. i;
  1249. SegmentInfo
  1250. bounds;
  1251. ssize_t
  1252. coordinates;
  1253. (void) memset(primitive_info,0,sizeof(primitive_info));
  1254. clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
  1255. status=QueryColorCompliance("#000F",AllCompliance,&clone_info->fill,
  1256. exception);
  1257. if (status == MagickFalse)
  1258. {
  1259. clone_info=DestroyDrawInfo(clone_info);
  1260. return(MagickFalse);
  1261. }
  1262. resolution.x=96.0;
  1263. resolution.y=96.0;
  1264. if (clone_info->density != (char *) NULL)
  1265. {
  1266. GeometryInfo
  1267. geometry_info;
  1268. MagickStatusType
  1269. flags;
  1270. flags=ParseGeometry(clone_info->density,&geometry_info);
  1271. resolution.x=geometry_info.rho;
  1272. resolution.y=geometry_info.sigma;
  1273. if ((flags & SigmaValue) == MagickFalse)
  1274. resolution.y=resolution.x;
  1275. }
  1276. mid=(resolution.x/96.0)*ExpandAffine(&clone_info->affine)*
  1277. SaneStrokeWidth(image,clone_info)/2.0;
  1278. bounds.x1=0.0;
  1279. bounds.y1=0.0;
  1280. bounds.x2=0.0;
  1281. bounds.y2=0.0;
  1282. if (polygon_info != (PolygonInfo *) NULL)
  1283. {
  1284. bounds=polygon_info->edges[0].bounds;
  1285. for (i=1; i < (ssize_t) polygon_info->number_edges; i++)
  1286. {
  1287. if (polygon_info->edges[i].bounds.x1 < (double) bounds.x1)
  1288. bounds.x1=polygon_info->edges[i].bounds.x1;
  1289. if (polygon_info->edges[i].bounds.y1 < (double) bounds.y1)
  1290. bounds.y1=polygon_info->edges[i].bounds.y1;
  1291. if (polygon_info->edges[i].bounds.x2 > (double) bounds.x2)
  1292. bounds.x2=polygon_info->edges[i].bounds.x2;
  1293. if (polygon_info->edges[i].bounds.y2 > (double) bounds.y2)
  1294. bounds.y2=polygon_info->edges[i].bounds.y2;
  1295. }
  1296. bounds.x1-=mid;
  1297. bounds.x1=bounds.x1 < 0.0 ? 0.0 : bounds.x1 >= (double)
  1298. image->columns ? (double) image->columns-1 : bounds.x1;
  1299. bounds.y1-=mid;
  1300. bounds.y1=bounds.y1 < 0.0 ? 0.0 : bounds.y1 >= (double)
  1301. image->rows ? (double) image->rows-1 : bounds.y1;
  1302. bounds.x2+=mid;
  1303. bounds.x2=bounds.x2 < 0.0 ? 0.0 : bounds.x2 >= (double)
  1304. image->columns ? (double) image->columns-1 : bounds.x2;
  1305. bounds.y2+=mid;
  1306. bounds.y2=bounds.y2 < 0.0 ? 0.0 : bounds.y2 >= (double)
  1307. image->rows ? (double) image->rows-1 : bounds.y2;
  1308. for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
  1309. {
  1310. if (polygon_info->edges[i].direction != 0)
  1311. status=QueryColorCompliance("#f00",AllCompliance,&clone_info->stroke,
  1312. exception);
  1313. else
  1314. status=QueryColorCompliance("#0f0",AllCompliance,&clone_info->stroke,
  1315. exception);
  1316. if (status == MagickFalse)
  1317. break;
  1318. start.x=(double) (polygon_info->edges[i].bounds.x1-mid);
  1319. start.y=(double) (polygon_info->edges[i].bounds.y1-mid);
  1320. end.x=(double) (polygon_info->edges[i].bounds.x2+mid);
  1321. end.y=(double) (polygon_info->edges[i].bounds.y2+mid);
  1322. primitive_info[0].primitive=RectanglePrimitive;
  1323. status&=TraceRectangle(primitive_info,start,end);
  1324. primitive_info[0].method=ReplaceMethod;
  1325. coordinates=(ssize_t) primitive_info[0].coordinates;
  1326. primitive_info[coordinates].primitive=UndefinedPrimitive;
  1327. status=DrawPrimitive(image,clone_info,primitive_info,exception);
  1328. if (status == MagickFalse)
  1329. break;
  1330. }
  1331. if (i < (ssize_t) polygon_info->number_edges)
  1332. {
  1333. clone_info=DestroyDrawInfo(clone_info);
  1334. return(status == 0 ? MagickFalse : MagickTrue);
  1335. }
  1336. }
  1337. status=QueryColorCompliance("#00f",AllCompliance,&clone_info->stroke,
  1338. exception);
  1339. if (status == MagickFalse)
  1340. {
  1341. clone_info=DestroyDrawInfo(clone_info);
  1342. return(MagickFalse);
  1343. }
  1344. start.x=(double) (bounds.x1-mid);
  1345. start.y=(double) (bounds.y1-mid);
  1346. end.x=(double) (bounds.x2+mid);
  1347. end.y=(double) (bounds.y2+mid);
  1348. primitive_info[0].primitive=RectanglePrimitive;
  1349. status&=TraceRectangle(primitive_info,start,end);
  1350. primitive_info[0].method=ReplaceMethod;
  1351. coordinates=(ssize_t) primitive_info[0].coordinates;
  1352. primitive_info[coordinates].primitive=UndefinedPrimitive;
  1353. status=DrawPrimitive(image,clone_info,primitive_info,exception);
  1354. clone_info=DestroyDrawInfo(clone_info);
  1355. return(status == 0 ? MagickFalse : MagickTrue);
  1356. }
  1357. /*
  1358. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1359. % %
  1360. % %
  1361. % %
  1362. % D r a w C l i p P a t h %
  1363. % %
  1364. % %
  1365. % %
  1366. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1367. %
  1368. % DrawClipPath() draws the clip path on the image mask.
  1369. %
  1370. % The format of the DrawClipPath method is:
  1371. %
  1372. % MagickBooleanType DrawClipPath(Image *image,const DrawInfo *draw_info,
  1373. % const char *id,ExceptionInfo *exception)
  1374. %
  1375. % A description of each parameter follows:
  1376. %
  1377. % o image: the image.
  1378. %
  1379. % o draw_info: the draw info.
  1380. %
  1381. % o id: the clip path id.…

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