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-2008 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 "magick/studio.h"
00049 #include "magick/annotate.h"
00050 #include "magick/artifact.h"
00051 #include "magick/blob.h"
00052 #include "magick/cache.h"
00053 #include "magick/cache-view.h"
00054 #include "magick/color.h"
00055 #include "magick/composite.h"
00056 #include "magick/composite-private.h"
00057 #include "magick/constitute.h"
00058 #include "magick/draw.h"
00059 #include "magick/draw-private.h"
00060 #include "magick/enhance.h"
00061 #include "magick/exception.h"
00062 #include "magick/exception-private.h"
00063 #include "magick/gem.h"
00064 #include "magick/geometry.h"
00065 #include "magick/image-private.h"
00066 #include "magick/list.h"
00067 #include "magick/log.h"
00068 #include "magick/monitor.h"
00069 #include "magick/monitor-private.h"
00070 #include "magick/option.h"
00071 #include "magick/paint.h"
00072 #include "magick/pixel-private.h"
00073 #include "magick/property.h"
00074 #include "magick/resample.h"
00075 #include "magick/resample-private.h"
00076 #include "magick/string_.h"
00077 #include "magick/token.h"
00078 #include "magick/transform.h"
00079 #include "magick/utility.h"
00080 
00081 /*
00082   Define declarations.
00083 */
00084 #define BezierQuantum  200
00085 
00086 /*
00087   Typedef declarations.
00088 */
00089 typedef struct _EdgeInfo
00090 {
00091   SegmentInfo
00092     bounds;
00093 
00094   MagickRealType
00095     scanline;
00096 
00097   PointInfo
00098     *points;
00099 
00100   unsigned long
00101     number_points;
00102 
00103   long
00104     direction;
00105 
00106   MagickBooleanType
00107     ghostline;
00108 
00109   unsigned long
00110     highwater;
00111 } EdgeInfo;
00112 
00113 typedef struct _ElementInfo
00114 {
00115   MagickRealType
00116     cx,
00117     cy,
00118     major,
00119     minor,
00120     angle;
00121 } ElementInfo;
00122 
00123 typedef struct _PolygonInfo
00124 {
00125   EdgeInfo
00126     *edges;
00127 
00128   unsigned long
00129     number_edges;
00130 } PolygonInfo;
00131 
00132 typedef enum
00133 {
00134   MoveToCode,
00135   OpenCode,
00136   GhostlineCode,
00137   LineToCode,
00138   EndCode
00139 } PathInfoCode;
00140 
00141 typedef struct _PathInfo
00142 {
00143   PointInfo
00144     point;
00145 
00146   PathInfoCode
00147     code;
00148 } PathInfo;
00149 
00150 /*
00151   Forward declarations.
00152 */
00153 static MagickBooleanType
00154   DrawPrimitive(Image *,const DrawInfo *,const PrimitiveInfo *),
00155   DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *);
00156 
00157 static PrimitiveInfo
00158   *TraceStrokePolygon(const DrawInfo *,const PrimitiveInfo *);
00159 
00160 static unsigned long
00161   TracePath(PrimitiveInfo *,const char *);
00162 
00163 static void
00164   TraceArc(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
00165   TraceArcPath(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo,
00166     const MagickRealType,const MagickBooleanType,const MagickBooleanType),
00167   TraceBezier(PrimitiveInfo *,const unsigned long),
00168   TraceCircle(PrimitiveInfo *,const PointInfo,const PointInfo),
00169   TraceEllipse(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
00170   TraceLine(PrimitiveInfo *,const PointInfo,const PointInfo),
00171   TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo),
00172   TraceRoundRectangle(PrimitiveInfo *,const PointInfo,const PointInfo,
00173     PointInfo),
00174   TraceSquareLinecap(PrimitiveInfo *,const unsigned long,const MagickRealType);
00175 
00176 /*
00177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00178 %                                                                             %
00179 %                                                                             %
00180 %                                                                             %
00181 %   A c q u i r e D r a w I n f o                                             %
00182 %                                                                             %
00183 %                                                                             %
00184 %                                                                             %
00185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00186 %
00187 %  AcquireDrawInfo() returns a DrawInfo structure properly initialized.
00188 %
00189 %  The format of the AcquireDrawInfo method is:
00190 %
00191 %      DrawInfo *AcquireDrawInfo(void)
00192 %
00193 */
00194 MagickExport DrawInfo *AcquireDrawInfo(void)
00195 {
00196   DrawInfo
00197     *draw_info;
00198 
00199   draw_info=(DrawInfo *) AcquireMagickMemory(sizeof(*draw_info));
00200   if (draw_info == (DrawInfo *) NULL)
00201     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00202   GetDrawInfo((ImageInfo *) NULL,draw_info);
00203   return(draw_info);
00204 }
00205 
00206 /*
00207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00208 %                                                                             %
00209 %                                                                             %
00210 %                                                                             %
00211 %   C l o n e D r a w I n f o                                                 %
00212 %                                                                             %
00213 %                                                                             %
00214 %                                                                             %
00215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00216 %
00217 %  CloneDrawInfo() makes a copy of the given draw info structure.  If NULL
00218 %  is specified, a new image info structure is created initialized to
00219 %  default values.
00220 %
00221 %  The format of the CloneDrawInfo method is:
00222 %
00223 %      DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
00224 %        const DrawInfo *draw_info)
00225 %
00226 %  A description of each parameter follows:
00227 %
00228 %    o image_info: the image info.
00229 %
00230 %    o draw_info: the draw info.
00231 %
00232 */
00233 MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
00234   const DrawInfo *draw_info)
00235 {
00236   DrawInfo
00237     *clone_info;
00238 
00239   clone_info=(DrawInfo *) AcquireMagickMemory(sizeof(*clone_info));
00240   if (clone_info == (DrawInfo *) NULL)
00241     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00242   GetDrawInfo(image_info,clone_info);
00243   if (draw_info == (DrawInfo *) NULL)
00244     return(clone_info);
00245   if (clone_info->primitive != (char *) NULL)
00246     (void) CloneString(&clone_info->primitive,draw_info->primitive);
00247   if (draw_info->geometry != (char *) NULL)
00248     (void) CloneString(&clone_info->geometry,draw_info->geometry);
00249   clone_info->viewbox=draw_info->viewbox;
00250   clone_info->affine=draw_info->affine;
00251   clone_info->gravity=draw_info->gravity;
00252   clone_info->fill=draw_info->fill;
00253   clone_info->stroke=draw_info->stroke;
00254   clone_info->stroke_width=draw_info->stroke_width;
00255   if (draw_info->fill_pattern != (Image *) NULL)
00256     clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue,
00257       &draw_info->fill_pattern->exception);
00258   else
00259     if (draw_info->tile != (Image *) NULL)
00260       clone_info->fill_pattern=CloneImage(draw_info->tile,0,0,MagickTrue,
00261         &draw_info->tile->exception);
00262   clone_info->tile=NewImageList();  /* tile is deprecated */
00263   if (draw_info->stroke_pattern != (Image *) NULL)
00264     clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0,
00265       MagickTrue,&draw_info->stroke_pattern->exception);
00266   clone_info->stroke_antialias=draw_info->stroke_antialias;
00267   clone_info->text_antialias=draw_info->text_antialias;
00268   clone_info->fill_rule=draw_info->fill_rule;
00269   clone_info->linecap=draw_info->linecap;
00270   clone_info->linejoin=draw_info->linejoin;
00271   clone_info->miterlimit=draw_info->miterlimit;
00272   clone_info->dash_offset=draw_info->dash_offset;
00273   clone_info->decorate=draw_info->decorate;
00274   clone_info->compose=draw_info->compose;
00275   if (draw_info->text != (char *) NULL)
00276     (void) CloneString(&clone_info->text,draw_info->text);
00277   if (draw_info->font != (char *) NULL)
00278     (void) CloneString(&clone_info->font,draw_info->font);
00279   if (draw_info->metrics != (char *) NULL)
00280     (void) CloneString(&clone_info->metrics,draw_info->metrics);
00281   if (draw_info->family != (char *) NULL)
00282     (void) CloneString(&clone_info->family,draw_info->family);
00283   clone_info->style=draw_info->style;
00284   clone_info->stretch=draw_info->stretch;
00285   clone_info->weight=draw_info->weight;
00286   if (draw_info->encoding != (char *) NULL)
00287     (void) CloneString(&clone_info->encoding,draw_info->encoding);
00288   clone_info->pointsize=draw_info->pointsize;
00289   if (draw_info->density != (char *) NULL)
00290     (void) CloneString(&clone_info->density,draw_info->density);
00291   clone_info->align=draw_info->align;
00292   clone_info->undercolor=draw_info->undercolor;
00293   clone_info->border_color=draw_info->border_color;
00294   if (draw_info->server_name != (char *) NULL)
00295     (void) CloneString(&clone_info->server_name,draw_info->server_name);
00296   if (draw_info->dash_pattern != (double *) NULL)
00297     {
00298       register long
00299         x;
00300 
00301       for (x=0; draw_info->dash_pattern[x] != 0.0; x++) ;
00302       clone_info->dash_pattern=(double *) AcquireQuantumMemory((size_t) x+1UL,
00303         sizeof(*clone_info->dash_pattern));
00304       if (clone_info->dash_pattern == (double *) NULL)
00305         ThrowFatalException(ResourceLimitFatalError,
00306           "UnableToAllocateDashPattern");
00307       (void) CopyMagickMemory(clone_info->dash_pattern,draw_info->dash_pattern,
00308         (size_t) (x+1)*sizeof(*clone_info->dash_pattern));
00309     }
00310   clone_info->gradient=draw_info->gradient;
00311   if (draw_info->gradient.stops != (StopInfo *) NULL)
00312     {
00313       unsigned long
00314         number_stops;
00315 
00316       number_stops=clone_info->gradient.number_stops;
00317       clone_info->gradient.stops=(StopInfo *) AcquireQuantumMemory((size_t)
00318         number_stops,sizeof(*clone_info->gradient.stops));
00319       if (clone_info->gradient.stops == (StopInfo *) NULL)
00320         ThrowFatalException(ResourceLimitFatalError,
00321           "UnableToAllocateDashPattern");
00322       (void) CopyMagickMemory(clone_info->gradient.stops,
00323         draw_info->gradient.stops,(size_t) number_stops*
00324         sizeof(*clone_info->gradient.stops));
00325     }
00326   if (draw_info->clip_mask != (char *) NULL)
00327     (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
00328   clone_info->bounds=draw_info->bounds;
00329   clone_info->clip_units=draw_info->clip_units;
00330   clone_info->render=draw_info->render;
00331   clone_info->opacity=draw_info->opacity;
00332   clone_info->element_reference=draw_info->element_reference;
00333   clone_info->debug=IsEventLogging();
00334   return(clone_info);
00335 }
00336 
00337 /*
00338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00339 %                                                                             %
00340 %                                                                             %
00341 %                                                                             %
00342 +   C o n v e r t P a t h T o P o l y g o n                                   %
00343 %                                                                             %
00344 %                                                                             %
00345 %                                                                             %
00346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00347 %
00348 %  ConvertPathToPolygon() converts a path to the more efficient sorted
00349 %  rendering form.
00350 %
00351 %  The format of the ConvertPathToPolygon method is:
00352 %
00353 %      PolygonInfo *ConvertPathToPolygon(const DrawInfo *draw_info,
00354 %        const PathInfo *path_info)
00355 %
00356 %  A description of each parameter follows:
00357 %
00358 %    o Method ConvertPathToPolygon returns the path in a more efficient sorted
00359 %      rendering form of type PolygonInfo.
00360 %
00361 %    o draw_info: Specifies a pointer to an DrawInfo structure.
00362 %
00363 %    o path_info: Specifies a pointer to an PathInfo structure.
00364 %
00365 %
00366 */
00367 
00368 #if defined(__cplusplus) || defined(c_plusplus)
00369 extern "C" {
00370 #endif
00371 
00372 static int CompareEdges(const void *x,const void *y)
00373 {
00374   register const EdgeInfo
00375     *p,
00376     *q;
00377 
00378   /*
00379     Compare two edges.
00380   */
00381   p=(const EdgeInfo *) x;
00382   q=(const EdgeInfo *) y;
00383   if ((p->points[0].y-MagickEpsilon) > q->points[0].y)
00384     return(1);
00385   if ((p->points[0].y+MagickEpsilon) < q->points[0].y)
00386     return(-1);
00387   if ((p->points[0].x-MagickEpsilon) > q->points[0].x)
00388     return(1);
00389   if ((p->points[0].x+MagickEpsilon) < q->points[0].x)
00390     return(-1);
00391   if (((p->points[1].x-p->points[0].x)*(q->points[1].y-q->points[0].y)-
00392        (p->points[1].y-p->points[0].y)*(q->points[1].x-q->points[0].x)) > 0.0)
00393     return(1);
00394   return(-1);
00395 }
00396 
00397 #if defined(__cplusplus) || defined(c_plusplus)
00398 }
00399 #endif
00400 
00401 static void LogPolygonInfo(const PolygonInfo *polygon_info)
00402 {
00403   register EdgeInfo
00404     *p;
00405 
00406   register long
00407     i,
00408     j;
00409 
00410   (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin active-edge");
00411   p=polygon_info->edges;
00412   for (i=0; i < (long) polygon_info->number_edges; i++)
00413   {
00414     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      edge %lu:",i);
00415     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      direction: %s",
00416       p->direction != MagickFalse ? "down" : "up");
00417     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      ghostline: %s",
00418       p->ghostline != MagickFalse ? "transparent" : "opaque");
00419     (void) LogMagickEvent(DrawEvent,GetMagickModule(),
00420       "      bounds: %g,%g - %g,%g",p->bounds.x1,p->bounds.y1,p->bounds.x2,
00421       p->bounds.y2);
00422     for (j=0; j < (long) p->number_points; j++)
00423       (void) LogMagickEvent(DrawEvent,GetMagickModule(),"        %g,%g",
00424         p->points[j].x,p->points[j].y);
00425     p++;
00426   }
00427   (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end active-edge");
00428 }
00429 
00430 static void ReversePoints(PointInfo *points,const unsigned long number_points)
00431 {
00432   PointInfo
00433     point;
00434 
00435   register long
00436     i;
00437 
00438   for (i=0; i < (long) (number_points >> 1); i++)
00439   {
00440     point=points[i];
00441     points[i]=points[number_points-(i+1)];
00442     points[number_points-(i+1)]=point;
00443   }
00444 }
00445 
00446 static PolygonInfo *ConvertPathToPolygon(
00447   const DrawInfo *magick_unused(draw_info),const PathInfo *path_info)
00448 {
00449   long
00450     direction,
00451     next_direction;
00452 
00453   PointInfo
00454     point,
00455     *points;
00456 
00457   PolygonInfo
00458     *polygon_info;
00459 
00460   SegmentInfo
00461     bounds;
00462 
00463   register long
00464     i,
00465     n;
00466 
00467   MagickBooleanType
00468     ghostline;
00469 
00470   unsigned long
00471     edge,
00472     number_edges,
00473     number_points;
00474 
00475   /*
00476     Convert a path to the more efficient sorted rendering form.
00477   */
00478   polygon_info=(PolygonInfo *) AcquireMagickMemory(sizeof(*polygon_info));
00479   if (polygon_info == (PolygonInfo *) NULL)
00480     return((PolygonInfo *) NULL);
00481   number_edges=16;
00482   polygon_info->edges=(EdgeInfo *) AcquireQuantumMemory((size_t) number_edges,
00483     sizeof(*polygon_info->edges));
00484   if (polygon_info->edges == (EdgeInfo *) NULL)
00485     return((PolygonInfo *) NULL);
00486   direction=0;
00487   edge=0;
00488   ghostline=MagickFalse;
00489   n=0;
00490   number_points=0;
00491   points=(PointInfo *) NULL;
00492   (void) ResetMagickMemory(&point,0,sizeof(point));
00493   (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
00494   for (i=0; path_info[i].code != EndCode; i++)
00495   {
00496     if ((path_info[i].code == MoveToCode) || (path_info[i].code == OpenCode) ||
00497         (path_info[i].code == GhostlineCode))
00498       {
00499         /*
00500           Move to.
00501         */
00502         if ((points != (PointInfo *) NULL) && (n >= 2))
00503           {
00504             if (edge == number_edges)
00505               {
00506                 number_edges<<=1;
00507                 polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00508                   polygon_info->edges,(size_t) number_edges,
00509                   sizeof(*polygon_info->edges));
00510                 if (polygon_info->edges == (EdgeInfo *) NULL)
00511                   return((PolygonInfo *) NULL);
00512               }
00513             polygon_info->edges[edge].number_points=(unsigned long) n;
00514             polygon_info->edges[edge].scanline=(-1.0);
00515             polygon_info->edges[edge].highwater=0;
00516             polygon_info->edges[edge].ghostline=ghostline;
00517             polygon_info->edges[edge].direction=(long) (direction > 0);
00518             if (direction < 0)
00519               ReversePoints(points,(unsigned long) n);
00520             polygon_info->edges[edge].points=points;
00521             polygon_info->edges[edge].bounds=bounds;
00522             polygon_info->edges[edge].bounds.y1=points[0].y;
00523             polygon_info->edges[edge].bounds.y2=points[n-1].y;
00524             points=(PointInfo *) NULL;
00525             ghostline=MagickFalse;
00526             edge++;
00527           }
00528         if (points == (PointInfo *) NULL)
00529           {
00530             number_points=16;
00531             points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
00532               sizeof(*points));
00533             if (points == (PointInfo *) NULL)
00534               return((PolygonInfo *) NULL);
00535           }
00536         ghostline=path_info[i].code == GhostlineCode ? MagickTrue : MagickFalse;
00537         point=path_info[i].point;
00538         points[0]=point;
00539         bounds.x1=point.x;
00540         bounds.x2=point.x;
00541         direction=0;
00542         n=1;
00543         continue;
00544       }
00545     /*
00546       Line to.
00547     */
00548     next_direction=((path_info[i].point.y > point.y) ||
00549       ((path_info[i].point.y == point.y) &&
00550        (path_info[i].point.x > point.x))) ? 1 : -1;
00551     if ((direction != 0) && (direction != next_direction))
00552       {
00553         /*
00554           New edge.
00555         */
00556         point=points[n-1];
00557         if (edge == number_edges)
00558           {
00559             number_edges<<=1;
00560             polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00561               polygon_info->edges,(size_t) number_edges,
00562               sizeof(*polygon_info->edges));
00563             if (polygon_info->edges == (EdgeInfo *) NULL)
00564               return((PolygonInfo *) NULL);
00565           }
00566         polygon_info->edges[edge].number_points=(unsigned long) n;
00567         polygon_info->edges[edge].scanline=(-1.0);
00568         polygon_info->edges[edge].highwater=0;
00569         polygon_info->edges[edge].ghostline=ghostline;
00570         polygon_info->edges[edge].direction=(long) (direction > 0);
00571         if (direction < 0)
00572           ReversePoints(points,(unsigned long) n);
00573         polygon_info->edges[edge].points=points;
00574         polygon_info->edges[edge].bounds=bounds;
00575         polygon_info->edges[edge].bounds.y1=points[0].y;
00576         polygon_info->edges[edge].bounds.y2=points[n-1].y;
00577         number_points=16;
00578         points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
00579           sizeof(*points));
00580         if (points == (PointInfo *) NULL)
00581           return((PolygonInfo *) NULL);
00582         n=1;
00583         ghostline=MagickFalse;
00584         points[0]=point;
00585         bounds.x1=point.x;
00586         bounds.x2=point.x;
00587         edge++;
00588       }
00589     direction=next_direction;
00590     if (points == (PointInfo *) NULL)
00591       continue;
00592     if (n == (long) number_points)
00593       {
00594         number_points<<=1;
00595         points=(PointInfo *) ResizeQuantumMemory(points,(size_t) number_points,
00596           sizeof(*points));
00597         if (points == (PointInfo *) NULL)
00598           return((PolygonInfo *) NULL);
00599       }
00600     point=path_info[i].point;
00601     points[n]=point;
00602     if (point.x < bounds.x1)
00603       bounds.x1=point.x;
00604     if (point.x > bounds.x2)
00605       bounds.x2=point.x;
00606     n++;
00607   }
00608   if (points != (PointInfo *) NULL)
00609     {
00610       if (n < 2)
00611         points=(PointInfo *) RelinquishMagickMemory(points);
00612       else
00613         {
00614           if (edge == number_edges)
00615             {
00616               number_edges<<=1;
00617               polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
00618                 polygon_info->edges,(size_t) number_edges,
00619                 sizeof(*polygon_info->edges));
00620               if (polygon_info->edges == (EdgeInfo *) NULL)
00621                 return((PolygonInfo *) NULL);
00622             }
00623           polygon_info->edges[edge].number_points=(unsigned long) n;
00624           polygon_info->edges[edge].scanline=(-1.0);
00625           polygon_info->edges[edge].highwater=0;
00626           polygon_info->edges[edge].ghostline=ghostline;
00627           polygon_info->edges[edge].direction=(long) (direction > 0);
00628           if (direction < 0)
00629             ReversePoints(points,(unsigned long) n);
00630           polygon_info->edges[edge].points=points;
00631           polygon_info->edges[edge].bounds=bounds;
00632           polygon_info->edges[edge].bounds.y1=points[0].y;
00633           polygon_info->edges[edge].bounds.y2=points[n-1].y;
00634           ghostline=MagickFalse;
00635           edge++;
00636         }
00637     }
00638   polygon_info->number_edges=edge;
00639   qsort(polygon_info->edges,(size_t) polygon_info->number_edges,
00640     sizeof(*polygon_info->edges),CompareEdges);
00641   if (IsEventLogging() != MagickFalse)
00642     LogPolygonInfo(polygon_info);
00643   return(polygon_info);
00644 }
00645 
00646 /*
00647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00648 %                                                                             %
00649 %                                                                             %
00650 %                                                                             %
00651 +   C o n v e r t P r i m i t i v e T o P a t h                               %
00652 %                                                                             %
00653 %                                                                             %
00654 %                                                                             %
00655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00656 %
00657 %  ConvertPrimitiveToPath() converts a PrimitiveInfo structure into a vector
00658 %  path structure.
00659 %
00660 %  The format of the ConvertPrimitiveToPath method is:
00661 %
00662 %      PathInfo *ConvertPrimitiveToPath(const DrawInfo *draw_info,
00663 %        const PrimitiveInfo *primitive_info)
00664 %
00665 %  A description of each parameter follows:
00666 %
00667 %    o Method ConvertPrimitiveToPath returns a vector path structure of type
00668 %      PathInfo.
00669 %
00670 %    o draw_info: a structure of type DrawInfo.
00671 %
00672 %    o primitive_info: Specifies a pointer to an PrimitiveInfo structure.
00673 %
00674 %
00675 */
00676 
00677 static void LogPathInfo(const PathInfo *path_info)
00678 {
00679   register const PathInfo
00680     *p;
00681 
00682   (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin vector-path");
00683   for (p=path_info; p->code != EndCode; p++)
00684     (void) LogMagickEvent(DrawEvent,GetMagickModule(),
00685       "      %g,%g %s",p->point.x,p->point.y,p->code == GhostlineCode ?
00686       "moveto ghostline" : p->code == OpenCode ? "moveto open" :
00687       p->code == MoveToCode ? "moveto" : p->code == LineToCode ? "lineto" :
00688       "?");
00689   (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end vector-path");
00690 }
00691 
00692 static PathInfo *ConvertPrimitiveToPath(
00693   const DrawInfo *magick_unused(draw_info),const PrimitiveInfo *primitive_info)
00694 {
00695   long
00696     coordinates,
00697     start;
00698 
00699   PathInfo
00700     *path_info;
00701 
00702   PathInfoCode
00703     code;
00704 
00705   PointInfo
00706     p,
00707     q;
00708 
00709   register long
00710     i,
00711     n;
00712 
00713   /*
00714     Converts a PrimitiveInfo structure into a vector path structure.
00715   */
00716   switch (primitive_info->primitive)
00717   {
00718     case PointPrimitive:
00719     case ColorPrimitive:
00720     case MattePrimitive:
00721     case TextPrimitive:
00722     case ImagePrimitive:
00723       return((PathInfo *) NULL);
00724     default:
00725       break;
00726   }
00727   for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
00728   path_info=(PathInfo *) AcquireQuantumMemory((size_t) (2UL*i+3UL),
00729     sizeof(*path_info));
00730   if (path_info == (PathInfo *) NULL)
00731     return((PathInfo *) NULL);
00732   coordinates=0;
00733   n=0;
00734   p.x=(-1.0);
00735   p.y=(-1.0);
00736   q.x=(-1.0);
00737   q.y=(-1.0);
00738   start=0;
00739   for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
00740   {
00741     code=LineToCode;
00742     if (coordinates <= 0)
00743       {
00744         coordinates=(long) primitive_info[i].coordinates;
00745         p=primitive_info[i].point;
00746         start=n;
00747         code=MoveToCode;
00748       }
00749     coordinates--;
00750     /*
00751       Eliminate duplicate points.
00752     */
00753     if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) > MagickEpsilon) ||
00754         (fabs(q.y-primitive_info[i].point.y) > MagickEpsilon))
00755       {
00756         path_info[n].code=code;
00757         path_info[n].point=primitive_info[i].point;
00758         q=primitive_info[i].point;
00759         n++;
00760       }
00761     if (coordinates > 0)
00762       continue;
00763     if ((fabs(p.x-primitive_info[i].point.x) <= MagickEpsilon) &&
00764         (fabs(p.y-primitive_info[i].point.y) <= MagickEpsilon))
00765       continue;
00766     /*
00767       Mark the p point as open if it does not match the q.
00768     */
00769     path_info[start].code=OpenCode;
00770     path_info[n].code=GhostlineCode;
00771     path_info[n].point=primitive_info[i].point;
00772     n++;
00773     path_info[n].code=LineToCode;
00774     path_info[n].point=p;
00775     n++;
00776   }
00777   path_info[n].code=EndCode;
00778   path_info[n].point.x=0.0;
00779   path_info[n].point.y=0.0;
00780   if (IsEventLogging() != MagickFalse)
00781     LogPathInfo(path_info);
00782   return(path_info);
00783 }
00784 
00785 /*
00786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00787 %                                                                             %
00788 %                                                                             %
00789 %                                                                             %
00790 %   D e s t r o y D r a w I n f o                                             %
00791 %                                                                             %
00792 %                                                                             %
00793 %                                                                             %
00794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00795 %
00796 %  DestroyDrawInfo() deallocates memory associated with an DrawInfo
00797 %  structure.
00798 %
00799 %  The format of the DestroyDrawInfo method is:
00800 %
00801 %      DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
00802 %
00803 %  A description of each parameter follows:
00804 %
00805 %    o draw_info: the draw info.
00806 %
00807 */
00808 MagickExport DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
00809 {
00810   if (draw_info->debug != MagickFalse)
00811     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00812   assert(draw_info != (DrawInfo *) NULL);
00813   assert(draw_info->signature == MagickSignature);
00814   if (draw_info->primitive != (char *) NULL)
00815     draw_info->primitive=DestroyString(draw_info->primitive);
00816   if (draw_info->text != (char *) NULL)
00817     draw_info->text=DestroyString(draw_info->text);
00818   if (draw_info->geometry != (char *) NULL)
00819     draw_info->geometry=DestroyString(draw_info->geometry);
00820   if (draw_info->tile != (Image *) NULL)
00821     draw_info->tile=DestroyImage(draw_info->tile);
00822   if (draw_info->fill_pattern != (Image *) NULL)
00823     draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
00824   if (draw_info->stroke_pattern != (Image *) NULL)
00825     draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
00826   if (draw_info->font != (char *) NULL)
00827     draw_info->font=DestroyString(draw_info->font);
00828   if (draw_info->metrics != (char *) NULL)
00829     draw_info->metrics=DestroyString(draw_info->metrics);
00830   if (draw_info->family != (char *) NULL)
00831     draw_info->family=DestroyString(draw_info->family);
00832   if (draw_info->encoding != (char *) NULL)
00833     draw_info->encoding=DestroyString(draw_info->encoding);
00834   if (draw_info->density != (char *) NULL)
00835     draw_info->density=DestroyString(draw_info->density);
00836   if (draw_info->server_name != (char *) NULL)
00837     draw_info->server_name=(char *)
00838      RelinquishMagickMemory(draw_info->server_name);
00839   if (draw_info->dash_pattern != (double *) NULL)
00840     draw_info->dash_pattern=(double *) RelinquishMagickMemory(
00841       draw_info->dash_pattern);
00842   if (draw_info->gradient.stops != (StopInfo *) NULL)
00843     draw_info->gr