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