00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "magick/studio.h"
00049 #include "magick/annotate.h"
00050 #include "magick/artifact.h"
00051 #include "magick/blob.h"
00052 #include "magick/cache.h"
00053 #include "magick/cache-view.h"
00054 #include "magick/color.h"
00055 #include "magick/composite.h"
00056 #include "magick/composite-private.h"
00057 #include "magick/constitute.h"
00058 #include "magick/draw.h"
00059 #include "magick/draw-private.h"
00060 #include "magick/enhance.h"
00061 #include "magick/exception.h"
00062 #include "magick/exception-private.h"
00063 #include "magick/gem.h"
00064 #include "magick/geometry.h"
00065 #include "magick/image-private.h"
00066 #include "magick/list.h"
00067 #include "magick/log.h"
00068 #include "magick/monitor.h"
00069 #include "magick/monitor-private.h"
00070 #include "magick/option.h"
00071 #include "magick/paint.h"
00072 #include "magick/pixel-private.h"
00073 #include "magick/property.h"
00074 #include "magick/resample.h"
00075 #include "magick/resample-private.h"
00076 #include "magick/string_.h"
00077 #include "magick/thread-private.h"
00078 #include "magick/token.h"
00079 #include "magick/transform.h"
00080 #include "magick/utility.h"
00081
00082
00083
00084
00085 #define BezierQuantum 200
00086
00087
00088
00089
00090 typedef struct _EdgeInfo
00091 {
00092 SegmentInfo
00093 bounds;
00094
00095 MagickRealType
00096 scanline;
00097
00098 PointInfo
00099 *points;
00100
00101 unsigned long
00102 number_points;
00103
00104 long
00105 direction;
00106
00107 MagickBooleanType
00108 ghostline;
00109
00110 unsigned long
00111 highwater;
00112 } EdgeInfo;
00113
00114 typedef struct _ElementInfo
00115 {
00116 MagickRealType
00117 cx,
00118 cy,
00119 major,
00120 minor,
00121 angle;
00122 } ElementInfo;
00123
00124 typedef struct _PolygonInfo
00125 {
00126 EdgeInfo
00127 *edges;
00128
00129 unsigned long
00130 number_edges;
00131 } PolygonInfo;
00132
00133 typedef enum
00134 {
00135 MoveToCode,
00136 OpenCode,
00137 GhostlineCode,
00138 LineToCode,
00139 EndCode
00140 } PathInfoCode;
00141
00142 typedef struct _PathInfo
00143 {
00144 PointInfo
00145 point;
00146
00147 PathInfoCode
00148 code;
00149 } PathInfo;
00150
00151
00152
00153
00154 static MagickBooleanType
00155 DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *);
00156
00157 static PrimitiveInfo
00158 *TraceStrokePolygon(const DrawInfo *,const PrimitiveInfo *);
00159
00160 static unsigned long
00161 TracePath(PrimitiveInfo *,const char *);
00162
00163 static void
00164 TraceArc(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
00165 TraceArcPath(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo,
00166 const MagickRealType,const MagickBooleanType,const MagickBooleanType),
00167 TraceBezier(PrimitiveInfo *,const unsigned long),
00168 TraceCircle(PrimitiveInfo *,const PointInfo,const PointInfo),
00169 TraceEllipse(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
00170 TraceLine(PrimitiveInfo *,const PointInfo,const PointInfo),
00171 TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo),
00172 TraceRoundRectangle(PrimitiveInfo *,const PointInfo,const PointInfo,
00173 PointInfo),
00174 TraceSquareLinecap(PrimitiveInfo *,const unsigned long,const MagickRealType);
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 MagickExport DrawInfo *AcquireDrawInfo(void)
00195 {
00196 DrawInfo
00197 *draw_info;
00198
00199 draw_info=(DrawInfo *) AcquireMagickMemory(sizeof(*draw_info));
00200 if (draw_info == (DrawInfo *) NULL)
00201 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00202 GetDrawInfo((ImageInfo *) NULL,draw_info);
00203 return(draw_info);
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
00234 const DrawInfo *draw_info)
00235 {
00236 DrawInfo
00237 *clone_info;
00238
00239 clone_info=(DrawInfo *) AcquireMagickMemory(sizeof(*clone_info));
00240 if (clone_info == (DrawInfo *) NULL)
00241 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00242 GetDrawInfo(image_info,clone_info);
00243 if (draw_info == (DrawInfo *) NULL)
00244 return(clone_info);
00245 if (clone_info->primitive != (char *) NULL)
00246 (void) CloneString(&clone_info->primitive,draw_info->primitive);
00247 if (draw_info->geometry != (char *) NULL)
00248 (void) CloneString(&clone_info->geometry,draw_info->geometry);
00249 clone_info->viewbox=draw_info->viewbox;
00250 clone_info->affine=draw_info->affine;
00251 clone_info->gravity=draw_info->gravity;
00252 clone_info->fill=draw_info->fill;
00253 clone_info->stroke=draw_info->stroke;
00254 clone_info->stroke_width=draw_info->stroke_width;
00255 if (draw_info->fill_pattern != (Image *) NULL)
00256 clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue,
00257 &draw_info->fill_pattern->exception);
00258 else
00259 if (draw_info->tile != (Image *) NULL)
00260 clone_info->fill_pattern=CloneImage(draw_info->tile,0,0,MagickTrue,
00261 &draw_info->tile->exception);
00262 clone_info->tile=NewImageList();
00263 if (draw_info->stroke_pattern != (Image *) NULL)
00264 clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0,
00265 MagickTrue,&draw_info->stroke_pattern->exception);
00266 clone_info->stroke_antialias=draw_info->stroke_antialias;
00267 clone_info->text_antialias=draw_info->text_antialias;
00268 clone_info->fill_rule=draw_info->fill_rule;
00269 clone_info->linecap=draw_info->linecap;
00270 clone_info->linejoin=draw_info->linejoin;
00271 clone_info->miterlimit=draw_info->miterlimit;
00272 clone_info->dash_offset=draw_info->dash_offset;
00273 clone_info->decorate=draw_info->decorate;
00274 clone_info->compose=draw_info->compose;
00275 if (draw_info->text != (char *) NULL)
00276 (void) CloneString(&clone_info->text,draw_info->text);
00277 if (draw_info->font != (char *) NULL)
00278 (void) CloneString(&clone_info->font,draw_info->font);
00279 if (draw_info->metrics != (char *) NULL)
00280 (void) CloneString(&clone_info->metrics,draw_info->metrics);
00281 if (draw_info->family != (char *) NULL)
00282 (void) CloneString(&clone_info->family,draw_info->family);
00283 clone_info->style=draw_info->style;
00284 clone_info->stretch=draw_info->stretch;
00285 clone_info->weight=draw_info->weight;
00286 if (draw_info->encoding != (char *) NULL)
00287 (void) CloneString(&clone_info->encoding,draw_info->encoding);
00288 clone_info->pointsize=draw_info->pointsize;
00289 clone_info->kerning=draw_info->kerning;
00290 clone_info->interline_spacing=draw_info->interline_spacing;
00291 clone_info->interword_spacing=draw_info->interword_spacing;
00292 if (draw_info->density != (char *) NULL)
00293 (void) CloneString(&clone_info->density,draw_info->density);
00294 clone_info->align=draw_info->align;
00295 clone_info->undercolor=draw_info->undercolor;
00296 clone_info->border_color=draw_info->border_color;
00297 if (draw_info->server_name != (char *) NULL)
00298 (void) CloneString(&clone_info->server_name,draw_info->server_name);
00299 if (draw_info->dash_pattern != (double *) NULL)
00300 {
00301 register long
00302 x;
00303
00304 for (x=0; draw_info->dash_pattern[x] != 0.0; x++) ;
00305 clone_info->dash_pattern=(double *) AcquireQuantumMemory((size_t) x+1UL,
00306 sizeof(*clone_info->dash_pattern));
00307 if (clone_info->dash_pattern == (double *) NULL)
00308 ThrowFatalException(ResourceLimitFatalError,
00309 "UnableToAllocateDashPattern");
00310 (void) CopyMagickMemory(clone_info->dash_pattern,draw_info->dash_pattern,
00311 (size_t) (x+1)*sizeof(*clone_info->dash_pattern));
00312 }
00313 clone_info->gradient=draw_info->gradient;
00314 if (draw_info->gradient.stops != (StopInfo *) NULL)
00315 {
00316 unsigned long
00317 number_stops;
00318
00319 number_stops=clone_info->gradient.number_stops;
00320 clone_info->gradient.stops=(StopInfo *) AcquireQuantumMemory((size_t)
00321 number_stops,sizeof(*clone_info->gradient.stops));
00322 if (clone_info->gradient.stops == (StopInfo *) NULL)
00323 ThrowFatalException(ResourceLimitFatalError,
00324 "UnableToAllocateDashPattern");
00325 (void) CopyMagickMemory(clone_info->gradient.stops,
00326 draw_info->gradient.stops,(size_t) number_stops*
00327 sizeof(*clone_info->gradient.stops));
00328 }
00329 if (draw_info->clip_mask != (char *) NULL)
00330 (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
00331 clone_info->bounds=draw_info->bounds;
00332 clone_info->clip_units=draw_info->clip_units;
00333 clone_info->render=draw_info->render;
00334 clone_info->opacity=draw_info->opacity;
00335 clone_info->element_reference=draw_info->element_reference;
00336 clone_info->debug=IsEventLogging();
00337 return(clone_info);
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 #if defined(__cplusplus) || defined(c_plusplus)
00372 extern "C" {
00373 #endif
00374
00375 static int CompareEdges(const void *x,const void *y)
00376 {
00377 register const EdgeInfo
00378 *p,
00379 *q;
00380
00381
00382
00383
00384 p=(const EdgeInfo *) x;
00385 q=(const EdgeInfo *) y;
00386 if ((p->points[0].y-MagickEpsilon) > q->points[0].y)
00387 return(1);
00388 if ((p->points[0].y+MagickEpsilon) < q->points[0].y)
00389 return(-1);
00390 if ((p->points[0].x-MagickEpsilon) > q->points[0].x)
00391 return(1);
00392 if ((p->points[0].x+MagickEpsilon) < q->points[0].x)
00393 return(-1);
00394 if (((p->points[1].x-p->points[0].x)*(q->points[1].y-q->points[0].y)-
00395 (p->points[1].y-p->points[0].y)*(q->points[1].x-q->points[0].x)) > 0.0)
00396 return(1);
00397 return(-1);
00398 }
00399
00400 #if defined(__cplusplus) || defined(c_plusplus)
00401 }
00402 #endif
00403
00404 static void LogPolygonInfo(const PolygonInfo *polygon_info)
00405 {
00406 register EdgeInfo
00407 *p;
00408
00409 register long
00410 i,
00411 j;
00412
00413 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin active-edge");
00414 p=polygon_info->edges;
00415 for (i=0; i < (long) polygon_info->number_edges; i++)
00416 {
00417 (void) LogMagickEvent(DrawEvent,GetMagickModule()," edge %lu:",i);
00418 (void) LogMagickEvent(DrawEvent,GetMagickModule()," direction: %s",
00419 p->direction != MagickFalse ? "down" : "up");
00420 (void) LogMagickEvent(DrawEvent,GetMagickModule()," ghostline: %s",
00421 p->ghostline != MagickFalse ? "transparent" : "opaque");
00422 (void) LogMagickEvent(DrawEvent,GetMagickModule(),
00423 " bounds: %g,%g - %g,%g",p->bounds.x1,p->bounds.y1,p->bounds.x2,
00424 p->bounds.y2);
00425 for (j=0; j < (long) p->number_points; j++)
00426 (void) LogMagickEvent(DrawEvent,GetMagickModule()," %g,%g",
00427 p->points[j].x,p->points[j].y);
00428 p++;
00429 }
00430 (void) LogMagickEvent(DrawEvent,GetMagickModule()," end active-edge");
00431 }
00432
00433 static void ReversePoints(PointInfo *points,const unsigned long number_points)
00434 {
00435 PointInfo
00436 point;
00437
00438 register long
00439 i;
00440
00441 for (i=0; i < (long) (number_points >> 1); i++)
00442 {
00443 point=points[i];
00444 points[i]=points[number_points-(i+1)];
00445 points[number_points-(i+1)]=point;
00446 }
00447 }
00448
00449 static PolygonInfo *ConvertPathToPolygon(
00450 const DrawInfo *magick_unused(draw_info),const PathInfo *path_info)
00451 {
00452 long
00453 direction,
00454 next_direction;
00455
00456 PointInfo
00457 point,
00458 *points;
00459
00460 PolygonInfo
00461 *polygon_info;
00462
00463 SegmentInfo
00464 bounds;
00465
00466 register long
00467 i,
00468 n;
00469
00470 MagickBooleanType
00471 ghostline;
00472
00473 unsigned long
00474 edge,
00475 number_edges,
00476 number_points;
00477
00478
00479
00480
00481 polygon_info=(PolygonInfo *) AcquireMagickMemory(sizeof(*polygon_info));
00482 if (polygon_info == (PolygonInfo *) NULL)
00483 return((PolygonInfo *) NULL);
00484 number_edges=16;
00485 polygon_info->edges=(EdgeInfo *) AcquireQuantumMemory((size_t) number_edges,
00486 sizeof(*polygon_info->edges));
00487 if (polygon_info->edges == (EdgeInfo *) NULL)
00488 return((PolygonInfo *) NULL);
00489 direction=0;
00490 edge=0;
00491 ghostline=MagickFalse;
00492 n=0;
00493 number_points=0;
00494 points=(PointInfo *) NULL;
00495 (void) ResetMagickMemory(&point,0,sizeof(point));
00496 (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
00497 for (i=0; path_info[i].code != EndCode; i++)
00498 {
00499 if ((path_info[i].code == MoveToCode) || (path_info[i].code == OpenCode) ||
00500 (path_info[i].code == GhostlineCode))
00501 {
00502
00503
00504
00505 if ((points != (PointInfo *) NULL) && (n >= 2))
00506 {
00507 if (edge == number_edges)
00508 {
00509 number_edges<<=1;
00510 polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00511 polygon_info->edges,(size_t) number_edges,
00512 sizeof(*polygon_info->edges));
00513 if (polygon_info->edges == (EdgeInfo *) NULL)
00514 return((PolygonInfo *) NULL);
00515 }
00516 polygon_info->edges[edge].number_points=(unsigned long) n;
00517 polygon_info->edges[edge].scanline=(-1.0);
00518 polygon_info->edges[edge].highwater=0;
00519 polygon_info->edges[edge].ghostline=ghostline;
00520 polygon_info->edges[edge].direction=(long) (direction > 0);
00521 if (direction < 0)
00522 ReversePoints(points,(unsigned long) n);
00523 polygon_info->edges[edge].points=points;
00524 polygon_info->edges[edge].bounds=bounds;
00525 polygon_info->edges[edge].bounds.y1=points[0].y;
00526 polygon_info->edges[edge].bounds.y2=points[n-1].y;
00527 points=(PointInfo *) NULL;
00528 ghostline=MagickFalse;
00529 edge++;
00530 }
00531 if (points == (PointInfo *) NULL)
00532 {
00533 number_points=16;
00534 points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
00535 sizeof(*points));
00536 if (points == (PointInfo *) NULL)
00537 return((PolygonInfo *) NULL);
00538 }
00539 ghostline=path_info[i].code == GhostlineCode ? MagickTrue : MagickFalse;
00540 point=path_info[i].point;
00541 points[0]=point;
00542 bounds.x1=point.x;
00543 bounds.x2=point.x;
00544 direction=0;
00545 n=1;
00546 continue;
00547 }
00548
00549
00550
00551 next_direction=((path_info[i].point.y > point.y) ||
00552 ((path_info[i].point.y == point.y) &&
00553 (path_info[i].point.x > point.x))) ? 1 : -1;
00554 if ((direction != 0) && (direction != next_direction))
00555 {
00556
00557
00558
00559 point=points[n-1];
00560 if (edge == number_edges)
00561 {
00562 number_edges<<=1;
00563 polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00564 polygon_info->edges,(size_t) number_edges,
00565 sizeof(*polygon_info->edges));
00566 if (polygon_info->edges == (EdgeInfo *) NULL)
00567 return((PolygonInfo *) NULL);
00568 }
00569 polygon_info->edges[edge].number_points=(unsigned long) n;
00570 polygon_info->edges[edge].scanline=(-1.0);
00571 polygon_info->edges[edge].highwater=0;
00572 polygon_info->edges[edge].ghostline=ghostline;
00573 polygon_info->edges[edge].direction=(long) (direction > 0);
00574 if (direction < 0)
00575 ReversePoints(points,(unsigned long) n);
00576 polygon_info->edges[edge].points=points;
00577 polygon_info->edges[edge].bounds=bounds;
00578 polygon_info->edges[edge].bounds.y1=points[0].y;
00579 polygon_info->edges[edge].bounds.y2=points[n-1].y;
00580 number_points=16;
00581 points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
00582 sizeof(*points));
00583 if (points == (PointInfo *) NULL)
00584 return((PolygonInfo *) NULL);
00585 n=1;
00586 ghostline=MagickFalse;
00587 points[0]=point;
00588 bounds.x1=point.x;
00589 bounds.x2=point.x;
00590 edge++;
00591 }
00592 direction=next_direction;
00593 if (points == (PointInfo *) NULL)
00594 continue;
00595 if (n == (long) number_points)
00596 {
00597 number_points<<=1;
00598 points=(PointInfo *) ResizeQuantumMemory(points,(size_t) number_points,
00599 sizeof(*points));
00600 if (points == (PointInfo *) NULL)
00601 return((PolygonInfo *) NULL);
00602 }
00603 point=path_info[i].point;
00604 points[n]=point;
00605 if (point.x < bounds.x1)
00606 bounds.x1=point.x;
00607 if (point.x > bounds.x2)
00608 bounds.x2=point.x;
00609 n++;
00610 }
00611 if (points != (PointInfo *) NULL)
00612 {
00613 if (n < 2)
00614 points=(PointInfo *) RelinquishMagickMemory(points);
00615 else
00616 {
00617 if (edge == number_edges)
00618 {
00619 number_edges<<=1;
00620 polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00621 polygon_info->edges,(size_t) number_edges,
00622 sizeof(*polygon_info->edges));
00623 if (polygon_info->edges == (EdgeInfo *) NULL)
00624 return((PolygonInfo *) NULL);
00625 }
00626 polygon_info->edges[edge].number_points=(unsigned long) n;
00627 polygon_info->edges[edge].scanline=(-1.0);
00628 polygon_info->edges[edge].highwater=0;
00629 polygon_info->edges[edge].ghostline=ghostline;
00630 polygon_info->edges[edge].direction=(long) (direction > 0);
00631 if (direction < 0)
00632 ReversePoints(points,(unsigned long) n);
00633 polygon_info->edges[edge].points=points;
00634 polygon_info->edges[edge].bounds=bounds;
00635 polygon_info->edges[edge].bounds.y1=points[0].y;
00636 polygon_info->edges[edge].bounds.y2=points[n-1].y;
00637 ghostline=MagickFalse;
00638 edge++;
00639 }
00640 }
00641 polygon_info->number_edges=edge;
00642 qsort(polygon_info->edges,(size_t) polygon_info->number_edges,
00643 sizeof(*polygon_info->edges),CompareEdges);
00644 if (IsEventLogging() != MagickFalse)
00645 LogPolygonInfo(polygon_info);
00646 return(polygon_info);
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 static void LogPathInfo(const PathInfo *path_info)
00681 {
00682 register const PathInfo
00683 *p;
00684
00685 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin vector-path");
00686 for (p=path_info; p->code != EndCode; p++)
00687 (void) LogMagickEvent(DrawEvent,GetMagickModule(),
00688 " %g,%g %s",p->point.x,p->point.y,p->code == GhostlineCode ?
00689 "moveto ghostline" : p->code == OpenCode ? "moveto open" :
00690 p->code == MoveToCode ? "moveto" : p->code == LineToCode ? "lineto" :
00691 "?");
00692 (void) LogMagickEvent(DrawEvent,GetMagickModule()," end vector-path");
00693 }
00694
00695 static PathInfo *ConvertPrimitiveToPath(
00696 const DrawInfo *magick_unused(draw_info),const PrimitiveInfo *primitive_info)
00697 {
00698 long
00699 coordinates,
00700 start;
00701
00702 PathInfo
00703 *path_info;
00704
00705 PathInfoCode
00706 code;
00707
00708 PointInfo
00709 p,
00710 q;
00711
00712 register long
00713 i,
00714 n;
00715
00716
00717
00718
00719 switch (primitive_info->primitive)
00720 {
00721 case PointPrimitive:
00722 case ColorPrimitive:
00723 case MattePrimitive:
00724 case TextPrimitive:
00725 case ImagePrimitive:
00726 return((PathInfo *) NULL);
00727 default:
00728 break;
00729 }
00730 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
00731 path_info=(PathInfo *) AcquireQuantumMemory((size_t) (2UL*i+3UL),
00732 sizeof(*path_info));
00733 if (path_info == (PathInfo *) NULL)
00734 return((PathInfo *) NULL);
00735 coordinates=0;
00736 n=0;
00737 p.x=(-1.0);
00738 p.y=(-1.0);
00739 q.x=(-1.0);
00740 q.y=(-1.0);
00741 start=0;
00742 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
00743 {
00744 code=LineToCode;
00745 if (coordinates <= 0)
00746 {
00747 coordinates=(long) primitive_info[i].coordinates;
00748 p=primitive_info[i].point;
00749 start=n;
00750 code=MoveToCode;
00751 }
00752 coordinates--;
00753
00754
00755
00756 if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) > MagickEpsilon) ||
00757 (fabs(q.y-primitive_info[i].point.y) > MagickEpsilon))
00758 {
00759 path_info[n].code=code;
00760 path_info[n].point=primitive_info[i].point;
00761 q=primitive_info[i].point;
00762 n++;
00763 }
00764 if (coordinates > 0)
00765 continue;
00766 if ((fabs(p.x-primitive_info[i].point.x) <= MagickEpsilon) &&
00767 (fabs(p.y-primitive_info[i].point.y) <= MagickEpsilon))
00768 continue;
00769
00770
00771
00772 path_info[start].code=OpenCode;
00773 path_info[n].code=GhostlineCode;
00774 path_info[n].point=primitive_info[i].point;
00775 n++;
00776 path_info[n].code=LineToCode;
00777 path_info[n].point=p;
00778 n++;
00779 }
00780 path_info[n].code=EndCode;
00781 path_info[n].point.x=0.0;
00782 path_info[n].point.y=0.0;
00783 if (IsEventLogging() != MagickFalse)
00784 LogPathInfo(path_info);
00785 return(path_info);
00786 }
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 MagickExport DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
00812 {
00813 if (draw_info->debug != MagickFalse)
00814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00815 assert(draw_info != (DrawInfo *) NULL);
00816 assert(draw_info->signature == MagickSignature);
00817 if (draw_info->primitive != (char *) NULL)
00818 draw_info->primitive=DestroyString(draw_info->primitive);
00819 if (draw_info->text != (char *) NULL)
00820 draw_info->text=DestroyString(draw_info->text);
00821 if (draw_info->geometry != (char *) NULL)
00822 draw_info->geometry=DestroyString(draw_info->geometry);
00823 if (draw_info->tile != (Image *) NULL)
00824 draw_info->tile=DestroyImage(draw_info->tile);
00825 if (draw_info->fill_pattern != (Image *) NULL)
00826 draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
00827 if (draw_info->stroke_pattern != (Image *) NULL)
00828 draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
00829 if (draw_info->font != (char *) NULL)
00830 draw_info->font=DestroyString(draw_info->font);
00831 if (draw_info->metrics != (char *) NULL)
00832 draw_info->metrics=DestroyString(draw_info->metrics);
00833 if (draw_info->family != (char *) NULL)
00834 draw_info->family=DestroyString(draw_info->family);
00835 if (draw_info->encoding != (char *) NULL)
00836 draw_info->encoding=DestroyString(draw_info->encoding);
00837 if (draw_info->density != (char *) NULL)
00838 draw_info->density=DestroyString(draw_info->density);
00839 if (draw_info->server_name != (char *) NULL)
00840 draw_info->server_name=(char *)
00841 RelinquishMagickMemory(draw_info->server_name);
00842 if (draw_info->dash_pattern != (double *) NULL)
00843 draw_info->dash_pattern=(double *) RelinquishMagickMemory(
00844 draw_info->dash_pattern);
00845 if (draw_info->gradient.stops != (StopInfo *) NULL)
00846 draw_info->gradient.stops=(StopInfo *) RelinquishMagickMemory(
00847 draw_info->gradient.stops);
00848 if (draw_info->clip_mask != (char *) NULL)
00849 draw_info->clip_mask=DestroyString(draw_info->clip_mask);
00850 draw_info->signature=(~MagickSignature);
00851 draw_info=(DrawInfo *) RelinquishMagickMemory(draw_info);
00852 return(draw_info);
00853 }
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879 static unsigned long DestroyEdge(PolygonInfo *polygon_info,
00880 const unsigned long edge)
00881 {
00882 assert(edge < polygon_info->number_edges);
00883 polygon_info->edges[edge].points=(PointInfo *) RelinquishMagickMemory(
00884 polygon_info->edges[edge].points);
00885 polygon_info->number_edges--;
00886 if (edge < polygon_info->number_edges)
00887 (void) CopyMagickMemory(polygon_info->edges+edge,polygon_info->edges+edge+1,
00888 (size_t) (polygon_info->number_edges-edge)*sizeof(*polygon_info->edges));
00889 return(polygon_info->number_edges);
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 static PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
00915 {
00916 register long
00917 i;
00918
00919 for (i=0; i < (long) polygon_info->number_edges; i++)
00920 polygon_info->edges[i].points=(PointInfo *)
00921 RelinquishMagickMemory(polygon_info->edges[i].points);
00922 polygon_info->edges=(EdgeInfo *) RelinquishMagickMemory(polygon_info->edges);
00923 return((PolygonInfo *) RelinquishMagickMemory(polygon_info));
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
00955 const double y,const SegmentInfo *edge)
00956 {
00957 double
00958 intercept,
00959 z;
00960
00961 register double
00962 x;
00963
00964 SegmentInfo
00965 inverse_edge;
00966
00967
00968
00969
00970 inverse_edge.x1=edge->x1;
00971 inverse_edge.y1=edge->y1;
00972 inverse_edge.x2=edge->x2;
00973 inverse_edge.y2=edge->y2;
00974 z=affine->ry*y+affine->tx;
00975 if (affine->sx > MagickEpsilon)
00976 {
00977 intercept=(-z/affine->sx);
00978 x=intercept+MagickEpsilon;
00979 if (x > inverse_edge.x1)
00980 inverse_edge.x1=x;
00981 intercept=(-z+(double) image->columns)/affine->sx;
00982 x=intercept-MagickEpsilon;
00983 if (x < inverse_edge.x2)
00984 inverse_edge.x2=x;
00985 }
00986 else
00987 if (affine->sx < -MagickEpsilon)
00988 {
00989 intercept=(-z+(double) image->columns)/affine->sx;
00990 x=intercept+MagickEpsilon;
00991 if (x > inverse_edge.x1)
00992 inverse_edge.x1=x;
00993 intercept=(-z/affine->sx);
00994 x=intercept-MagickEpsilon;
00995 if (x < inverse_edge.x2)
00996 inverse_edge.x2=x;
00997 }
00998 else
00999 if ((z < 0.0) || ((unsigned long) (z+0.5) >= image->columns))
01000 {
01001 inverse_edge.x2=edge->x1;
01002 return(inverse_edge);
01003 }
01004
01005
01006
01007 z=affine->sy*y+affine->ty;
01008 if (affine->rx > MagickEpsilon)
01009 {
01010 intercept=(-z/affine->rx);
01011 x=intercept+MagickEpsilon;
01012 if (x > inverse_edge.x1)
01013 inverse_edge.x1=x;
01014 intercept=(-z+(double) image->rows)/affine->rx;
01015 x=intercept-MagickEpsilon;
01016 if (x < inverse_edge.x2)
01017 inverse_edge.x2=x;
01018 }
01019 else
01020 if (affine->rx < -MagickEpsilon)
01021 {
01022 intercept=(-z+(double) image->rows)/affine->rx;
01023 x=intercept+MagickEpsilon;
01024 if (x > inverse_edge.x1)
01025 inverse_edge.x1=x;
01026 intercept=(-z/affine->rx);
01027 x=intercept-MagickEpsilon;
01028 if (x < inverse_edge.x2)
01029 inverse_edge.x2=x;
01030 }
01031 else
01032 if ((z < 0.0) || ((unsigned long) (z+0.5) >= image->rows))
01033 {
01034 inverse_edge.x2=edge->x2;
01035 return(inverse_edge);
01036 }
01037 return(inverse_edge);
01038 }
01039
01040 static AffineMatrix InverseAffineMatrix(const AffineMatrix *affine)
01041 {
01042 AffineMatrix
01043 inverse_affine;
01044
01045 double
01046 determinant;
01047
01048 determinant=1.0/(affine->sx*affine->sy-affine->rx*affine->ry);
01049 inverse_affine.sx=determinant*affine->sy;
01050 inverse_affine.rx=determinant*(-affine->rx);
01051 inverse_affine.ry=determinant*(-affine->ry);
01052 inverse_affine.sy=determinant*affine->sx;
01053 inverse_affine.tx=(-affine->tx)*inverse_affine.sx-affine->ty*
01054 inverse_affine.ry;
01055 inverse_affine.ty=(-affine->tx)*inverse_affine.rx-affine->ty*
01056 inverse_affine.sy;
01057 return(inverse_affine);
01058 }
01059
01060 static inline long MagickAbsoluteValue(const long x)
01061 {
01062 if (x < 0)
01063 return(-x);
01064 return(x);
01065 }
01066
01067 static inline double MagickMax(const double x,const double y)
01068 {
01069 if (x > y)
01070 return(x);
01071 return(y);
01072 }
01073
01074 static inline double MagickMin(const double x,const double y)
01075 {
01076 if (x < y)
01077 return(x);
01078 return(y);
01079 }
01080
01081 MagickExport MagickBooleanType DrawAffineImage(Image *image,
01082 const Image *source,const AffineMatrix *affine)
01083 {
01084 AffineMatrix
01085 inverse_affine;
01086
01087 ExceptionInfo
01088 *exception;
01089
01090 long
01091 y;
01092
01093 MagickBooleanType
01094 status;
01095
01096 MagickPixelPacket
01097 zero;
01098
01099 PointInfo
01100 extent[4],
01101 min,
01102 max,
01103 point;
01104
01105 register long
01106 i;
01107
01108 ResampleFilter
01109 **resample_filter;
01110
01111 SegmentInfo
01112 edge;
01113
01114 CacheView
01115 *image_view,
01116 *source_view;
01117
01118
01119
01120
01121 assert(image != (Image *) NULL);
01122 assert(image->signature == MagickSignature);
01123 if (image->debug != MagickFalse)
01124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01125 assert(source != (const Image *) NULL);
01126 assert(source->signature == MagickSignature);
01127 assert(affine != (AffineMatrix *) NULL);
01128 extent[0].x=0.0;
01129 extent[0].y=0.0;
01130 extent[1].x=(double) source->columns-1.0;
01131 extent[1].y=0.0;
01132 extent[2].x=(double) source->columns-1.0;
01133 extent[2].y=(double) source->rows-1.0;
01134 extent[3].x=0.0;
01135 extent[3].y=(double) source->rows-1.0;
01136 for (i=0; i < 4; i++)
01137 {
01138 point=extent[i];
01139 extent[i].x=point.x*affine->sx+point.y*affine->ry+affine->tx;
01140 extent[i].y=point.x*affine->rx+point.y*affine->sy+affine->ty;
01141 }
01142 min=extent[0];
01143 max=extent[0];
01144 for (i=1; i < 4; i++)
01145 {
01146 if (min.x > extent[i].x)
01147 min.x=extent[i].x;
01148 if (min.y > extent[i].y)
01149 min.y=extent[i].y;
01150 if (max.x < extent[i].x)
01151 max.x=extent[i].x;
01152 if (max.y < extent[i].y)
01153 max.y=extent[i].y;
01154 }
01155
01156
01157
01158 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01159 return(MagickFalse);
01160 status=MagickTrue;
01161 edge.x1=MagickMax(min.x,0.0);
01162 edge.y1=MagickMax(min.y,0.0);
01163 edge.x2=MagickMin(max.x,(double) image->columns-1.0);
01164 edge.y2=MagickMin(max.y,(double) image->rows-1.0);
01165 inverse_affine=InverseAffineMatrix(affine);
01166 GetMagickPixelPacket(image,&zero);
01167 exception=(&image->exception);
01168 resample_filter=AcquireResampleFilterThreadSet(source,MagickTrue,exception);
01169 image_view=AcquireCacheView(image);
01170 source_view=AcquireCacheView(source);
01171 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01172 #pragma omp parallel for schedule(dynamic,4) shared(status)
01173 #endif
01174 for (y=(long) (edge.y1+0.5); y <= (long) (edge.y2+0.5); y++)
01175 {
01176 long
01177 x_offset;
01178
01179 MagickPixelPacket
01180 composite,
01181 pixel;
01182
01183 PointInfo
01184 point;
01185
01186 register IndexPacket
01187 *__restrict indexes;
01188
01189 register long
01190 id,
01191 x;
01192
01193 register PixelPacket
01194 *__restrict q;
01195
01196 SegmentInfo
01197 inverse_edge;
01198
01199 inverse_edge=AffineEdge(source,&inverse_affine,(double) y,&edge);
01200 if (inverse_edge.x2 < inverse_edge.x1)
01201 continue;
01202 q=GetCacheViewAuthenticPixels(image_view,(long) (inverse_edge.x1+0.5),y,
01203 (unsigned long) ((long) (inverse_edge.x2+0.5)-(long) (inverse_edge.x1+
01204 0.5)+1),1,exception);
01205 if (q == (PixelPacket *) NULL)
01206 continue;
01207 id=GetOpenMPThreadId();
01208 indexes=GetCacheViewAuthenticIndexQueue(image_view);
01209 pixel=zero;
01210 composite=zero;
01211 x_offset=0;
01212 for (x=(long) (inverse_edge.x1+0.5); x <= (long) (inverse_edge.x2+0.5); x++)
01213 {
01214 point.x=(double) x*inverse_affine.sx+y*inverse_affine.ry+
01215 inverse_affine.tx;
01216 point.y=(double) x*inverse_affine.rx+y*inverse_affine.sy+
01217 inverse_affine.ty;
01218 (void) ResamplePixelColor(resample_filter[id],point.x,point.y,&pixel);
01219 SetMagickPixelPacket(image,q,indexes+x_offset,&composite);
01220 MagickPixelCompositeOver(&pixel,pixel.opacity,&composite,
01221 composite.opacity,&composite);
01222 SetPixelPacket(image,&composite,q,indexes+x_offset);
01223 x_offset++;
01224 q++;
01225 }
01226 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01227 status=MagickFalse;
01228 }
01229 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
01230 source_view=DestroyCacheView(source_view);
01231 image_view=DestroyCacheView(image_view);
01232 return(status);
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263 static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
01264 const PolygonInfo *polygon_info)
01265 {
01266 DrawInfo
01267 *clone_info;
01268
01269 long
01270 coordinates;
01271
01272 MagickRealType
01273 mid;
01274
01275 PointInfo
01276 end,
01277 resolution,
01278 start;
01279
01280 PrimitiveInfo
01281 primitive_info[6];
01282
01283 register long
01284 i;
01285
01286 SegmentInfo
01287 bounds;
01288
01289 clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
01290 (void) QueryColorDatabase("#0000",&clone_info->fill,&image->exception);
01291 resolution.x=DefaultResolution;
01292 resolution.y=DefaultResolution;
01293 if (clone_info->density != (char *) NULL)
01294 {
01295 GeometryInfo
01296 geometry_info;
01297
01298 MagickStatusType
01299 flags;
01300
01301 flags=ParseGeometry(clone_info->density,&geometry_info);
01302 resolution.x=geometry_info.rho;
01303 resolution.y=geometry_info.sigma;
01304 if ((flags & SigmaValue) == MagickFalse)
01305 resolution.y=resolution.x;
01306 }
01307 mid=(resolution.x/72.0)*ExpandAffine(&clone_info->affine)*
01308 clone_info->stroke_width/2.0;
01309 bounds.x1=0.0;
01310 bounds.y1=0.0;
01311 bounds.x2=0.0;
01312 bounds.y2=0.0;
01313 if (polygon_info != (PolygonInfo *) NULL)
01314 {
01315 bounds=polygon_info->edges[0].bounds;
01316 for (i=1; i < (long) polygon_info->number_edges; i++)
01317 {
01318 if (polygon_info->edges[i].bounds.x1 < (double) bounds.x1)
01319 bounds.x1=polygon_info->edges[i].bounds.x1;
01320 if (polygon_info->edges[i].bounds.y1 < (double) bounds.y1)
01321 bounds.y1=polygon_info->edges[i].bounds.y1;
01322 if (polygon_info->edges[i].bounds.x2 > (double) bounds.x2)
01323 bounds.x2=polygon_info->edges[i].bounds.x2;
01324 if (polygon_info->edges[i].bounds.y2 > (double) bounds.y2)
01325 bounds.y2=polygon_info->edges[i].bounds.y2;
01326 }
01327 bounds.x1-=mid;
01328 bounds.x1=bounds.x1 < 0.0 ? 0.0 : bounds.x1 >= (double)
01329 image->columns ? (double) image->columns-1 : bounds.x1;
01330 bounds.y1-=mid;
01331 bounds.y1=bounds.y1 < 0.0 ? 0.0 : bounds.y1 >= (double)
01332 image->rows ? (double) image->rows-1 : bounds.y1;
01333 bounds.x2+=mid;
01334 bounds.x2=bounds.x2 < 0.0 ? 0.0 : bounds.x2 >= (double)
01335 image->columns ? (double) image->columns-1 : bounds.x2;
01336 bounds.y2+=mid;
01337 bounds.y2=bounds.y2 < 0.0 ? 0.0 : bounds.y2 >= (double)
01338 image->rows ? (double) image->rows-1 : bounds.y2;
01339 for (i=0; i < (long) polygon_info->number_edges; i++)
01340 {
01341 if (polygon_info->edges[i].direction != 0)
01342 (void) QueryColorDatabase("red",&clone_info->stroke,
01343 &image->exception);
01344 else
01345 (void) QueryColorDatabase("green",&clone_info->stroke,
01346 &image->exception);
01347 start.x=(double) (polygon_info->edges[i].bounds.x1-mid);
01348 start.y=(double) (polygon_info->edges[i].bounds.y1-mid);
01349 end.x=(double) (polygon_info->edges[i].bounds.x2+mid);
01350 end.y=(double) (polygon_info->edges[i].bounds.y2+mid);
01351 primitive_info[0].primitive=RectanglePrimitive;
01352 TraceRectangle(primitive_info,start,end);
01353 primitive_info[0].method=ReplaceMethod;
01354 coordinates=(long) primitive_info[0].coordinates;
01355 primitive_info[coordinates].primitive=UndefinedPrimitive;
01356 (void) DrawPrimitive(image,clone_info,primitive_info);
01357 }
01358 }
01359 (void) QueryColorDatabase("blue",&clone_info->stroke,&image->exception);
01360 start.x=(double) (bounds.x1-mid);
01361 start.y=(double) (bounds.y1-mid);
01362 end.x=(double) (bounds.x2+mid);
01363 end.y=(double) (bounds.y2+mid);
01364 primitive_info[0].primitive=RectanglePrimitive;
01365 TraceRectangle(primitive_info,start,end);
01366 primitive_info[0].method=ReplaceMethod;
01367 coordinates=(long) primitive_info[0].coordinates;
01368 primitive_info[coordinates].primitive=UndefinedPrimitive;
01369 (void) DrawPrimitive(image,clone_info,primitive_info);
01370 clone_info=DestroyDrawInfo(clone_info);
01371 }
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400 MagickExport MagickBooleanType DrawClipPath(Image *image,
01401 const DrawInfo *draw_info,const char *name)
01402 {
01403 char
01404 clip_mask[MaxTextExtent];
01405
01406 const char
01407 *value;
01408
01409 DrawInfo
01410 *clone_info;
01411
01412 MagickStatusType
01413 status;
01414
01415 assert(image != (Image *) NULL);
01416 assert(image->signature == MagickSignature);
01417 if (image->debug != MagickFalse)
01418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01419 assert(draw_info != (const DrawInfo *) NULL);
01420 (void) FormatMagickString(clip_mask,MaxTextExtent,"%s",name);
01421 value=GetImageArtifact(image,clip_mask);
01422 if (value == (const char *) NULL)
01423 return(MagickFalse);
01424 if (image->clip_mask == (Image *) NULL)
01425 {
01426 Image
01427 *clip_mask;
01428
01429 clip_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
01430 &image->exception);
01431 if (clip_mask == (Image *) NULL)
01432 return(MagickFalse);
01433 (void) SetImageClipMask(image,clip_mask);
01434 clip_mask=DestroyImage(clip_mask);
01435 }
01436 (void) QueryColorDatabase("#00000000",&image->clip_mask->background_color,
01437 &image->exception);
01438 image->clip_mask->background_color.opacity=(Quantum) TransparentOpacity;
01439 (void) SetImageBackgroundColor(image->clip_mask);
01440 if (image->debug != MagickFalse)
01441 (void) LogMagickEvent(DrawEvent,GetMagickModule(),"\nbegin clip-path %s",
01442 draw_info->clip_mask);
01443 clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
01444 (void) CloneString(&clone_info->primitive,value);
01445 (void) QueryColorDatabase("#ffffff",&clone_info->fill,&image->exception);
01446 clone_info->clip_mask=(char *) NULL;
01447 status=DrawImage(image->clip_mask,clone_info);
01448 status|=NegateImage(image->clip_mask,MagickFalse);
01449 clone_info=DestroyDrawInfo(clone_info);
01450 if (image->debug != MagickFalse)
01451 (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end clip-path");
01452 return(status != 0 ? MagickTrue : MagickFalse);
01453 }
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
01485 const PrimitiveInfo *primitive_info,Image *image)
01486 {
01487 DrawInfo
01488 *clone_info;
01489
01490 long
01491 j,
01492 n;
01493
01494 MagickRealType
01495 length,
01496 maximum_length,
01497 offset,
01498 scale,
01499 total_length;
01500
01501 MagickStatusType
01502 status;
01503
01504 PrimitiveInfo
01505 *dash_polygon;
01506
01507 register long
01508 i;
01509
01510 register MagickRealType
01511 dx,
01512 dy;
01513
01514 unsigned long
01515 number_vertices;
01516
01517 assert(draw_info != (const DrawInfo *) NULL);
01518 if (image->debug != MagickFalse)
01519 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin draw-dash");
01520 clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
01521 clone_info->miterlimit=0;
01522 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
01523 number_vertices=(unsigned long) i;
01524 dash_polygon=(PrimitiveInfo *) AcquireQuantumMemory((size_t)
01525 (2UL*number_vertices+1UL),sizeof(*dash_polygon));
01526 if (dash_polygon == (PrimitiveInfo *) NULL)
01527 return(MagickFalse);
01528 dash_polygon[0]=primitive_info[0];
01529 scale=ExpandAffine(&draw_info->affine);
01530 length=scale*(draw_info->dash_pattern[0]-0.5);
01531 offset=draw_info->dash_offset != 0.0 ? scale*draw_info->dash_offset : 0.0;
01532 j=1;
01533 for (n=0; offset > 0.0; j=0)
01534 {
01535 if (draw_info->dash_pattern[n] <= 0.0)
01536 break;
01537 length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
01538 if (offset > length)
01539 {
01540 offset-=length;
01541 n++;
01542 length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
01543 continue;
01544 }
01545 if (offset < length)
01546 {
01547 length-=offset;
01548 offset=0.0;
01549 break;
01550 }
01551 offset=0.0;
01552 n++;
01553 }
01554 status=MagickTrue;
01555 maximum_length=0.0;
01556 total_length=0.0;
01557 for (i=1; i < (long) number_vertices; i++)
01558 {
01559 dx=primitive_info[i].point.x-primitive_info[i-1].point.x;
01560 dy=primitive_info[i].point.y-primitive_info[i-1].point.y;
01561 maximum_length=hypot((double) dx,dy);
01562 if (length == 0.0)
01563 {
01564 n++;
01565 if (draw_info->dash_pattern[n] == 0.0)
01566 n=0;
01567 length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
01568 }
01569 for (total_length=0.0; (total_length+length) < maximum_length; )
01570 {
01571 total_length+=length;
01572 if ((n & 0x01) != 0)
01573 {
01574 dash_polygon[0]=primitive_info[0];
01575 dash_polygon[0].point.x=(double) (primitive_info[i-1].point.x+dx*
01576 total_length/maximum_length);
01577 dash_polygon[0].point.y=(double) (primitive_info[i-1].point.y+dy*
01578 total_length/maximum_length);
01579 j=1;
01580 }
01581 else
01582 {
01583 if ((j+1) > (long) (2*number_vertices))
01584 break;
01585 dash_polygon[j]=primitive_info[i-1];
01586 dash_polygon[j].point.x=(double) (primitive_info[i-1].point.x+dx*
01587 total_length/maximum_length);
01588 dash_polygon[j].point.y=(double) (primitive_info[i-1].point.y+dy*
01589 total_length/maximum_length);
01590 dash_polygon[j].coordinates=1;
01591 j++;
01592 dash_polygon[0].coordinates=(unsigned long) j;
01593 dash_polygon[j].primitive=UndefinedPrimitive;
01594 status|=DrawStrokePolygon(image,clone_info,dash_polygon);
01595 }
01596 n++;
01597 if (draw_info->dash_pattern[n] == 0.0)
01598 n=0;
01599 length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
01600 }
01601 length-=(maximum_length-total_length);
01602 if ((n & 0x01) != 0)
01603 continue;
01604 dash_polygon[j]=primitive_info[i];
01605 dash_polygon[j].coordinates=1;
01606 j++;
01607 }
01608 if ((total_length < maximum_length) && ((n & 0x01) == 0) && (j > 1))
01609 {
01610 dash_polygon[j]=primitive_info[i-1];
01611 dash_polygon[j].point.x+=MagickEpsilon;
01612 dash_polygon[j].point.y+=MagickEpsilon;
01613 dash_polygon[j].coordinates=1;
01614 j++;
01615 dash_polygon[0].coordinates=(unsigned long) j;
01616 dash_polygon[j].primitive=UndefinedPrimitive;
01617 status|=DrawStrokePolygon(image,clone_info,dash_polygon);
01618 }
01619 dash_polygon=(PrimitiveInfo *) RelinquishMagickMemory(dash_polygon);
01620 clone_info=DestroyDrawInfo(clone_info);
01621 if (image->debug != MagickFalse)
01622 (void) LogMagickEvent(DrawEvent,GetMagickModule()," end draw-dash");
01623 return(status != 0 ? MagickTrue : MagickFalse);
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655 static inline MagickBooleanType IsPoint(const char *point)
01656 {
01657 char
01658 *p;
01659
01660 double
01661 value;
01662
01663 value=strtod(point,&p);
01664 return((value == 0.0) && (p == point) ? MagickFalse : MagickTrue);
01665 }
01666
01667 static inline void TracePoint(PrimitiveInfo *primitive_info,
01668 const PointInfo point)
01669 {
01670 primitive_info->coordinates=1;
01671 primitive_info->point=point;
01672 }
01673
01674 MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info)
01675 {
01676 #define RenderImageTag "Render/Image"
01677
01678 AffineMatrix
01679 affine,
01680 current;
01681
01682 char
01683 key[2*MaxTextExtent],
01684 keyword[MaxTextExtent],
01685 geometry[MaxTextExtent],
01686 name[MaxTextExtent],
01687 pattern[MaxTextExtent],
01688 *primitive,
01689 *token;
01690
01691 const char
01692 *q;
01693
01694 DrawInfo
01695 **graphic_context;
01696
01697 long
01698 j,
01699 k,
01700 n;
01701
01702 MagickBooleanType
01703 proceed,
01704 status;
01705
01706 MagickRealType
01707 angle,
01708 factor,
01709 primitive_extent;
01710
01711 PointInfo
01712 point;
01713
01714 PixelPacket
01715 start_color;
01716
01717 PrimitiveInfo
01718 *primitive_info;
01719
01720 PrimitiveType
01721 primitive_type;
01722
01723 register const char
01724 *p;
01725
01726 register long
01727 i,
01728 x;
01729
01730 SegmentInfo
01731 bounds;
01732
01733 size_t
01734 length;
01735
01736 unsigned long
01737 number_points;
01738
01739
01740
01741
01742 assert(image != (Image *) NULL);
01743 assert(image->signature == MagickSignature);
01744 if (image->debug != MagickFalse)
01745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01746 assert(draw_info != (DrawInfo *) NULL);
01747 assert(draw_info->signature == MagickSignature);
01748 if (image->debug != MagickFalse)
01749 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
01750 if ((draw_info->primitive == (char *) NULL) ||
01751 (*draw_info->primitive == '\0'))
01752 return(MagickFalse);
01753 if (image->debug != MagickFalse)
01754 (void) LogMagickEvent(DrawEvent,GetMagickModule(),"begin draw-image");
01755 if (*draw_info->primitive != '@')
01756 primitive=AcquireString(draw_info->primitive);
01757 else
01758 primitive=FileToString(draw_info->primitive+1,~0,&image->exception);
01759 if (primitive == (char *) NULL)
01760 return(MagickFalse);
01761 primitive_extent=(MagickRealType) strlen(primitive);
01762 (void) SetImageArtifact(image,"MVG",primitive);
01763 n=0;
01764
01765
01766
01767 graphic_context=(DrawInfo **) AcquireMagickMemory(sizeof(*graphic_context));
01768 if (graphic_context == (DrawInfo **) NULL)
01769 {
01770 primitive=DestroyString(primitive);
01771 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01772 image->filename);
01773 }
01774 number_points=2047;
01775 primitive_info=(PrimitiveInfo *) AcquireQuantumMemory((size_t) number_points,
01776 sizeof(*primitive_info));
01777 if (primitive_info == (PrimitiveInfo *) NULL)
01778 {
01779 primitive=DestroyString(primitive);
01780 for ( ; n >= 0; n--)
01781 graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
01782 graphic_context=(DrawInfo **) RelinquishMagickMemory(graphic_context);
01783 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01784 image->filename);
01785 }
01786 graphic_context[n]=CloneDrawInfo((ImageInfo *) NULL,draw_info);
01787 graphic_context[n]->viewbox=image->page;
01788 if ((image->page.width == 0) || (image->page.height == 0))
01789 {
01790 graphic_context[n]->viewbox.width=image->columns;
01791 graphic_context[n]->viewbox.height=image->rows;
01792 }
01793 token=AcquireString(primitive);
01794 (void) QueryColorDatabase("#000000",&start_color,&image->exception);
01795 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01796 return(MagickFalse);
01797 status=MagickTrue;
01798 for (q=primitive; *q != '\0'; )
01799 {
01800
01801
01802
01803 GetMagickToken(q,&q,keyword);
01804 if (*keyword == '\0')
01805 break;
01806 if (*keyword == '#')
01807 {
01808
01809
01810
01811 while ((*q != '\n') && (*q != '\0'))
01812 q++;
01813 continue;
01814 }
01815 p=q-strlen(keyword)-1;
01816 primitive_type=UndefinedPrimitive;
01817 current=graphic_context[n]->affine;
01818 GetAffineMatrix(&affine);
01819 switch (*keyword)
01820 {
01821 case ';':
01822 break;
01823 case 'a':
01824 case 'A':
01825 {
01826 if (LocaleCompare("affine",keyword) == 0)
01827 {
01828 GetMagickToken(q,&q,token);
01829 affine.sx=atof(token);
01830 GetMagickToken(q,&q,token);
01831 if (*token == ',')
01832 GetMagickToken(q,&q,token);
01833 affine.rx=atof(token);
01834 GetMagickToken(q,&q,token);
01835 if (*token == ',')
01836 GetMagickToken(q,&q,token);
01837 affine.ry=atof(token);
01838 GetMagickToken(q,&q,token);
01839 if (*token == ',')
01840 GetMagickToken(q,&q,token);
01841 affine.sy=atof(token);
01842 GetMagickToken(q,&q,token);
01843 if (*token == ',')
01844 GetMagickToken(q,&q,token);
01845 affine.tx=atof(token);
01846 GetMagickToken(q,&q,token);
01847 if (*token == ',')
01848 GetMagickToken(q,&q,token);
01849 affine.ty=atof(token);
01850 break;
01851 }
01852 if (LocaleCompare("arc",keyword) == 0)
01853 {
01854 primitive_type=ArcPrimitive;
01855 break;
01856 }
01857 status=MagickFalse;
01858 break;
01859 }
01860 case 'b':
01861 case 'B':
01862 {
01863 if (LocaleCompare("bezier",keyword) == 0)
01864 {
01865 primitive_type=BezierPrimitive;
01866 break;
01867 }
01868 if (LocaleCompare("border-color",keyword) == 0)
01869 {
01870 GetMagickToken(q,&q,token);
01871 (void) QueryColorDatabase(token,&graphic_context[n]->border_color,
01872 &image->exception);
01873 break;
01874 }
01875 status=MagickFalse;
01876 break;
01877 }
01878 case 'c':
01879 case 'C':
01880 {
01881 if (LocaleCompare("clip-path",keyword) == 0)
01882 {
01883
01884
01885
01886 GetMagickToken(q,&q,token);
01887 (void) CloneString(&graphic_context[n]->clip_mask,token);
01888 (void) DrawClipPath(image,graphic_context[n],
01889 graphic_context[n]->clip_mask);
01890 break;
01891 }
01892 if (LocaleCompare("clip-rule",keyword) == 0)
01893 {
01894 long
01895 fill_rule;
01896
01897 GetMagickToken(q,&q,token);
01898 fill_rule=ParseMagickOption(MagickFillRuleOptions,MagickFalse,
01899 token);
01900 if (fill_rule == -1)
01901 {
01902 status=MagickFalse;
01903 break;
01904 }
01905 graphic_context[n]->fill_rule=(FillRule) fill_rule;
01906 break;
01907 }
01908 if (LocaleCompare("clip-units",keyword) == 0)
01909 {
01910 long
01911 clip_units;
01912
01913 GetMagickToken(q,&q,token);
01914 clip_units=ParseMagickOption(MagickClipPathOptions,MagickFalse,
01915 token);
01916 if (clip_units == -1)
01917 {
01918 status=MagickFalse;
01919 break;
01920 }
01921 graphic_context[n]->clip_units=(ClipPathUnits) clip_units;
01922 if (clip_units == ObjectBoundingBox)
01923 {
01924 GetAffineMatrix(¤t);
01925 affine.sx=draw_info->bounds.x2;
01926 affine.sy=draw_info->bounds.y2;
01927 affine.tx=draw_info->bounds.x1;
01928 affine.ty=draw_info->bounds.y1;
01929 break;
01930 }
01931 break;
01932 }
01933 if (LocaleCompare("circle",keyword) == 0)
01934 {
01935 primitive_type=CirclePrimitive;
01936 break;
01937 }
01938 if (LocaleCompare("color",keyword) == 0)
01939 {
01940 primitive_type=ColorPrimitive;
01941 break;
01942 }
01943 status=MagickFalse;
01944 break;
01945 }
01946 case 'd':
01947 case 'D':
01948 {
01949 if (LocaleCompare("decorate",keyword) == 0)
01950 {
01951 long
01952 decorate;
01953
01954 GetMagickToken(q,&q,token);
01955 decorate=ParseMagickOption(MagickDecorateOptions,MagickFalse,
01956 token);
01957 if (decorate == -1)
01958 {
01959 status=MagickFalse;
01960 break;
01961 }
01962 graphic_context[n]->decorate=(DecorationType) decorate;
01963 break;
01964 }
01965 status=MagickFalse;
01966 break;
01967 }
01968 case 'e':
01969 case 'E':
01970 {
01971 if (LocaleCompare("ellipse",keyword) == 0)
01972 {
01973 primitive_type=EllipsePrimitive;
01974 break;
01975 }
01976 if (LocaleCompare("encoding",keyword) == 0)
01977 {
01978 GetMagickToken(q,&q,token);
01979 (void) CloneString(&graphic_context[n]->encoding,token);
01980 break;
01981 }
01982 status=MagickFalse;
01983 break;
01984 }
01985 case 'f':
01986 case 'F':
01987 {
01988 if (LocaleCompare("fill",keyword) == 0)
01989 {
01990 GetMagickToken(q,&q,token);
01991 (void) FormatMagickString(pattern,MaxTextExtent,"%s",token);
01992 if (GetImageArtifact(image,pattern) != (const char *) NULL)
01993 (void) DrawPatternPath(image,draw_info,token,
01994 &graphic_context[n]->fill_pattern);
01995 else
01996 {
01997 status=QueryColorDatabase(token,&graphic_context[n]->fill,
01998 &image->exception);
01999 if (status == MagickFalse)
02000 {
02001 ImageInfo
02002 *pattern_info;
02003
02004 pattern_info=AcquireImageInfo();
02005 (void) CopyMagickString(pattern_info->filename,token,
02006 MaxTextExtent);
02007 graphic_context[n]->fill_pattern=
02008 ReadImage(pattern_info,&image->exception);
02009 CatchException(&image->exception);
02010 pattern_info=DestroyImageInfo(pattern_info);
02011 }
02012 }
02013 break;
02014 }
02015 if (LocaleCompare("fill-opacity",keyword) == 0)
02016 {
02017 GetMagickToken(q,&q,token);
02018 factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
02019 graphic_context[n]->fill.opacity=RoundToQuantum((MagickRealType)
02020 QuantumRange*(1.0-factor*atof(token)));
02021 break;
02022 }
02023 if (LocaleCompare("fill-rule",keyword) == 0)
02024 {
02025 long
02026 fill_rule;
02027
02028 GetMagickToken(q,&q,token);
02029 fill_rule=ParseMagickOption(MagickFillRuleOptions,MagickFalse,
02030 token);
02031 if (fill_rule == -1)
02032 {
02033 status=MagickFalse;
02034 break;
02035 }
02036 graphic_context[n]->fill_rule=(FillRule) fill_rule;
02037 break;
02038 }
02039 if (LocaleCompare("font",keyword) == 0)
02040 {
02041 GetMagickToken(q,&q,token);
02042 (void) CloneString(&graphic_context[n]->font,token);
02043 if (LocaleCompare("none",token) == 0)
02044 graphic_context[n]->font=(char *)
02045 RelinquishMagickMemory(graphic_context[n]->font);
02046 break;
02047 }
02048 if (LocaleCompare("font-family",keyword) == 0)
02049 {
02050 GetMagickToken(q,&q,token);
02051 (void) CloneString(&graphic_context[n]->family,token);
02052 break;
02053 }
02054 if (LocaleCompare("font-size",keyword) == 0)
02055 {
02056 GetMagickToken(q,&q,token);
02057 graphic_context[n]->pointsize=atof(token);
02058 break;
02059 }
02060 if (LocaleCompare("font-stretch",keyword) == 0)
02061 {
02062 long
02063 stretch;
02064
02065 GetMagickToken(q,&q,token);
02066 stretch=ParseMagickOption(MagickStretchOptions,MagickFalse,token);
02067 if (stretch == -1)
02068 {
02069 status=MagickFalse;
02070 break;
02071 }
02072 graphic_context[n]->stretch=(StretchType) stretch;
02073 break;
02074 }
02075 if (LocaleCompare("font-style",keyword) == 0)
02076 {
02077 long
02078 style;
02079
02080 GetMagickToken(q,&q,token);
02081 style=ParseMagickOption(MagickStyleOptions,MagickFalse,token);
02082 if (style == -1)
02083 {
02084 status=MagickFalse;
02085 break;
02086 }
02087 graphic_context[n]->style=(StyleType) style;
02088 break;
02089 }
02090 if (LocaleCompare("font-weight",keyword) == 0)
02091 {
02092 GetMagickToken(q,&q,token);
02093 graphic_context[n]->weight=(unsigned long) atol(token);
02094 if (LocaleCompare(token,"all") == 0)
02095 graphic_context[n]->weight=0;
02096 if (LocaleCompare(token,"bold") == 0)
02097 graphic_context[n]->weight=700;
02098 if (LocaleCompare(token,"bolder") == 0)
02099 if (graphic_context[n]->weight <= 800)
02100 graphic_context[n]->weight+=100;
02101 if (LocaleCompare(token,"lighter") == 0)
02102 if (graphic_context[n]->weight >= 100)
02103 graphic_context[n]->weight-=100;
02104 if (LocaleCompare(token,"normal") == 0)
02105 graphic_context[n]->weight=400;
02106 break;
02107 }
02108 status=MagickFalse;
02109 break;
02110 }
02111 case 'g':
02112 case 'G':
02113 {
02114 if (LocaleCompare("gradient-units",keyword) == 0)
02115 {
02116 GetMagickToken(q,&q,token);
02117 break;
02118 }
02119 if (LocaleCompare("gravity",keyword) == 0)
02120 {
02121 long
02122 gravity;
02123
02124 GetMagickToken(q,&q,token);
02125 gravity=ParseMagickOption(MagickGravityOptions,MagickFalse,token);
02126 if (gravity == -1)
02127 {
02128 status=MagickFalse;
02129 break;
02130 }
02131 graphic_context[n]->gravity=(GravityType) gravity;
02132 break;
02133 }
02134 status=MagickFalse;
02135 break;
02136 }
02137 case 'i':
02138 case 'I':
02139 {
02140 if (LocaleCompare("image",keyword) == 0)
02141 {
02142 long
02143 compose;
02144
02145 primitive_type=ImagePrimitive;
02146 GetMagickToken(q,&q,token);
02147 compose=ParseMagickOption(MagickComposeOptions,MagickFalse,token);
02148 if (compose == -1)
02149 {
02150 status=MagickFalse;
02151 break;
02152 }
02153 graphic_context[n]->compose=(CompositeOperator) compose;
02154 break;
02155 }
02156 if (LocaleCompare("interline-spacing",keyword) == 0)
02157 {
02158 GetMagickToken(q,&q,token);
02159 graphic_context[n]->interline_spacing=atof(token);
02160 break;
02161 }
02162 if (LocaleCompare("interword-spacing",keyword) == 0)
02163 {
02164 GetMagickToken(q,&q,token);
02165 graphic_context[n]->interword_spacing=atof(token);
02166 break;
02167 }
02168 status=MagickFalse;
02169 break;
02170 }
02171 case 'k':
02172 case 'K':
02173 {
02174 if (LocaleCompare("kerning",keyword) == 0)
02175 {
02176 GetMagickToken(q,&q,token);
02177 graphic_context[n]->kerning=atof(token);
02178 break;
02179 }
02180 status=MagickFalse;
02181 break;
02182 }
02183 case 'l':
02184 case 'L':
02185 {
02186 if (LocaleCompare("line",keyword) == 0)
02187 {
02188 primitive_type=LinePrimitive;
02189 break;
02190 }
02191 status=MagickFalse;
02192 break;
02193 }
02194 case 'm':
02195 case 'M':
02196 {
02197 if (LocaleCompare("matte",keyword) == 0)
02198 {
02199 primitive_type=MattePrimitive;
02200 break;
02201 }
02202 status=MagickFalse;
02203 break;
02204 }
02205 case 'o':
02206 case 'O':
02207 {
02208 if (LocaleCompare("offset",keyword) == 0)
02209 {
02210 GetMagickToken(q,&q,token);
02211 break;
02212 }
02213 if (LocaleCompare("opacity",keyword) == 0)
02214 {
02215 GetMagickToken(q,&q,token);
02216 factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
02217 graphic_context[n]->opacity=RoundToQuantum((MagickRealType)
02218 QuantumRange*(1.0-((1.0-QuantumScale*graphic_context[n]->opacity)*
02219 factor*atof(token))));
02220 graphic_context[n]->fill.opacity=graphic_context[n]->opacity;
02221 graphic_context[n]->stroke.opacity=graphic_context[n]->opacity;
02222 break;
02223 }
02224 status=MagickFalse;
02225 break;
02226 }
02227 case 'p':
02228 case 'P':
02229 {
02230 if (LocaleCompare("path",keyword) == 0)
02231 {
02232 primitive_type=PathPrimitive;
02233 break;
02234 }
02235 if (LocaleCompare("point",keyword) == 0)
02236 {
02237 primitive_type=PointPrimitive;
02238 break;
02239 }
02240 if (LocaleCompare("polyline",keyword) == 0)
02241 {
02242 primitive_type=PolylinePrimitive;
02243 break;
02244 }
02245 if (LocaleCompare("polygon",keyword) == 0)
02246 {
02247 primitive_type=PolygonPrimitive;
02248 break;
02249 }
02250 if (LocaleCompare("pop",keyword) == 0)
02251 {
02252 GetMagickToken(q,&q,token);
02253 if (LocaleCompare("clip-path",token) == 0)
02254 break;
02255 if (LocaleCompare("defs",token) == 0)
02256 break;
02257 if (LocaleCompare("gradient",token) == 0)
02258 break;
02259 if (LocaleCompare("graphic-context",token) == 0)
02260 {
02261 if (n <= 0)
02262 {
02263 (void) ThrowMagickException(&image->exception,
02264 GetMagickModule(),DrawError,
02265 "UnbalancedGraphicContextPushPop","`%s'",token);
02266 n=0;
02267 break;
02268 }
02269 if (graphic_context[n]->clip_mask != (char *) NULL)
02270 if (LocaleCompare(graphic_context[n]->clip_mask,
02271 graphic_context[n-1]->clip_mask) != 0)
02272 (void) SetImageClipMask(image,(Image *) NULL);
02273 graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
02274 n--;
02275 break;
02276 }
02277 if (LocaleCompare("pattern",token) == 0)
02278 break;
02279 status=MagickFalse;
02280 break;
02281 }
02282 if (LocaleCompare("push",keyword) == 0)
02283 {
02284 GetMagickToken(q,&q,token);
02285 if (LocaleCompare("clip-path",token) == 0)
02286 {
02287 char
02288 name[MaxTextExtent];
02289
02290 GetMagickToken(q,&q,token);
02291 (void) FormatMagickString(name,MaxTextExtent,"%s",token);
02292 for (p=q; *q != '\0'; )
02293 {
02294 GetMagickToken(q,&q,token);
02295 if (LocaleCompare(token,"pop") != 0)
02296 continue;
02297 GetMagickToken(q,(const char **) NULL,token);
02298 if (LocaleCompare(token,"clip-path") != 0)
02299 continue;
02300 break;
02301 }
02302 (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
02303 (void) SetImageArtifact(image,name,token);
02304 GetMagickToken(q,&q,token);
02305 break;
02306 }
02307 if (LocaleCompare("gradient",token) == 0)
02308 {
02309 char
02310 key[2*MaxTextExtent],
02311 name[MaxTextExtent],
02312 type[MaxTextExtent];
02313
02314 ElementInfo
02315 element;
02316
02317 SegmentInfo
02318 segment;
02319
02320 GetMagickToken(q,&q,token);
02321 (void) CopyMagickString(name,token,MaxTextExtent);
02322 GetMagickToken(q,&q,token);
02323 (void) CopyMagickString(type,token,MaxTextExtent);
02324 GetMagickToken(q,&q,token);
02325 segment.x1=atof(token);
02326 element.cx=atof(token);
02327 GetMagickToken(q,&q,token);
02328 if (*token == ',')
02329 GetMagickToken(q,&q,token);
02330 segment.y1=atof(token);
02331 element.cy=atof(token);
02332 GetMagickToken(q,&q,token);
02333 if (*token == ',')
02334 GetMagickToken(q,&q,token);
02335 segment.x2=atof(token);
02336 element.major=atof(token);
02337 GetMagickToken(q,&q,token);
02338 if (*token == ',')
02339 GetMagickToken(q,&q,token);
02340 segment.y2=atof(token);
02341 element.minor=atof(token);
02342 if (LocaleCompare(type,"radial") == 0)
02343 {
02344 GetMagickToken(q,&q,token);
02345 if (*token == ',')
02346 GetMagickToken(q,&q,token);
02347 element.angle=atof(token);
02348 }
02349 for (p=q; *q != '\0'; )
02350 {
02351 GetMagickToken(q,&q,token);
02352 if (LocaleCompare(token,"pop") != 0)
02353 continue;
02354 GetMagickToken(q,(const char **) NULL,token);
02355 if (LocaleCompare(token,"gradient") != 0)
02356 continue;
02357 break;
02358 }
02359 (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
02360 bounds.x1=graphic_context[n]->affine.sx*segment.x1+
02361 graphic_context[n]->affine.ry*segment.y1+
02362 graphic_context[n]->affine.tx;
02363 bounds.y1=graphic_context[n]->affine.rx*segment.x1+
02364 graphic_context[n]->affine.sy*segment.y1+
02365 graphic_context[n]->affine.ty;
02366 bounds.x2=graphic_context[n]->affine.sx*segment.x2+
02367 graphic_context[n]->affine.ry*segment.y2+
02368 graphic_context[n]->affine.tx;
02369 bounds.y2=graphic_context[n]->affine.rx*segment.x2+
02370 graphic_context[n]->affine.sy*segment.y2+
02371 graphic_context[n]->affine.ty;
02372 (void) FormatMagickString(key,MaxTextExtent,"%s",name);
02373 (void) SetImageArtifact(image,key,token);
02374 (void) FormatMagickString(key,MaxTextExtent,"%s-geometry",name);
02375 (void) FormatMagickString(geometry,MaxTextExtent,"%gx%g%+f%+f",
02376 MagickMax(fabs(bounds.x2-bounds.x1+1.0),1.0),
02377 MagickMax(fabs(bounds.y2-bounds.y1+1.0),1.0),
02378 bounds.x1,bounds.y1);
02379 (void) SetImageArtifact(image,key,geometry);
02380 GetMagickToken(q,&q,token);
02381 break;
02382 }
02383 if (LocaleCompare("pattern",token) == 0)
02384 {
02385 RectangleInfo
02386 bounds;
02387
02388 GetMagickToken(q,&q,token);
02389 (void) CopyMagickString(name,token,MaxTextExtent);
02390 GetMagickToken(q,&q,token);
02391 bounds.x=(long) (atof(token)+0.5);
02392 GetMagickToken(q,&q,token);
02393 if (*token == ',')
02394 GetMagickToken(q,&q,token);
02395 bounds.y=(long) (atof(token)+0.5);
02396 GetMagickToken(q,&q,token);
02397 if (*token == ',')
02398 GetMagickToken(q,&q,token);
02399 bounds.width=(unsigned long) (atof(token)+0.5);
02400 GetMagickToken(q,&q,token);
02401 if (*token == ',')
02402 GetMagickToken(q,&q,token);
02403 bounds.height=(unsigned long) (atof(token)+0.5);
02404 for (p=q; *q != '\0'; )
02405 {
02406 GetMagickToken(q,&q,token);
02407 if (LocaleCompare(token,"pop") != 0)
02408 continue;
02409 GetMagickToken(q,(const char **) NULL,token);
02410 if (LocaleCompare(token,"pattern") != 0)
02411 continue;
02412 break;
02413 }
02414 (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
02415 (void) FormatMagickString(key,MaxTextExtent,"%s",name);
02416 (void) SetImageArtifact(image,key,token);
02417 (void) FormatMagickString(key,MaxTextExtent,"%s-geometry",name);
02418 (void) FormatMagickString(geometry,MaxTextExtent,
02419 "%lux%lu%+ld%+ld",bounds.width,bounds.height,bounds.x,
02420 bounds.y);
02421 (void) SetImageArtifact(image,key,geometry);
02422 GetMagickToken(q,&q,token);
02423 break;
02424 }
02425 if (LocaleCompare("graphic-context",token) == 0)
02426 {
02427 n++;
02428 graphic_context=(DrawInfo **) ResizeQuantumMemory(
02429 graphic_context,(size_t) (n+1),sizeof(*graphic_context));
02430 if (graphic_context == (DrawInfo **) NULL)
02431 {
02432 (void) ThrowMagickException(&image->exception,
02433 GetMagickModule(),ResourceLimitError,
02434 "MemoryAllocationFailed","`%s'",image->filename);
02435 break;
02436 }
02437 graphic_context[n]=CloneDrawInfo((ImageInfo *) NULL,
02438 graphic_context[n-1]);
02439 break;
02440 }
02441 if (LocaleCompare("defs",token) == 0)
02442 break;
02443 status=MagickFalse;
02444 break;
02445 }
02446 status=MagickFalse;
02447 break;
02448 }
02449 case 'r':
02450 case 'R':
02451 {
02452 if (LocaleCompare("rectangle",keyword) == 0)
02453 {
02454 primitive_type=RectanglePrimitive;
02455 break;
02456 }
02457 if (LocaleCompare("rotate",keyword) == 0)
02458 {
02459 GetMagickToken(q,&q,token);
02460 angle=atof(token);
02461 affine.sx=cos(DegreesToRadians(fmod((double) angle,360.0)));
02462 affine.rx=sin(DegreesToRadians(fmod((double) angle,360.0)));
02463 affine.ry=(-sin(DegreesToRadians(fmod((double) angle,360.0))));
02464 affine.sy=cos(DegreesToRadians(fmod((double) angle,360.0)));
02465 break;
02466 }
02467 if (LocaleCompare("roundRectangle",keyword) == 0)
02468 {
02469 primitive_type=RoundRectanglePrimitive;
02470 break;
02471 }
02472 status=MagickFalse;
02473 break;
02474 }
02475 case 's':
02476 case 'S':
02477 {
02478 if (LocaleCompare("scale",keyword) == 0)
02479 {
02480 GetMagickToken(q,&q,token);
02481 affine.sx=atof(token);
02482 GetMagickToken(q,&q,token);
02483 if (*token == ',')
02484 GetMagickToken(q,&q,token);
02485 affine.sy=atof(token);
02486 break;
02487 }
02488 if (LocaleCompare("skewX",keyword) == 0)
02489 {
02490 GetMagickToken(q,&q,token);
02491 angle=atof(token);
02492 affine.ry=sin(DegreesToRadians(angle));
02493 break;
02494 }
02495 if (LocaleCompare("skewY",keyword) == 0)
02496 {
02497 GetMagickToken(q,&q,token);
02498 angle=atof(token);
02499 affine.rx=(-tan(DegreesToRadians(angle)/2.0));
02500 break;
02501 }
02502 if (LocaleCompare("stop-color",keyword) == 0)
02503 {
02504 PixelPacket
02505 stop_color;
02506
02507 GetMagickToken(q,&q,token);
02508 (void) QueryColorDatabase(token,&stop_color,&image->exception);
02509 (void) GradientImage(image,LinearGradient,ReflectSpread,
02510 &start_color,&stop_color);
02511 start_color=stop_color;
02512 GetMagickToken(q,&q,token);
02513 break;
02514 }
02515 if (LocaleCompare("stroke",keyword) == 0)
02516 {
02517 GetMagickToken(q,&q,token);
02518 (void) FormatMagickString(pattern,MaxTextExtent,"%s",token);
02519 if (GetImageArtifact(image,pattern) != (const char *) NULL)
02520 (void) DrawPatternPath(image,draw_info,token,
02521 &graphic_context[n]->stroke_pattern);
02522 else
02523 {
02524 status=QueryColorDatabase(token,&graphic_context[n]->stroke,
02525 &image->exception);
02526 if (status == MagickFalse)
02527 {
02528 ImageInfo
02529 *pattern_info;
02530
02531 pattern_info=AcquireImageInfo();
02532 (void) CopyMagickString(pattern_info->filename,token,
02533 MaxTextExtent);
02534 graphic_context[n]->stroke_pattern=
02535 ReadImage(pattern_info,&image->exception);
02536 CatchException(&image->exception);
02537 pattern_info=DestroyImageInfo(pattern_info);
02538 }
02539 }
02540 break;
02541 }
02542 if (LocaleCompare("stroke-antialias",keyword) == 0)
02543 {
02544 GetMagickToken(q,&q,token);
02545 graphic_context[n]->stroke_antialias=
02546 atoi(token) != 0 ? MagickTrue : MagickFalse;
02547 break;
02548 }
02549 if (LocaleCompare("stroke-dasharray",keyword) == 0)
02550 {
02551 if (graphic_context[n]->dash_pattern != (double *) NULL)
02552 graphic_context[n]->dash_pattern=(double *)
02553 RelinquishMagickMemory(graphic_context[n]->dash_pattern);
02554 if (IsPoint(q) != MagickFalse)
02555 {
02556 const char
02557 *p;
02558
02559 p=q;
02560 GetMagickToken(p,&p,token);
02561 if (*token == ',')
02562 GetMagickToken(p,&p,token);
02563 for (x=0; IsPoint(token) != MagickFalse; x++)
02564 {
02565 GetMagickToken(p,&p,token);
02566 if (*token == ',')
02567 GetMagickToken(p,&p,token);
02568 }
02569 graphic_context[n]->dash_pattern=(double *)
02570 AcquireQuantumMemory((size_t) (2UL*x+1UL),
02571 sizeof(*graphic_context[n]->dash_pattern));
02572 if (graphic_context[n]->dash_pattern == (double *) NULL)
02573 {
02574 (void) ThrowMagickException(&image->exception,
02575 GetMagickModule(),ResourceLimitError,
02576 "MemoryAllocationFailed","`%s'",image->filename);
02577 break;
02578 }
02579 for (j=0; j < x; j++)
02580 {
02581 GetMagickToken(q,&q,token);
02582 if (*token == ',')
02583 GetMagickToken(q,&q,token);
02584 graphic_context[n]->dash_pattern[j]=atof(token);
02585 }
02586 if ((x & 0x01) != 0)
02587 for ( ; j < (2*x); j++)
02588 graphic_context[n]->dash_pattern[j]=
02589 graphic_context[n]->dash_pattern[j-x];
02590 graphic_context[n]->dash_pattern[j]=0.0;
02591 break;
02592 }
02593 GetMagickToken(q,&q,token);
02594 break;
02595 }
02596 if (LocaleCompare("stroke-dashoffset",keyword) == 0)
02597 {
02598 GetMagickToken(q,&q,token);
02599 graphic_context[n]->dash_offset=atof(token);
02600 break;
02601 }
02602 if (LocaleCompare("stroke-linecap",keyword) == 0)
02603 {
02604 long
02605 linecap;
02606
02607 GetMagickToken(q,&q,token);
02608 linecap=ParseMagickOption(MagickLineCapOptions,MagickFalse,token);
02609 if (linecap == -1)
02610 {
02611 status=MagickFalse;
02612 break;
02613 }
02614 graphic_context[n]->linecap=(LineCap) linecap;
02615 break;
02616 }
02617 if (LocaleCompare("stroke-linejoin",keyword) == 0)
02618 {
02619 long
02620 linejoin;
02621
02622 GetMagickToken(q,&q,token);
02623 linejoin=ParseMagickOption(MagickLineJoinOptions,MagickFalse,token);
02624 if (linejoin == -1)
02625 {
02626 status=MagickFalse;
02627 break;
02628 }
02629 graphic_context[n]->linejoin=(LineJoin) linejoin;
02630 break;
02631 }
02632 if (LocaleCompare("stroke-miterlimit",keyword) == 0)
02633 {
02634 GetMagickToken(q,&q,token);
02635 graphic_context[n]->miterlimit=(unsigned long) atol(token);
02636 break;
02637 }
02638 if (LocaleCompare("stroke-opacity",keyword) == 0)
02639 {
02640 GetMagickToken(q,&q,token);
02641 factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
02642 graphic_context[n]->stroke.opacity=RoundToQuantum((MagickRealType)
02643 QuantumRange*(1.0-factor*atof(token)));
02644 break;
02645 }
02646 if (LocaleCompare("stroke-width",keyword) == 0)
02647 {
02648 GetMagickToken(q,&q,token);
02649 graphic_context[n]->stroke_width=atof(token);
02650 break;
02651 }
02652 status=MagickFalse;
02653 break;
02654 }
02655 case 't':
02656 case 'T':
02657 {
02658 if (LocaleCompare("text",keyword) == 0)
02659 {
02660 primitive_type=TextPrimitive;
02661 break;
02662 }
02663 if (LocaleCompare("text-align",keyword) == 0)
02664 {
02665 long
02666 align;
02667
02668 GetMagickToken(q,&q,token);
02669 align=ParseMagickOption(MagickAlignOptions,MagickFalse,token);
02670 if (align == -1)
02671 {
02672 status=MagickFalse;
02673 break;
02674 }
02675 graphic_context[n]->align=(AlignType) align;
02676 break;
02677 }
02678 if (LocaleCompare("text-anchor",keyword) == 0)
02679 {
02680 long
02681 align;
02682
02683 GetMagickToken(q,&q,token);
02684 align=ParseMagickOption(MagickAlignOptions,MagickFalse,token);
02685 if (align == -1)
02686 {
02687 status=MagickFalse;
02688 break;
02689 }
02690 graphic_context[n]->align=(AlignType) align;
02691 break;
02692 }
02693 if (LocaleCompare("text-antialias",keyword) == 0)
02694 {
02695 GetMagickToken(q,&q,token);
02696 graphic_context[n]->text_antialias=
02697 atoi(token) != 0 ? MagickTrue : MagickFalse;
02698 break;
02699 }
02700 if (LocaleCompare("text-undercolor",keyword) == 0)
02701 {
02702 GetMagickToken(q,&q,token);
02703 (void) QueryColorDatabase(token,&graphic_context[n]->undercolor,
02704 &image->exception);
02705 break;
02706 }
02707 if (LocaleCompare("translate",keyword) == 0)
02708 {
02709 GetMagickToken(q,&q,token);
02710 affine.tx=atof(token);
02711 GetMagickToken(q,&q,token);
02712 if (*token == ',')
02713 GetMagickToken(q,&q,token);
02714 affine.ty=atof(token);
02715 break;
02716 }
02717 status=MagickFalse;
02718 break;
02719 }
02720 case 'v':
02721 case 'V':
02722 {
02723 if (LocaleCompare("viewbox",keyword) == 0)
02724 {
02725 GetMagickToken(q,&q,token);
02726 graphic_context[n]->viewbox.x=(long) (atof(token)+0.5);
02727 GetMagickToken(q,&q,token);
02728 if (*token == ',')
02729 GetMagickToken(q,&q,token);
02730 graphic_context[n]->viewbox.y=(long) (atof(token)+0.5);
02731 GetMagickToken(q,&q,token);
02732 if (*token == ',')
02733 GetMagickToken(q,&q,token);
02734 graphic_context[n]->viewbox.width=(unsigned long) (atof(token)+0.5);
02735 GetMagickToken(q,&q,token);
02736 if (*token == ',')
02737 GetMagickToken(q,&q,token);
02738 graphic_context[n]->viewbox.height=(unsigned long) (atof(token)+
02739 0.5);
02740 break;
02741 }
02742 status=MagickFalse;
02743 break;
02744 }
02745 default:
02746 {
02747 status=MagickFalse;
02748 break;
02749 }
02750 }
02751 if (status == MagickFalse)
02752 break;
02753 if ((affine.sx != 1.0) || (affine.rx != 0.0) || (affine.ry != 0.0) ||
02754 (affine.sy != 1.0) || (affine.tx != 0.0) || (affine.ty != 0.0))
02755 {
02756 graphic_context[n]->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
02757 graphic_context[n]->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
02758 graphic_context[n]->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
02759 graphic_context[n]->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
02760 graphic_context[n]->affine.tx=
02761 current.sx*affine.tx+current.ry*affine.ty+current.tx;
02762 graphic_context[n]->affine.ty=
02763 current.rx*affine.tx+current.sy*affine.ty+current.ty;
02764 }
02765 if (primitive_type == UndefinedPrimitive)
02766 {
02767 if (image->debug != MagickFalse)
02768 (void) LogMagickEvent(DrawEvent,GetMagickModule()," %.*s",
02769 (int) (q-p),p);
02770 continue;
02771 }
02772
02773
02774
02775 i=0;
02776 j=0;
02777 primitive_info[0].point.x=0.0;
02778 primitive_info[0].point.y=0.0;
02779 for (x=0; *q != '\0'; x++)
02780 {
02781
02782
02783
02784 if (IsPoint(q) == MagickFalse)
02785 break;
02786 GetMagickToken(q,&q,token);
02787 point.x=atof(token);
02788 GetMagickToken(q,&q,token);
02789 if (*token == ',')
02790 GetMagickToken(q,&q,token);
02791 point.y=atof(token);
02792 GetMagickToken(q,(const char **) NULL,token);
02793 if (*token == ',')
02794 GetMagickToken(q,&q,token);
02795 primitive_info[i].primitive=primitive_type;
02796 primitive_info[i].point=point;
02797 primitive_info[i].coordinates=0;
02798 primitive_info[i].method=FloodfillMethod;
02799 i++;
02800 if (i < (long) number_points)
02801 continue;
02802 number_points<<=1;
02803 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
02804 (size_t) number_points,sizeof(*primitive_info));
02805 if (primitive_info == (PrimitiveInfo *) NULL)
02806 {
02807 (void) ThrowMagickException(&image->exception,GetMagickModule(),
02808 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
02809 break;
02810 }
02811 }
02812 primitive_info[j].primitive=primitive_type;
02813 primitive_info[j].coordinates=(unsigned long) x;
02814 primitive_info[j].method=FloodfillMethod;
02815 primitive_info[j].text=(char *) NULL;
02816
02817
02818
02819 bounds.x1=primitive_info[j].point.x;
02820 bounds.y1=primitive_info[j].point.y;
02821 bounds.x2=primitive_info[j].point.x;
02822 bounds.y2=primitive_info[j].point.y;
02823 for (k=1; k < (long) primitive_info[j].coordinates; k++)
02824 {
02825 point=primitive_info[j+k].point;
02826 if (point.x < bounds.x1)
02827 bounds.x1=point.x;
02828 if (point.y < bounds.y1)
02829 bounds.y1=point.y;
02830 if (point.x > bounds.x2)
02831 bounds.x2=point.x;
02832 if (point.y > bounds.y2)
02833 bounds.y2=point.y;
02834 }
02835
02836
02837
02838 length=primitive_info[j].coordinates;
02839 switch (primitive_type)
02840 {
02841 case RectanglePrimitive:
02842 {
02843 length*=5;
02844 break;
02845 }
02846 case RoundRectanglePrimitive:
02847 {
02848 length*=5+4*BezierQuantum;
02849 break;
02850 }
02851 case BezierPrimitive:
02852 {
02853 if (primitive_info[j].coordinates > 107)
02854 (void) ThrowMagickException(&image->exception,GetMagickModule(),
02855 DrawError,"TooManyBezierCoordinates","`%s'",token);
02856 length=BezierQuantum*primitive_info[j].coordinates;
02857 break;
02858 }
02859 case PathPrimitive:
02860 {
02861 char
02862 *s,
02863 *t;
02864
02865 GetMagickToken(q,&q,token);
02866 k=1;
02867 t=token;
02868 for (s=token; *s != '\0'; s=t)
02869 {
02870 double
02871 value;
02872
02873 value=strtod(s,&t);
02874 if (s == t)
02875 {
02876 t++;
02877 continue;
02878 }
02879 k++;
02880 }
02881 length+=k*BezierQuantum;
02882 break;
02883 }
02884 case CirclePrimitive:
02885 case ArcPrimitive:
02886 case EllipsePrimitive:
02887 {
02888 MagickRealType
02889 alpha,
02890 beta,
02891 radius;
02892
02893 alpha=bounds.x2-bounds.x1;
02894 beta=bounds.y2-bounds.y1;
02895 radius=hypot((double) alpha,(double) beta);
02896 length=2*((size_t) (MagickPI*radius))+6*BezierQuantum+360+1;
02897 break;
02898 }
02899 default:
02900 break;
02901 }
02902 if ((unsigned long) (i+length) >= number_points)
02903 {
02904
02905
02906
02907 while ((unsigned long) (i+length) >= number_points)
02908 number_points<<=1;
02909 primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
02910 (size_t) number_points,sizeof(*primitive_info));
02911 if (primitive_info == (PrimitiveInfo *) NULL)
02912 {
02913 (void) ThrowMagickException(&image->exception,GetMagickModule(),
02914 ResourceLimitError,"MemoryAllocationFailed","`%s'",
02915 image->filename);
02916 break;
02917 }
02918 }
02919 switch (primitive_type)
02920 {
02921 case PointPrimitive:
02922 default:
02923 {
02924 if (primitive_info[j].coordinates != 1)
02925 {
02926 status=MagickFalse;
02927 break;
02928 }
02929 TracePoint(primitive_info+j,primitive_info[j].point);
02930 i=(long) (j+primitive_info[j].coordinates);
02931 break;
02932 }
02933 case LinePrimitive:
02934 {
02935 if (primitive_info[j].coordinates != 2)
02936 {
02937 status=MagickFalse;
02938 break;
02939 }
02940 TraceLine(primitive_info+j,primitive_info[j].point,
02941 primitive_info[j+1].point);
02942 i=(long) (j+primitive_info[j].coordinates);
02943 break;
02944 }
02945 case RectanglePrimitive:
02946 {
02947 if (primitive_info[j].coordinates != 2)
02948 {
02949 status=MagickFalse;
02950 break;
02951 }
02952 TraceRectangle(primitive_info+j,primitive_info[j].point,
02953 primitive_info[j+1].point);
02954 i=(long) (j+primitive_info[j].coordinates);
02955 break;
02956 }
02957 case RoundRectanglePrimitive:
02958 {
02959 if (primitive_info[j].coordinates != 3)
02960 {
02961 status=MagickFalse;
02962 break;
02963 }
02964 TraceRoundRectangle(primitive_info+j,primitive_info[j].point,
02965 primitive_info[j+1].point,primitive_info[j+2].point);
02966 i=(long) (j+primitive_info[j].coordinates);
02967 break;
02968 }
02969 case ArcPrimitive:
02970 {
02971 if (primitive_info[j].coordinates != 3)
02972 {
02973 primitive_type=UndefinedPrimitive;
02974 break;
02975 }
02976 TraceArc(primitive_info+j,primitive_info[j].point,
02977 primitive_info[j+1].point,primitive_info[j+2].point);
02978 i=(long) (j+primitive_info[j].coordinates);
02979 break;
02980 }
02981 case EllipsePrimitive:
02982 {
02983 if (primitive_info[j].coordinates != 3)
02984 {
02985 status=MagickFalse;
02986 break;
02987 }
02988 TraceEllipse(primitive_info+j,primitive_info[j].point,
02989 primitive_info[j+1].point,primitive_info[j+2].point);
02990 i=(long) (j+primitive_info[j].coordinates);
02991 break;
02992 }
02993 case CirclePrimitive:
02994 {
02995 if (primitive_info[j].coordinates != 2)
02996 {
02997 status=MagickFalse;
02998 break;
02999 }
03000 TraceCircle(primitive_info+j,primitive_info[j].point,
03001 primitive_info[j+1].point);
03002 i=(long) (j+primitive_info[j].coordinates);
03003 break;
03004 }
03005 case PolylinePrimitive:
03006 break;
03007 case PolygonPrimitive:
03008 {
03009 primitive_info[i]=primitive_info[j];
03010 primitive_info[i].coordinates=0;
03011 primitive_info[j].coordinates++;
03012 i++;
03013 break;
03014 }
03015 case BezierPrimitive:
03016 {
03017 if (primitive_info[j].coordinates < 3)
03018 {
03019 status=MagickFalse;
03020 break;
03021 }
03022 TraceBezier(primitive_info+j,primitive_info[j].coordinates);
03023 i=(long) (j+primitive_info[j].coordinates);
03024 break;
03025 }
03026 case PathPrimitive:
03027 {
03028 i=(long) (j+TracePath(primitive_info+j,token));
03029 break;
03030 }
03031 case ColorPrimitive:
03032 case MattePrimitive:
03033 {
03034 long
03035 method;
03036
03037 if (primitive_info[j].coordinates != 1)
03038 {
03039 status=MagickFalse;
03040 break;
03041 }
03042 GetMagickToken(q,&q,token);
03043 method=ParseMagickOption(MagickMethodOptions,MagickFalse,token);
03044 if (method == -1)
03045 {
03046 status=MagickFalse;
03047 break;
03048 }
03049 primitive_info[j].method=(PaintMethod) method;
03050 break;
03051 }
03052 case TextPrimitive:
03053 {
03054 if (primitive_info[j].coordinates != 1)
03055 {
03056 status=MagickFalse;
03057 break;
03058 }
03059 if (*token != ',')
03060 GetMagickToken(q,&q,token);
03061 primitive_info[j].text=AcquireString(token);
03062 break;
03063 }
03064 case ImagePrimitive:
03065 {
03066 if (primitive_info[j].coordinates != 2)
03067 {
03068 status=MagickFalse;
03069 break;
03070 }
03071 GetMagickToken(q,&q,token);
03072 primitive_info[j].text=AcquireString(token);
03073 break;
03074 }
03075 }
03076 if (primitive_info == (PrimitiveInfo *) NULL)
03077 break;
03078 if (image->debug != MagickFalse)
03079 (void) LogMagickEvent(DrawEvent,GetMagickModule()," %.*s",(int) (q-p),p);
03080 if (status == MagickFalse)
03081 break;
03082 primitive_info[i].primitive=UndefinedPrimitive;
03083 if (i == 0)
03084 continue;
03085
03086
03087
03088 for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
03089 {
03090 point=primitive_info[i].point;
03091 primitive_info[i].point.x=graphic_context[n]->affine.sx*point.x+
03092 graphic_context[n]->affine.ry*point.y+graphic_context[n]->affine.tx;
03093 primitive_info[i].point.y=graphic_context[n]->affine.rx*point.x+
03094 graphic_context[n]->affine.sy*point.y+graphic_context[n]->affine.ty;
03095 point=primitive_info[i].point;
03096 if (point.x < graphic_context[n]->bounds.x1)
03097 graphic_context[n]->bounds.x1=point.x;
03098 if (point.y < graphic_context[n]->bounds.y1)
03099 graphic_context[n]->bounds.y1=point.y;
03100 if (point.x > graphic_context[n]->bounds.x2)
03101 graphic_context[n]->bounds.x2=point.x;
03102 if (point.y > graphic_context[n]->bounds.y2)
03103 graphic_context[n]->bounds.y2=point.y;
03104 if (primitive_info[i].primitive == ImagePrimitive)
03105 break;
03106 }
03107 if (i >= (long) number_points)
03108 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
03109 if (graphic_context[n]->render != MagickFalse)
03110 {
03111 if ((n != 0) && (graphic_context[n]->clip_mask != (char *) NULL) &&
03112 (LocaleCompare(graphic_context[n]->clip_mask,
03113 graphic_context[n-1]->clip_mask) != 0))
03114 (void) DrawClipPath(image,graphic_context[n],
03115 graphic_context[n]->clip_mask);
03116 (void) DrawPrimitive(image,graphic_context[n],primitive_info);
03117 }
03118 if (primitive_info->text != (char *) NULL)
03119 primitive_info->text=(char *) RelinquishMagickMemory(
03120 primitive_info->text);
03121 proceed=SetImageProgress(image,RenderImageTag,q-primitive,(MagickSizeType)
03122 primitive_extent);
03123 if (proceed == MagickFalse)
03124 break;
03125 }
03126 if (image->debug != MagickFalse)
03127 (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end draw-image");
03128
03129
03130
03131 token=DestroyString(token);
03132 if (primitive_info != (PrimitiveInfo *) NULL)
03133 primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
03134 primitive=DestroyString(primitive);
03135 for ( ; n >= 0; n--)
03136 graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
03137 graphic_context=(DrawInfo **) RelinquishMagickMemory(graphic_context);
03138 if (status == MagickFalse)
03139 ThrowBinaryException(DrawError,"NonconformingDrawingPrimitiveDefinition",
03140 keyword);
03141 return(status);
03142 }
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155
03156
03157
03158
03159
03160
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170 static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
03171 const long x,const long y)
03172 {
03173 switch (gradient->type)
03174 {
03175 case UndefinedGradient:
03176 case LinearGradient:
03177 {
03178 MagickRealType
03179 gamma,
03180 length,
03181 offset,
03182 scale;
03183
03184 PointInfo
03185 p,
03186 q;
03187
03188 const SegmentInfo
03189 *gradient_vector;
03190
03191 gradient_vector=(&gradient->gradient_vector);
03192 p.x=gradient_vector->x2-gradient_vector->x1;
03193 p.y=gradient_vector->y2-gradient_vector->y1;
03194 q.x=(double) x-gradient_vector->x1;
03195 q.y=(double) y-gradient_vector->y1;
03196 length=sqrt(q.x*q.x+q.y*q.y);
03197 gamma=sqrt(p.x*p.x+p.y*p.y)*length;
03198 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
03199 scale=p.x*q.x+p.y*q.y;
03200 offset=gamma*scale*length;
03201 return(offset);
03202 }
03203 case RadialGradient:
03204 {
03205 MagickRealType
03206 length,
03207 offset;
03208
03209 PointInfo
03210 v;
03211
03212 v.x=(double) x-gradient->center.x;
03213 v.y=(double) y-gradient->center.y;
03214 length=sqrt(v.x*v.x+v.y*v.y);
03215 if (gradient->spread == RepeatSpread)
03216 return(length);
03217 offset=length/gradient->radius;
03218 return(offset);
03219 }
03220 }
03221 return(0.0);
03222 }
03223
03224 MagickExport MagickBooleanType DrawGradientImage(Image *image,
03225 const DrawInfo *draw_info)
03226 {
03227 const GradientInfo
03228 *gradient;
03229
03230 const SegmentInfo
03231 *gradient_vector;
03232
03233 ExceptionInfo
03234 *exception;
03235
03236 long
03237 y;
03238
03239 MagickBooleanType
03240 status;
03241
03242 MagickPixelPacket
03243 zero;
03244
03245 MagickRealType
03246 length;
03247
03248 PointInfo
03249 point;
03250
03251 RectangleInfo
03252 bounding_box;
03253
03254 CacheView
03255 *image_view;
03256
03257
03258
03259
03260 assert(image != (Image *) NULL);
03261 assert(image->signature == MagickSignature);
03262 if (image->debug != MagickFalse)
03263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03264 assert(draw_info != (const DrawInfo *) NULL);
03265 gradient=(&draw_info->gradient);
03266 gradient_vector=(&gradient->gradient_vector);
03267 point.x=gradient_vector->x2-gradient_vector->x1;
03268 point.y=gradient_vector->y2-gradient_vector->y1;
03269 length=sqrt(point.x*point.x+point.y*point.y);
03270 bounding_box=gradient->bounding_box;
03271 status=MagickTrue;
03272 exception=(&image->exception);
03273 GetMagickPixelPacket(image,&zero);
03274 image_view=AcquireCacheView(image);
03275 #if defined(MAGICKCORE_OPENMP_SUPPORT)
03276 #pragma omp parallel for schedule(dynamic,4) shared(status)
03277 #endif
03278 for (y=bounding_box.y; y < (long) bounding_box.height; y++)
03279 {
03280 long
03281 j;
03282
03283 MagickPixelPacket
03284 composite,
03285 pixel;
03286
03287 MagickRealType
03288 alpha,
03289 offset;
03290
03291 register IndexPacket
03292 *__restrict indexes;
03293
03294 register long
03295 i,
03296 x;
03297
03298 register PixelPacket
03299 *__restrict q;
03300
03301 if (status == MagickFalse)
03302 continue;
03303 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
03304 if (q == (PixelPacket *) NULL)
03305 {
03306 status=MagickFalse;
03307 continue;
03308 }
03309 indexes=GetCacheViewAuthenticIndexQueue(image_view);
03310 pixel=zero;
03311 composite=zero;
03312 offset=GetStopColorOffset(gradient,0,y);
03313 if (gradient->type != RadialGradient)
03314 offset/=length;
03315 for (x=bounding_box.x; x < (long) bounding_box.width; x++)
03316 {
03317 SetMagickPixelPacket(image,q,indexes+x,&pixel);
03318 switch (gradient->spread)
03319 {
03320 case UndefinedSpread:
03321 case PadSpread:
03322 {
03323 if ((x != (long) (gradient_vector->x1+0.5)) ||
03324 (y != (long) (gradient_vector->y1+0.5)))
03325 {
03326 offset=GetStopColorOffset(gradient,x,y);
03327 if (gradient->type != RadialGradient)
03328 offset/=length;
03329 }
03330 for (i=0; i < (long) gradient->number_stops; i++)
03331 if (offset < gradient->stops[i].offset)
03332 break;
03333 if ((offset < 0.0) || (i == 0))
03334 composite=gradient->stops[0].color;
03335 else
03336 if ((offset > 1.0) || (i == (long) gradient->number_stops))
03337 composite=gradient->stops[gradient->number_stops-1].color;
03338 else
03339 {
03340 j=i;
03341 i--;
03342 alpha=(offset-gradient->stops[i].offset)/
03343 (gradient->stops[j].offset-gradient->stops[i].offset);
03344 MagickPixelCompositeBlend(&gradient->stops[i].color,1.0-alpha,
03345 &gradient->stops[j].color,alpha,&composite);
03346 }
03347 break;
03348 }
03349 case ReflectSpread:
03350 {
03351 if ((x != (long) (gradient_vector->x1+0.5)) ||
03352 (y != (long) (gradient_vector->y1+0.5)))
03353 {
03354 offset=GetStopColorOffset(gradient,x,y);
03355 if (gradient->type != RadialGradient)
03356 offset/=length;
03357 }
03358 if (offset < 0.0)
03359 offset=(-offset);
03360 if ((long) fmod(offset,2.0) == 0)
03361 offset=fmod(offset,1.0);
03362 else
03363 offset=1.0-fmod(offset,1.0);
03364 for (i=0; i < (long) gradient->number_stops; i++)
03365 if (offset < gradient->stops[i].offset)
03366 break;
03367 if (i == 0)
03368 composite=gradient->stops[0].color;
03369 else
03370 if (i == (long) gradient->number_stops)
03371 composite=gradient->stops[gradient->number_stops-1].color;
03372 else
03373 {
03374 j=i;
03375 i--;
03376 alpha=(offset-gradient->stops[i].offset)/
03377 (gradient->stops[j].offset-gradient->stops[i].offset);
03378 MagickPixelCompositeBlend(&gradient->stops[i].color,1.0-alpha,
03379 &gradient->stops[j].color,alpha,&composite);
03380 }
03381 break;
03382 }
03383 case RepeatSpread:
03384 {
03385 MagickBooleanType
03386 antialias;
03387
03388 MagickRealType
03389 repeat;
03390
03391 antialias=MagickFalse;
03392 repeat=0.0;
03393 if ((x != (long) (gradient_vector->x1+0.5)) ||
03394 (y != (long) (gradient_vector->y1+0.5)))
03395 {
03396 offset=GetStopColorOffset(gradient,x,y);
03397 if (gradient->type == LinearGradient)
03398 {
03399 repeat=fmod(offset,length);
03400 if (repeat < 0.0)
03401 repeat=length-fmod(-repeat,length);
03402 else
03403 repeat=fmod(offset,length);
03404 antialias=(repeat < length) && ((repeat+1.0) > length) ?
03405 MagickTrue : MagickFalse;
03406 offset=repeat/length;
03407 }
03408 else
03409 {
03410 repeat=fmod(offset,gradient->radius);
03411 if (repeat < 0.0)
03412 repeat=gradient->radius-fmod(-repeat,gradient->radius);
03413 else
03414 repeat=fmod(offset,gradient->radius);
03415 antialias=repeat+1.0 > gradient->radius ?
03416 MagickTrue : MagickFalse;
03417 offset=repeat/gradient->radius;
03418 }
03419 }
03420 for (i=0; i < (long) gradient->number_stops; i++)
03421 if (offset < gradient->stops[i].offset)
03422 break;
03423 if (i == 0)
03424 composite=gradient->stops[0].color;
03425 else
03426 if (i == (long) gradient->number_stops)
03427 composite=gradient->stops[gradient->number_stops-1].color;
03428 else
03429 {
03430 j=i;
03431 i--;
03432 alpha=(offset-gradient->stops[i].offset)/
03433 (gradient->stops[j].offset-gradient->stops[i].offset);
03434 if (antialias != MagickFalse)
03435 {
03436 if (gradient->type == LinearGradient)
03437 alpha=length-repeat;
03438 else
03439 alpha=gradient->radius-repeat;
03440 i=0;
03441 j=(long) gradient->number_stops-1L;
03442 }
03443 MagickPixelCompositeBlend(&gradient->stops[i].color,1.0-alpha,
03444 &gradient->stops[j].color,alpha,&composite);
03445 }
03446 break;
03447 }
03448 }
03449 MagickPixelCompositeOver(&composite,composite.opacity,&pixel,
03450 pixel.opacity,&pixel);
03451 SetPixelPacket(image,&pixel,q,indexes+x);
03452 q++;
03453 }
03454 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
03455 status=MagickFalse;
03456 }
03457 image_view=DestroyCacheView(image_view);
03458 return(status);
03459 }
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490 MagickExport MagickBooleanType DrawPatternPath(Image *image,
03491 const DrawInfo *draw_info,const char *name,Image **pattern)
03492 {
03493 char
03494 property[MaxTextExtent];
03495
03496 const char
03497 *geometry,
03498 *path;
03499
03500 DrawInfo
03501 *clone_info;
03502
03503 ImageInfo
03504 *image_info;
03505
03506 MagickBooleanType
03507 status;
03508
03509 assert(image != (Image *) NULL);
03510 assert(image->signature == MagickSignature);
03511 if (image->debug != MagickFalse)
03512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03513 assert(draw_info != (const DrawInfo *) NULL);
03514 assert(name != (const char *) NULL);
03515 (void) FormatMagickString(property,MaxTextExtent,"%s",name);
03516 path=GetImageArtifact(image,property);
03517 if (path == (const char *) NULL)
03518 return(MagickFalse);
03519 (void) FormatMagickString(property,MaxTextExtent,"%s-geometry",name);
03520 geometry=GetImageArtifact(image,property);
03521 if (geometry == (const char *) NULL)
03522 return(MagickFalse);
03523 if ((*pattern) != (Image *) NULL)
03524 *pattern=DestroyImage(*pattern);
03525 image_info=AcquireImageInfo();
03526 image_info->size=AcquireString(geometry);
03527 *pattern=AcquireImage(image_info);
03528 image_info=DestroyImageInfo(image_info);
03529 (void) QueryColorDatabase("#00000000",&(*pattern)->background_color,
03530 &image->exception);
03531 (void) SetImageBackgroundColor(*pattern);
03532 if (image->debug != MagickFalse)
03533 (void) LogMagickEvent(DrawEvent,GetMagickModule(),
03534 "begin pattern-path %s %s",name,geometry);
03535 clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
03536 clone_info->fill_pattern=NewImageList();
03537 clone_info->stroke_pattern=NewImageList();
03538 (void) CloneString(&clone_info->primitive,path);
03539 status=DrawImage(*pattern,clone_info);
03540 clone_info=DestroyDrawInfo(clone_info);
03541 if (image->debug != MagickFalse)
03542 (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end pattern-path");
03543 return(status);
03544 }
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573
03574 static PolygonInfo **DestroyPolygonThreadSet(PolygonInfo **polygon_info)
03575 {
03576 register long
03577 i;
03578
03579 assert(polygon_info != (PolygonInfo **) NULL);
03580 for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
03581 if (polygon_info[i] != (PolygonInfo *) NULL)
03582 polygon_info[i]=DestroyPolygonInfo(polygon_info[i]);
03583 polygon_info=(PolygonInfo **) RelinquishAlignedMemory(polygon_info);
03584 return(polygon_info);
03585 }
03586
03587 static PolygonInfo **AcquirePolygonThreadSet(const DrawInfo *draw_info,
03588 const PrimitiveInfo *primitive_info)
03589 {
03590 PathInfo
03591 *path_info;
03592
03593 register long
03594 i;
03595
03596 PolygonInfo
03597 **polygon_info;
03598
03599 unsigned long
03600 number_threads;
03601
03602 number_threads=GetOpenMPMaximumThreads();
03603 polygon_info=(PolygonInfo **) AcquireAlignedMemory(number_threads,
03604 sizeof(*polygon_info));
03605 if (polygon_info == (PolygonInfo **) NULL)
03606 return((PolygonInfo **) NULL);
03607 (void) ResetMagickMemory(polygon_info,0,GetOpenMPMaximumThreads()*
03608 sizeof(*polygon_info));
03609 path_info=ConvertPrimitiveToPath(draw_info,primitive_info);
03610 if (path_info == (PathInfo *) NULL)
03611 return(DestroyPolygonThreadSet(polygon_info));
03612 for (i=0; i < (long) number_threads; i++)
03613 {
03614 polygon_info[i]=ConvertPathToPolygon(draw_info,path_info);
03615 if (polygon_info[i] == (PolygonInfo *) NULL)
03616 return(DestroyPolygonThreadSet(polygon_info));
03617 }
03618 path_info=(PathInfo *) RelinquishMagickMemory(path_info);
03619 return(polygon_info);
03620 }
03621
03622 static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
03623 const MagickRealType mid,const MagickBooleanType fill,
03624 const FillRule fill_rule,const long x,const long y,
03625 MagickRealType *stroke_opacity)
03626 {
03627 int
03628 winding_number;
03629
03630 long
03631 j;
03632
03633 MagickRealType
03634 alpha,
03635 beta,
03636 distance,
03637 subpath_opacity;
03638
03639 PointInfo
03640 delta;
03641
03642 register EdgeInfo
03643 *p;
03644
03645 register const PointInfo
03646 *q;
03647
03648 register long
03649 i;
03650
03651
03652
03653
03654 *stroke_opacity=0.0;
03655 subpath_opacity=0.0;
03656 p=polygon_info->edges;
03657 for (j=0; j < (long) polygon_info->number_edges; j++, p++)
03658 {
03659 if (y <= (p->bounds.y1-mid-0.5))
03660 break;
03661 if (y > (p->bounds.y2+mid+0.5))
03662 {
03663 (void) DestroyEdge(polygon_info,j);
03664 continue;
03665 }
03666 if ((x <= (p->bounds.x1-mid-0.5)) || (x > (p->bounds.x2+mid+0.5)))
03667 continue;
03668 for (i=MagickMax(p->highwater,1); i < (long) p->number_points; i++)
03669 {
03670 if (y <= (p->points[i-1].y-mid-0.5))
03671 break;
03672 if (y > (p->points[i].y+mid+0.5))
03673 continue;
03674 if (p->scanline != y)
03675 {
03676 p->scanline=y;
03677 p->highwater=i;
03678 }
03679
03680
03681
03682 q=p->points+i-1;
03683 delta.x=(q+1)->x-q->x;
03684 delta.y=(q+1)->y-q->y;
03685 beta=delta.x*(x-q->x)+delta.y*(y-q->y);
03686 if (beta < 0.0)
03687 {
03688 delta.x=x-q->x;
03689 delta.y=y-q->y;
03690 distance=delta.x*delta.x+delta.y*delta.y;
03691 }
03692 else
03693 {
03694 alpha=delta.x*delta.x+delta.y*delta.y;
03695 if (beta > alpha)
03696 {
03697 delta.x=x-(q+1)->x;
03698 delta.y=y-(q+1)->y;
03699 distance=delta.x*delta.x+delta.y*delta.y;
03700 }
03701 else
03702 {
03703 alpha=1.0/alpha;
03704 beta=delta.x*(y-q->y)-delta.y*(x-q->x);
03705 distance=alpha*beta*beta;
03706 }
03707 }
03708
03709
03710
03711 beta=0.0;
03712 if (p->ghostline == MagickFalse)
03713 {
03714 alpha=mid+0.5;
03715 if ((*stroke_opacity < 1.0) &&
03716 (distance <= ((alpha+0.25)*(alpha+0.25))))
03717 {
03718 alpha=mid-0.5;
03719 if (distance <= ((alpha+0.25)*(alpha+0.25)))
03720 *stroke_opacity=1.0;
03721 else
03722 {
03723 beta=1.0;
03724 if (distance != 1.0)
03725 beta=sqrt((double) distance);
03726 alpha=beta-mid-0.5;
03727 if (*stroke_opacity < ((alpha-0.25)*(alpha-0.25)))
03728 *stroke_opacity=(alpha-0.25)*(alpha-0.25);
03729 }
03730 }
03731 }
03732 if ((fill == MagickFalse) || (distance > 1.0) || (subpath_opacity >= 1.0))
03733 continue;
03734 if (distance <= 0.0)
03735 {
03736 subpath_opacity=1.0;
03737 continue;
03738 }
03739 if (distance > 1.0)
03740 continue;
03741 if (beta == 0.0)
03742 {
03743 beta=1.0;
03744 if (distance != 1.0)
03745 beta=sqrt(distance);
03746 }
03747 alpha=beta-1.0;
03748 if (subpath_opacity < (alpha*alpha))
03749 subpath_opacity=alpha*alpha;
03750 }
03751 }
03752
03753
03754
03755 if (fill == MagickFalse)
03756 return(0.0);
03757 if (subpath_opacity >= 1.0)
03758 return(1.0);
03759
03760
03761
03762 winding_number=0;
03763 p=polygon_info->edges;
03764 for (j=0; j < (long) polygon_info->number_edges; j++, p++)
03765 {
03766 if (y <= p->bounds.y1)
03767 break;
03768 if ((y > p->bounds.y2) || (x <= p->bounds.x1))
03769 continue;
03770 if (x > p->bounds.x2)
03771 {
03772 winding_number+=p->direction ? 1 : -1;
03773 continue;
03774 }
03775 for (i=MagickMax(p->highwater,1); i < (long) p->number_points; i++)
03776 if (y <= p->points[i].y)
03777 break;
03778 q=p->points+i-1;
03779 if ((((q+1)->x-q->x)*(y-q->y)) <= (((q+1)->y-q->y)*(x-q->x)))
03780 winding_number+=p->direction ? 1 : -1;
03781 }
03782 if (fill_rule != NonZeroRule)
03783 {
03784 if ((MagickAbsoluteValue(winding_number) & 0x01) != 0)
03785 return(1.0);
03786 }
03787 else
03788 if (MagickAbsoluteValue(winding_number) != 0)
03789 return(1.0);
03790 return(subpath_opacity);
03791 }
03792
03793 static MagickBooleanType DrawPolygonPrimitive(Image *image,
03794 const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
03795 {
03796 ExceptionInfo
03797 *exception;
03798
03799 long
03800 start,
03801 stop,
03802 y;
03803
03804 MagickBooleanType
03805 fill,
03806 status;
03807
03808 MagickRealType
03809 mid;
03810
03811 PolygonInfo
03812 **polygon_info;
03813
03814 register EdgeInfo
03815 *p;
03816
03817 register long
03818 i;
03819
03820 SegmentInfo
03821 bounds;
03822
03823 CacheView
03824 *image_view;
03825
03826
03827
03828
03829 assert(image != (Image *) NULL);
03830 assert(image->signature == MagickSignature);
03831 if (image->debug != MagickFalse)
03832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03833 assert(draw_info != (DrawInfo *) NULL);
03834 assert(draw_info->signature == MagickSignature);
03835 assert(primitive_info != (PrimitiveInfo *) NULL);
03836 if (primitive_info->coordinates == 0)
03837 return(MagickTrue);
03838 polygon_info=AcquirePolygonThreadSet(draw_info,primitive_info);
03839 if (polygon_info == (PolygonInfo **) NULL)
03840 return(MagickFalse);
03841 if (0)
03842 DrawBoundingRectangles(image,draw_info,polygon_info[0]);
03843 if (image->debug != MagickFalse)
03844 (void) LogMagickEvent(DrawEvent,GetMagickModule()," begin draw-polygon");
03845 fill=(primitive_info->method == FillToBorderMethod) ||
03846 (primitive_info->method == FloodfillMethod) ?