]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/draw.c
(no commit message)
[imagemagick] / MagickCore / draw.c
index b22152da6c2c5d6245b80c1aa478e19e4a6de0da..fc792353bfc9f43393138072c97cf682a54b5481 100644 (file)
@@ -18,7 +18,7 @@
 %                                 July 1998                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -52,6 +52,7 @@
 #include "MagickCore/cache.h"
 #include "MagickCore/cache-view.h"
 #include "MagickCore/color.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/composite.h"
 #include "MagickCore/composite-private.h"
 #include "MagickCore/constitute.h"
 #include "MagickCore/option.h"
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel-accessor.h"
+#include "MagickCore/pixel-private.h"
 #include "MagickCore/property.h"
 #include "MagickCore/resample.h"
 #include "MagickCore/resample-private.h"
+#include "MagickCore/resource_.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/string-private.h"
 #include "MagickCore/thread-private.h"
@@ -93,7 +96,7 @@ typedef struct _EdgeInfo
   SegmentInfo
     bounds;
 
-  MagickRealType
+  double
     scanline;
 
   PointInfo
@@ -114,7 +117,7 @@ typedef struct _EdgeInfo
 
 typedef struct _ElementInfo
 {
-  MagickRealType
+  double
     cx,
     cy,
     major,
@@ -153,7 +156,8 @@ typedef struct _PathInfo
   Forward declarations.
 */
 static MagickBooleanType
-  DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *);
+  DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *,
+    ExceptionInfo *);
 
 static PrimitiveInfo
   *TraceStrokePolygon(const DrawInfo *,const PrimitiveInfo *);
@@ -164,7 +168,7 @@ static size_t
 static void
   TraceArc(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
   TraceArcPath(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo,
-    const MagickRealType,const MagickBooleanType,const MagickBooleanType),
+    const double,const MagickBooleanType,const MagickBooleanType),
   TraceBezier(PrimitiveInfo *,const size_t),
   TraceCircle(PrimitiveInfo *,const PointInfo,const PointInfo),
   TraceEllipse(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
@@ -172,7 +176,7 @@ static void
   TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo),
   TraceRoundRectangle(PrimitiveInfo *,const PointInfo,const PointInfo,
     PointInfo),
-  TraceSquareLinecap(PrimitiveInfo *,const size_t,const MagickRealType);
+  TraceSquareLinecap(PrimitiveInfo *,const size_t,const double);
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -216,8 +220,8 @@ MagickExport DrawInfo *AcquireDrawInfo(void)
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  CloneDrawInfo() makes a copy of the given draw_info structure.  If NULL
-%  is specified, a new draw_info structure is created initialized to
-%  default values, according to the given image_info.
+%  is specified, a new DrawInfo structure is created initialized to default
+%  values.
 %
 %  The format of the CloneDrawInfo method is:
 %
@@ -237,18 +241,18 @@ MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
   DrawInfo
     *clone_info;
 
+  ExceptionInfo
+    *exception;
+
   clone_info=(DrawInfo *) AcquireMagickMemory(sizeof(*clone_info));
   if (clone_info == (DrawInfo *) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
-
   GetDrawInfo(image_info,clone_info);
   if (draw_info == (DrawInfo *) NULL)
     return(clone_info);
-
-  if (clone_info->primitive != (char *) NULL)
-    (void) CloneString(&clone_info->primitive,draw_info->primitive);
-  if (draw_info->geometry != (char *) NULL)
-    (void) CloneString(&clone_info->geometry,draw_info->geometry);
+  exception=AcquireExceptionInfo();
+  (void) CloneString(&clone_info->primitive,draw_info->primitive);
+  (void) CloneString(&clone_info->geometry,draw_info->geometry);
   clone_info->viewbox=draw_info->viewbox;
   clone_info->affine=draw_info->affine;
   clone_info->gravity=draw_info->gravity;
@@ -257,10 +261,10 @@ MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
   clone_info->stroke_width=draw_info->stroke_width;
   if (draw_info->fill_pattern != (Image *) NULL)
     clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue,
-      &draw_info->fill_pattern->exception);
+      exception);
   if (draw_info->stroke_pattern != (Image *) NULL)
     clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0,
-      MagickTrue,&draw_info->stroke_pattern->exception);
+      MagickTrue,exception);
   clone_info->stroke_antialias=draw_info->stroke_antialias;
   clone_info->text_antialias=draw_info->text_antialias;
   clone_info->fill_rule=draw_info->fill_rule;
@@ -270,31 +274,24 @@ MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
   clone_info->dash_offset=draw_info->dash_offset;
   clone_info->decorate=draw_info->decorate;
   clone_info->compose=draw_info->compose;
-  if (draw_info->text != (char *) NULL)
-    (void) CloneString(&clone_info->text,draw_info->text);
-  if (draw_info->font != (char *) NULL)
-    (void) CloneString(&clone_info->font,draw_info->font);
-  if (draw_info->metrics != (char *) NULL)
-    (void) CloneString(&clone_info->metrics,draw_info->metrics);
-  if (draw_info->family != (char *) NULL)
-    (void) CloneString(&clone_info->family,draw_info->family);
+  (void) CloneString(&clone_info->text,draw_info->text);
+  (void) CloneString(&clone_info->font,draw_info->font);
+  (void) CloneString(&clone_info->metrics,draw_info->metrics);
+  (void) CloneString(&clone_info->family,draw_info->family);
   clone_info->style=draw_info->style;
   clone_info->stretch=draw_info->stretch;
   clone_info->weight=draw_info->weight;
-  if (draw_info->encoding != (char *) NULL)
-    (void) CloneString(&clone_info->encoding,draw_info->encoding);
+  (void) CloneString(&clone_info->encoding,draw_info->encoding);
   clone_info->pointsize=draw_info->pointsize;
   clone_info->kerning=draw_info->kerning;
   clone_info->interline_spacing=draw_info->interline_spacing;
   clone_info->interword_spacing=draw_info->interword_spacing;
   clone_info->direction=draw_info->direction;
-  if (draw_info->density != (char *) NULL)
-    (void) CloneString(&clone_info->density,draw_info->density);
+  (void) CloneString(&clone_info->density,draw_info->density);
   clone_info->align=draw_info->align;
   clone_info->undercolor=draw_info->undercolor;
   clone_info->border_color=draw_info->border_color;
-  if (draw_info->server_name != (char *) NULL)
-    (void) CloneString(&clone_info->server_name,draw_info->server_name);
+  (void) CloneString(&clone_info->server_name,draw_info->server_name);
   if (draw_info->dash_pattern != (double *) NULL)
     {
       register ssize_t
@@ -325,14 +322,14 @@ MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
         draw_info->gradient.stops,(size_t) number_stops*
         sizeof(*clone_info->gradient.stops));
     }
-  if (draw_info->clip_mask != (char *) NULL)
-    (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
+  (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
   clone_info->bounds=draw_info->bounds;
   clone_info->clip_units=draw_info->clip_units;
   clone_info->render=draw_info->render;
   clone_info->alpha=draw_info->alpha;
   clone_info->element_reference=draw_info->element_reference;
   clone_info->debug=IsEventLogging();
+  exception=DestroyExceptionInfo(exception);
   return(clone_info);
 }
 \f
@@ -753,8 +750,8 @@ static PathInfo *ConvertPrimitiveToPath(
     /*
       Eliminate duplicate points.
     */
-    if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) > MagickEpsilon) ||
-        (fabs(q.y-primitive_info[i].point.y) > MagickEpsilon))
+    if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) >= MagickEpsilon) ||
+        (fabs(q.y-primitive_info[i].point.y) >= MagickEpsilon))
       {
         path_info[n].code=code;
         path_info[n].point=primitive_info[i].point;
@@ -763,8 +760,8 @@ static PathInfo *ConvertPrimitiveToPath(
       }
     if (coordinates > 0)
       continue;
-    if ((fabs(p.x-primitive_info[i].point.x) <= MagickEpsilon) &&
-        (fabs(p.y-primitive_info[i].point.y) <= MagickEpsilon))
+    if ((fabs(p.x-primitive_info[i].point.x) < MagickEpsilon) &&
+        (fabs(p.y-primitive_info[i].point.y) < MagickEpsilon))
       continue;
     /*
       Mark the p point as open if it does not match the q.
@@ -938,7 +935,7 @@ static PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
 %  The format of the DrawAffineImage method is:
 %
 %      MagickBooleanType DrawAffineImage(Image *image,const Image *source,
-%        const AffineMatrix *affine)
+%        const AffineMatrix *affine,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -948,7 +945,10 @@ static PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
 %
 %    o affine: the affine transform.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
+
 static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
   const double y,const SegmentInfo *edge)
 {
@@ -970,14 +970,14 @@ static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
   inverse_edge.x2=edge->x2;
   inverse_edge.y2=edge->y2;
   z=affine->ry*y+affine->tx;
-  if (affine->sx > MagickEpsilon)
+  if (affine->sx >= MagickEpsilon)
     {
       intercept=(-z/affine->sx);
-      x=intercept+MagickEpsilon;
+      x=intercept;
       if (x > inverse_edge.x1)
         inverse_edge.x1=x;
       intercept=(-z+(double) image->columns)/affine->sx;
-      x=intercept-MagickEpsilon;
+      x=intercept;
       if (x < inverse_edge.x2)
         inverse_edge.x2=x;
     }
@@ -985,11 +985,11 @@ static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
     if (affine->sx < -MagickEpsilon)
       {
         intercept=(-z+(double) image->columns)/affine->sx;
-        x=intercept+MagickEpsilon;
+        x=intercept;
         if (x > inverse_edge.x1)
           inverse_edge.x1=x;
         intercept=(-z/affine->sx);
-        x=intercept-MagickEpsilon;
+        x=intercept;
         if (x < inverse_edge.x2)
           inverse_edge.x2=x;
       }
@@ -1003,14 +1003,14 @@ static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
     Determine top and bottom edges.
   */
   z=affine->sy*y+affine->ty;
-  if (affine->rx > MagickEpsilon)
+  if (affine->rx >= MagickEpsilon)
     {
       intercept=(-z/affine->rx);
-      x=intercept+MagickEpsilon;
+      x=intercept;
       if (x > inverse_edge.x1)
         inverse_edge.x1=x;
       intercept=(-z+(double) image->rows)/affine->rx;
-      x=intercept-MagickEpsilon;
+      x=intercept;
       if (x < inverse_edge.x2)
         inverse_edge.x2=x;
     }
@@ -1018,11 +1018,11 @@ static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
     if (affine->rx < -MagickEpsilon)
       {
         intercept=(-z+(double) image->rows)/affine->rx;
-        x=intercept+MagickEpsilon;
+        x=intercept;
         if (x > inverse_edge.x1)
           inverse_edge.x1=x;
         intercept=(-z/affine->rx);
-        x=intercept-MagickEpsilon;
+        x=intercept;
         if (x < inverse_edge.x2)
           inverse_edge.x2=x;
       }
@@ -1043,7 +1043,8 @@ static AffineMatrix InverseAffineMatrix(const AffineMatrix *affine)
   double
     determinant;
 
-  determinant=1.0/(affine->sx*affine->sy-affine->rx*affine->ry);
+  determinant=MagickEpsilonReciprocal(affine->sx*affine->sy-affine->rx*
+    affine->ry);
   inverse_affine.sx=determinant*affine->sy;
   inverse_affine.rx=determinant*(-affine->rx);
   inverse_affine.ry=determinant*(-affine->ry);
@@ -1077,7 +1078,7 @@ static inline double MagickMin(const double x,const double y)
 }
 
 MagickExport MagickBooleanType DrawAffineImage(Image *image,
-  const Image *source,const AffineMatrix *affine)
+  const Image *source,const AffineMatrix *affine,ExceptionInfo *exception)
 {
   AffineMatrix
     inverse_affine;
@@ -1086,9 +1087,6 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
     *image_view,
     *source_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
@@ -1107,7 +1105,15 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
   SegmentInfo
     edge;
 
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  size_t
+    height,
+    width;
+#endif
+
   ssize_t
+    start,
+    stop,
     y;
 
   /*
@@ -1150,7 +1156,6 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
   /*
     Affine transform image.
   */
-  exception=(&image->exception);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
   status=MagickTrue;
@@ -1160,12 +1165,19 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
   edge.y2=MagickMin(max.y,(double) image->rows-1.0);
   inverse_affine=InverseAffineMatrix(affine);
   GetPixelInfo(image,&zero);
-  image_view=AcquireCacheView(image);
-  source_view=AcquireCacheView(source);
+  start=(ssize_t) ceil(edge.y1-0.5);
+  stop=(ssize_t) floor(edge.y2+0.5);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+  height=(size_t) (floor(edge.y2+0.5)-ceil(edge.y1-0.5));
+  width=(size_t) (floor(edge.x2+0.5)-ceil(edge.x1-0.5));
 #endif
-  for (y=(ssize_t) ceil(edge.y1-0.5); y <= (ssize_t) floor(edge.y2+0.5); y++)
+  source_view=AcquireVirtualCacheView(source,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    dynamic_number_threads(image,width,height,1)
+#endif
+  for (y=start; y <= stop; y++)
   {
     PixelInfo
       composite,
@@ -1190,8 +1202,8 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
     if (inverse_edge.x2 < inverse_edge.x1)
       continue;
     q=GetCacheViewAuthenticPixels(image_view,(ssize_t) ceil(inverse_edge.x1-
-      0.5),y,(size_t) ((ssize_t) floor(inverse_edge.x2+0.5)-(ssize_t) floor(
-      inverse_edge.x1+0.5)+1),1,exception);
+      0.5),y,(size_t) ((ssize_t) floor(inverse_edge.x2+0.5)-(ssize_t) ceil(
+      inverse_edge.x1-0.5)),1,exception);
     if (q == (Quantum *) NULL)
       continue;
     pixel=zero;
@@ -1205,10 +1217,10 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
         inverse_affine.ty;
       (void) InterpolatePixelInfo(source,source_view,UndefinedInterpolatePixel,
         point.x,point.y,&pixel,exception);
-      SetPixelInfo(image,q,&composite);
+      GetPixelInfoPixel(image,q,&composite);
       CompositePixelInfoOver(&pixel,pixel.alpha,&composite,composite.alpha,
         &composite);
-      SetPixelPixelInfo(image,&composite,q);
+      SetPixelInfoPixel(image,&composite,q);
       x_offset++;
       q+=GetPixelChannels(image);
     }
@@ -1237,7 +1249,7 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
 %  The format of the DrawBoundingRectangles method is:
 %
 %      void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
-%        PolygonInfo *polygon_info)
+%        PolygonInfo *polygon_info,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1247,14 +1259,16 @@ MagickExport MagickBooleanType DrawAffineImage(Image *image,
 %
 %    o polygon_info: Specifies a pointer to a PolygonInfo structure.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
-  const PolygonInfo *polygon_info)
+  const PolygonInfo *polygon_info,ExceptionInfo *exception)
 {
   DrawInfo
     *clone_info;
 
-  MagickRealType
+  double
     mid;
 
   PointInfo
@@ -1276,7 +1290,7 @@ static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
 
   clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
   (void) QueryColorCompliance("#0000",AllCompliance,&clone_info->fill,
-    &image->exception);
+    exception);
   resolution.x=DefaultResolution;
   resolution.y=DefaultResolution;
   if (clone_info->density != (char *) NULL)
@@ -1329,10 +1343,10 @@ static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
       {
         if (polygon_info->edges[i].direction != 0)
           (void) QueryColorCompliance("red",AllCompliance,&clone_info->stroke,
-            &image->exception);
+            exception);
         else
           (void) QueryColorCompliance("green",AllCompliance,&clone_info->stroke,
-            &image->exception);
+            exception);
         start.x=(double) (polygon_info->edges[i].bounds.x1-mid);
         start.y=(double) (polygon_info->edges[i].bounds.y1-mid);
         end.x=(double) (polygon_info->edges[i].bounds.x2+mid);
@@ -1342,11 +1356,11 @@ static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
         primitive_info[0].method=ReplaceMethod;
         coordinates=(ssize_t) primitive_info[0].coordinates;
         primitive_info[coordinates].primitive=UndefinedPrimitive;
-        (void) DrawPrimitive(image,clone_info,primitive_info);
+        (void) DrawPrimitive(image,clone_info,primitive_info,exception);
       }
     }
   (void) QueryColorCompliance("blue",AllCompliance,&clone_info->stroke,
-    &image->exception);
+    exception);
   start.x=(double) (bounds.x1-mid);
   start.y=(double) (bounds.y1-mid);
   end.x=(double) (bounds.x2+mid);
@@ -1356,7 +1370,7 @@ static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
   primitive_info[0].method=ReplaceMethod;
   coordinates=(ssize_t) primitive_info[0].coordinates;
   primitive_info[coordinates].primitive=UndefinedPrimitive;
-  (void) DrawPrimitive(image,clone_info,primitive_info);
+  (void) DrawPrimitive(image,clone_info,primitive_info,exception);
   clone_info=DestroyDrawInfo(clone_info);
 }
 \f
@@ -1393,7 +1407,10 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
   const DrawInfo *draw_info,const char *name,ExceptionInfo *exception)
 {
   char
-    clip_mask[MaxTextExtent];
+    filename[MaxTextExtent];
+
+  Image
+    *clip_mask;
 
   const char
     *value;
@@ -1409,36 +1426,29 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(draw_info != (const DrawInfo *) NULL);
-  (void) FormatLocaleString(clip_mask,MaxTextExtent,"%s",name);
-  value=GetImageArtifact(image,clip_mask);
+  (void) FormatLocaleString(filename,MaxTextExtent,"%s",name);
+  value=GetImageArtifact(image,filename);
   if (value == (const char *) NULL)
     return(MagickFalse);
-  if (image->clip_mask == (Image *) NULL)
-    {
-      Image
-        *clip_mask;
-
-      clip_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
-        &image->exception);
-      if (clip_mask == (Image *) NULL)
-        return(MagickFalse);
-      (void) SetImageClipMask(image,clip_mask,exception);
-      clip_mask=DestroyImage(clip_mask);
-    }
-  (void) QueryColorCompliance("#00000000",AllCompliance,
-    &image->clip_mask->background_color,&image->exception);
-  image->clip_mask->background_color.alpha=(Quantum) TransparentAlpha;
-  (void) SetImageBackgroundColor(image->clip_mask);
+  clip_mask=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (clip_mask == (Image *) NULL)
+    return(MagickFalse);
+  (void) QueryColorCompliance("#0000",AllCompliance,
+    &clip_mask->background_color,exception);
+  clip_mask->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(clip_mask,exception);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"\nbegin clip-path %s",
       draw_info->clip_mask);
   clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
   (void) CloneString(&clone_info->primitive,value);
   (void) QueryColorCompliance("#ffffff",AllCompliance,&clone_info->fill,
-    &image->exception);
+    exception);
   clone_info->clip_mask=(char *) NULL;
-  status=DrawImage(image->clip_mask,clone_info,exception);
-  status|=NegateImage(image->clip_mask,MagickFalse,&image->exception);
+  status=NegateImage(clip_mask,MagickFalse,exception);
+  (void) SetImageMask(image,clip_mask,exception);
+  clip_mask=DestroyImage(clip_mask);
+  status=DrawImage(image,clone_info,exception);
   clone_info=DestroyDrawInfo(clone_info);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end clip-path");
@@ -1462,7 +1472,8 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
 %  The format of the DrawDashPolygon method is:
 %
 %      MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
-%        const PrimitiveInfo *primitive_info,Image *image)
+%        const PrimitiveInfo *primitive_info,Image *image,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1472,15 +1483,16 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
 %
 %    o image: the image.
 %
+%    o exception: return any errors or warnings in this structure.
 %
 */
 static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
-  const PrimitiveInfo *primitive_info,Image *image)
+  const PrimitiveInfo *primitive_info,Image *image,ExceptionInfo *exception)
 {
   DrawInfo
     *clone_info;
 
-  MagickRealType
+  double
     length,
     maximum_length,
     offset,
@@ -1496,7 +1508,7 @@ static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
   register ssize_t
     i;
 
-  register MagickRealType
+  register double
     dx,
     dy;
 
@@ -1559,7 +1571,7 @@ static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
           n=0;
         length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
       }
-    for (total_length=0.0; (total_length+length) < maximum_length; )
+    for (total_length=0.0; (total_length+length) <= maximum_length; )
     {
       total_length+=length;
       if ((n & 0x01) != 0)
@@ -1584,7 +1596,7 @@ static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
           j++;
           dash_polygon[0].coordinates=(size_t) j;
           dash_polygon[j].primitive=UndefinedPrimitive;
-          status|=DrawStrokePolygon(image,clone_info,dash_polygon);
+          status|=DrawStrokePolygon(image,clone_info,dash_polygon,exception);
         }
       n++;
       if (draw_info->dash_pattern[n] == 0.0)
@@ -1598,7 +1610,7 @@ static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
     dash_polygon[j].coordinates=1;
     j++;
   }
-  if ((total_length < maximum_length) && ((n & 0x01) == 0) && (j > 1))
+  if ((total_length <= maximum_length) && ((n & 0x01) == 0) && (j > 1))
     {
       dash_polygon[j]=primitive_info[i-1];
       dash_polygon[j].point.x+=MagickEpsilon;
@@ -1607,7 +1619,7 @@ static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
       j++;
       dash_polygon[0].coordinates=(size_t) j;
       dash_polygon[j].primitive=UndefinedPrimitive;
-      status|=DrawStrokePolygon(image,clone_info,dash_polygon);
+      status|=DrawStrokePolygon(image,clone_info,dash_polygon,exception);
     }
   dash_polygon=(PrimitiveInfo *) RelinquishMagickMemory(dash_polygon);
   clone_info=DestroyDrawInfo(clone_info);
@@ -1656,7 +1668,7 @@ static inline MagickBooleanType IsPoint(const char *point)
   double
     value;
 
-  value=InterpretLocaleValue(point,&p);
+  value=StringToDouble(point,&p);
   return((value == 0.0) && (p == point) ? MagickFalse : MagickTrue);
 }
 
@@ -1695,7 +1707,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
     proceed,
     status;
 
-  MagickRealType
+  double
     angle,
     factor,
     primitive_extent;
@@ -1703,7 +1715,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
   PointInfo
     point;
 
-  PixelPacket
+  PixelInfo
     start_color;
 
   PrimitiveInfo
@@ -1750,10 +1762,10 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
   if (*draw_info->primitive != '@')
     primitive=AcquireString(draw_info->primitive);
   else
-    primitive=FileToString(draw_info->primitive+1,~0,&image->exception);
+    primitive=FileToString(draw_info->primitive+1,~0,exception);
   if (primitive == (char *) NULL)
     return(MagickFalse);
-  primitive_extent=(MagickRealType) strlen(primitive);
+  primitive_extent=(double) strlen(primitive);
   (void) SetImageArtifact(image,"MVG",primitive);
   n=0;
   /*
@@ -1767,7 +1779,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
         image->filename);
     }
-  number_points=2047;
+  number_points=6553;
   primitive_info=(PrimitiveInfo *) AcquireQuantumMemory((size_t) number_points,
     sizeof(*primitive_info));
   if (primitive_info == (PrimitiveInfo *) NULL)
@@ -1788,8 +1800,8 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
     }
   token=AcquireString(primitive);
   (void) QueryColorCompliance("#000000",AllCompliance,&start_color,
-    &image->exception);
-  if (SetImageStorageClass(image,DirectClass,&image->exception) == MagickFalse)
+    exception);
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
   status=MagickTrue;
   for (q=primitive; *q != '\0'; )
@@ -1823,27 +1835,27 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("affine",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            affine.sx=InterpretLocaleValue(token,(char **) NULL);
+            affine.sx=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.rx=InterpretLocaleValue(token,(char **) NULL);
+            affine.rx=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.ry=InterpretLocaleValue(token,(char **) NULL);
+            affine.ry=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.sy=InterpretLocaleValue(token,(char **) NULL);
+            affine.sy=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.tx=InterpretLocaleValue(token,(char **) NULL);
+            affine.tx=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.ty=InterpretLocaleValue(token,(char **) NULL);
+            affine.ty=StringToDouble(token,(char **) NULL);
             break;
           }
         if (LocaleCompare("arc",keyword) == 0)
@@ -1866,7 +1878,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           {
             GetMagickToken(q,&q,token);
             (void) QueryColorCompliance(token,AllCompliance,
-              &graphic_context[n]->border_color,&image->exception);
+              &graphic_context[n]->border_color,exception);
             break;
           }
         status=MagickFalse;
@@ -1988,7 +2000,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
             else
               {
                 status=QueryColorCompliance(token,AllCompliance,
-                  &graphic_context[n]->fill,&image->exception);
+                  &graphic_context[n]->fill,exception);
                 if (status == MagickFalse)
                   {
                     ImageInfo
@@ -1997,20 +2009,20 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                     pattern_info=AcquireImageInfo();
                     (void) CopyMagickString(pattern_info->filename,token,
                       MaxTextExtent);
-                    graphic_context[n]->fill_pattern=
-                      ReadImage(pattern_info,&image->exception);
-                    CatchException(&image->exception);
+                    graphic_context[n]->fill_pattern=ReadImage(pattern_info,
+                      exception);
+                    CatchException(exception);
                     pattern_info=DestroyImageInfo(pattern_info);
                   }
               }
             break;
           }
-        if (LocaleCompare("fill-opacity",keyword) == 0)
+        if (LocaleCompare("fill-alpha",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
             factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
-            graphic_context[n]->fill.alpha=(MagickRealType) QuantumRange*
-              factor*InterpretLocaleValue(token,(char **) NULL);
+            graphic_context[n]->fill.alpha=(double) QuantumRange*
+              factor*StringToDouble(token,(char **) NULL);
             break;
           }
         if (LocaleCompare("fill-rule",keyword) == 0)
@@ -2045,8 +2057,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("font-size",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->pointsize=InterpretLocaleValue(token,
-              (char **) NULL);
+            graphic_context[n]->pointsize=StringToDouble(token,(char **) NULL);
             break;
           }
         if (LocaleCompare("font-stretch",keyword) == 0)
@@ -2140,14 +2151,14 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("interline-spacing",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->interline_spacing=InterpretLocaleValue(token,
+            graphic_context[n]->interline_spacing=StringToDouble(token,
               (char **) NULL);
             break;
           }
         if (LocaleCompare("interword-spacing",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->interword_spacing=InterpretLocaleValue(token,
+            graphic_context[n]->interword_spacing=StringToDouble(token,
               (char **) NULL);
             break;
           }
@@ -2160,8 +2171,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("kerning",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->kerning=InterpretLocaleValue(token,
-              (char **) NULL);
+            graphic_context[n]->kerning=StringToDouble(token,(char **) NULL);
             break;
           }
         status=MagickFalse;
@@ -2197,9 +2207,9 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           {
             GetMagickToken(q,&q,token);
             factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
-            graphic_context[n]->alpha=ClampToQuantum((MagickRealType)
-              QuantumRange*(1.0-((1.0-QuantumScale*graphic_context[n]->alpha)*
-              factor*InterpretLocaleValue(token,(char **) NULL))));
+            graphic_context[n]->alpha=ClampToQuantum(QuantumRange*(1.0-((1.0-
+              QuantumScale*graphic_context[n]->alpha)*factor*
+              StringToDouble(token,(char **) NULL))));
             graphic_context[n]->fill.alpha=(double) graphic_context[n]->alpha;
             graphic_context[n]->stroke.alpha=(double) graphic_context[n]->alpha;
             break;
@@ -2243,16 +2253,15 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
               {
                 if (n <= 0)
                   {
-                    (void) ThrowMagickException(&image->exception,
-                      GetMagickModule(),DrawError,
-                      "UnbalancedGraphicContextPushPop","`%s'",token);
+                    (void) ThrowMagickException(exception,GetMagickModule(),
+                      DrawError,"UnbalancedGraphicContextPushPop","'%s'",token);
                     n=0;
                     break;
                   }
                 if (graphic_context[n]->clip_mask != (char *) NULL)
                   if (LocaleCompare(graphic_context[n]->clip_mask,
                       graphic_context[n-1]->clip_mask) != 0)
-                    (void) SetImageClipMask(image,(Image *) NULL,exception);
+                    (void) SetImageMask(image,(Image *) NULL,exception);
                 graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
                 n--;
                 break;
@@ -2302,19 +2311,19 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                 GetMagickToken(q,&q,token);
                 (void) CopyMagickString(type,token,MaxTextExtent);
                 GetMagickToken(q,&q,token);
-                segment.x1=InterpretLocaleValue(token,(char **) NULL);
+                segment.x1=StringToDouble(token,(char **) NULL);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                segment.y1=InterpretLocaleValue(token,(char **) NULL);
+                segment.y1=StringToDouble(token,(char **) NULL);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                segment.x2=InterpretLocaleValue(token,(char **) NULL);
+                segment.x2=StringToDouble(token,(char **) NULL);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                segment.y2=InterpretLocaleValue(token,(char **) NULL);
+                segment.y2=StringToDouble(token,(char **) NULL);
                 if (LocaleCompare(type,"radial") == 0)
                   {
                     GetMagickToken(q,&q,token);
@@ -2364,22 +2373,22 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                 GetMagickToken(q,&q,token);
                 (void) CopyMagickString(name,token,MaxTextExtent);
                 GetMagickToken(q,&q,token);
-                bounds.x=(ssize_t) ceil(InterpretLocaleValue(token,
-                  (char **) NULL)-0.5);
+                bounds.x=(ssize_t) ceil(StringToDouble(token,(char **) NULL)-
+                  0.5);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                bounds.y=(ssize_t) ceil(InterpretLocaleValue(token,
-                  (char **) NULL)-0.5);
+                bounds.y=(ssize_t) ceil(StringToDouble(token,(char **) NULL)-
+                  0.5);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                bounds.width=(size_t) floor(InterpretLocaleValue(token,
+                bounds.width=(size_t) floor(StringToDouble(token,
                   (char **) NULL)+0.5);
                 GetMagickToken(q,&q,token);
                 if (*token == ',')
                   GetMagickToken(q,&q,token);
-                bounds.height=(size_t) floor(InterpretLocaleValue(token,
+                bounds.height=(size_t) floor(StringToDouble(token,
                   (char **) NULL)+0.5);
                 for (p=q; *q != '\0'; )
                 {
@@ -2409,9 +2418,9 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                   graphic_context,(size_t) (n+1),sizeof(*graphic_context));
                 if (graphic_context == (DrawInfo **) NULL)
                   {
-                    (void) ThrowMagickException(&image->exception,
-                      GetMagickModule(),ResourceLimitError,
-                      "MemoryAllocationFailed","`%s'",image->filename);
+                    (void) ThrowMagickException(exception,GetMagickModule(),
+                      ResourceLimitError,"MemoryAllocationFailed","'%s'",
+                      image->filename);
                     break;
                   }
                 graphic_context[n]=CloneDrawInfo((ImageInfo *) NULL,
@@ -2437,7 +2446,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("rotate",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            angle=InterpretLocaleValue(token,(char **) NULL);
+            angle=StringToDouble(token,(char **) NULL);
             affine.sx=cos(DegreesToRadians(fmod((double) angle,360.0)));
             affine.rx=sin(DegreesToRadians(fmod((double) angle,360.0)));
             affine.ry=(-sin(DegreesToRadians(fmod((double) angle,360.0))));
@@ -2458,37 +2467,37 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("scale",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            affine.sx=InterpretLocaleValue(token,(char **) NULL);
+            affine.sx=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.sy=InterpretLocaleValue(token,(char **) NULL);
+            affine.sy=StringToDouble(token,(char **) NULL);
             break;
           }
         if (LocaleCompare("skewX",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            angle=InterpretLocaleValue(token,(char **) NULL);
+            angle=StringToDouble(token,(char **) NULL);
             affine.ry=sin(DegreesToRadians(angle));
             break;
           }
         if (LocaleCompare("skewY",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            angle=InterpretLocaleValue(token,(char **) NULL);
+            angle=StringToDouble(token,(char **) NULL);
             affine.rx=(-tan(DegreesToRadians(angle)/2.0));
             break;
           }
         if (LocaleCompare("stop-color",keyword) == 0)
           {
-            PixelPacket
+            PixelInfo
               stop_color;
 
             GetMagickToken(q,&q,token);
             (void) QueryColorCompliance(token,AllCompliance,&stop_color,
-              &image->exception);
+              exception);
             (void) GradientImage(image,LinearGradient,ReflectSpread,
-              &start_color,&stop_color,&image->exception);
+              &start_color,&stop_color,exception);
             start_color=stop_color;
             GetMagickToken(q,&q,token);
             break;
@@ -2503,7 +2512,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
             else
               {
                 status=QueryColorCompliance(token,AllCompliance,
-                  &graphic_context[n]->stroke,&image->exception);
+                  &graphic_context[n]->stroke,exception);
                 if (status == MagickFalse)
                   {
                     ImageInfo
@@ -2512,9 +2521,9 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                     pattern_info=AcquireImageInfo();
                     (void) CopyMagickString(pattern_info->filename,token,
                       MaxTextExtent);
-                    graphic_context[n]->stroke_pattern=
-                      ReadImage(pattern_info,&image->exception);
-                    CatchException(&image->exception);
+                    graphic_context[n]->stroke_pattern=ReadImage(pattern_info,
+                      exception);
+                    CatchException(exception);
                     pattern_info=DestroyImageInfo(pattern_info);
                   }
               }
@@ -2552,9 +2561,9 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                   sizeof(*graphic_context[n]->dash_pattern));
                 if (graphic_context[n]->dash_pattern == (double *) NULL)
                   {
-                    (void) ThrowMagickException(&image->exception,
-                      GetMagickModule(),ResourceLimitError,
-                      "MemoryAllocationFailed","`%s'",image->filename);
+                    (void) ThrowMagickException(exception,GetMagickModule(),
+                      ResourceLimitError,"MemoryAllocationFailed","'%s'",
+                      image->filename);
                     break;
                   }
                 for (j=0; j < x; j++)
@@ -2562,8 +2571,8 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
                   GetMagickToken(q,&q,token);
                   if (*token == ',')
                     GetMagickToken(q,&q,token);
-                  graphic_context[n]->dash_pattern[j]=InterpretLocaleValue(
-                    token,(char **) NULL);
+                  graphic_context[n]->dash_pattern[j]=StringToDouble(token,
+                    (char **) NULL);
                 }
                 if ((x & 0x01) != 0)
                   for ( ; j < (2*x); j++)
@@ -2578,7 +2587,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("stroke-dashoffset",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->dash_offset=InterpretLocaleValue(token,
+            graphic_context[n]->dash_offset=StringToDouble(token,
               (char **) NULL);
             break;
           }
@@ -2619,14 +2628,14 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           {
             GetMagickToken(q,&q,token);
             factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
-            graphic_context[n]->stroke.alpha=(MagickRealType) QuantumRange*
-              factor*InterpretLocaleValue(token,(char **) NULL);
+            graphic_context[n]->stroke.alpha=(double) QuantumRange*
+              factor*StringToDouble(token,(char **) NULL);
             break;
           }
         if (LocaleCompare("stroke-width",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->stroke_width=InterpretLocaleValue(token,
+            graphic_context[n]->stroke_width=StringToDouble(token,
               (char **) NULL);
             break;
           }
@@ -2678,17 +2687,17 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           {
             GetMagickToken(q,&q,token);
             (void) QueryColorCompliance(token,AllCompliance,
-              &graphic_context[n]->undercolor,&image->exception);
+              &graphic_context[n]->undercolor,exception);
             break;
           }
         if (LocaleCompare("translate",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            affine.tx=InterpretLocaleValue(token,(char **) NULL);
+            affine.tx=StringToDouble(token,(char **) NULL);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            affine.ty=InterpretLocaleValue(token,(char **) NULL);
+            affine.ty=StringToDouble(token,(char **) NULL);
             break;
           }
         status=MagickFalse;
@@ -2700,23 +2709,23 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         if (LocaleCompare("viewbox",keyword) == 0)
           {
             GetMagickToken(q,&q,token);
-            graphic_context[n]->viewbox.x=(ssize_t) ceil(InterpretLocaleValue(
-              token,(char **) NULL)-0.5);
+            graphic_context[n]->viewbox.x=(ssize_t) ceil(StringToDouble(token,
+              (char **) NULL)-0.5);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            graphic_context[n]->viewbox.y=(ssize_t) ceil(InterpretLocaleValue(
-              token,(char **) NULL)-0.5);
+            graphic_context[n]->viewbox.y=(ssize_t) ceil(StringToDouble(token,
+              (char **) NULL)-0.5);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            graphic_context[n]->viewbox.width=(size_t) floor(
-              InterpretLocaleValue(token,(char **) NULL)+0.5);
+            graphic_context[n]->viewbox.width=(size_t) floor(StringToDouble(
+              token,(char **) NULL)+0.5);
             GetMagickToken(q,&q,token);
             if (*token == ',')
               GetMagickToken(q,&q,token);
-            graphic_context[n]->viewbox.height=(size_t) floor(
-              InterpretLocaleValue(token,(char **) NULL)+0.5);
+            graphic_context[n]->viewbox.height=(size_t) floor(StringToDouble(
+              token,(char **) NULL)+0.5);
             break;
           }
         status=MagickFalse;
@@ -2764,11 +2773,11 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
       if (IsPoint(q) == MagickFalse)
         break;
       GetMagickToken(q,&q,token);
-      point.x=InterpretLocaleValue(token,(char **) NULL);
+      point.x=StringToDouble(token,(char **) NULL);
       GetMagickToken(q,&q,token);
       if (*token == ',')
         GetMagickToken(q,&q,token);
-      point.y=InterpretLocaleValue(token,(char **) NULL);
+      point.y=StringToDouble(token,(char **) NULL);
       GetMagickToken(q,(const char **) NULL,token);
       if (*token == ',')
         GetMagickToken(q,&q,token);
@@ -2784,8 +2793,8 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
         (size_t) number_points,sizeof(*primitive_info));
       if (primitive_info == (PrimitiveInfo *) NULL)
         {
-          (void) ThrowMagickException(&image->exception,GetMagickModule(),
-            ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","'%s'",image->filename);
           break;
         }
     }
@@ -2831,8 +2840,8 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
       case BezierPrimitive:
       {
         if (primitive_info[j].coordinates > 107)
-          (void) ThrowMagickException(&image->exception,GetMagickModule(),
-            DrawError,"TooManyBezierCoordinates","`%s'",token);
+          (void) ThrowMagickException(exception,GetMagickModule(),DrawError,
+            "TooManyBezierCoordinates","'%s'",token);
         length=BezierQuantum*primitive_info[j].coordinates;
         break;
       }
@@ -2850,7 +2859,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           double
             value;
 
-          value=InterpretLocaleValue(s,&t);
+          value=StringToDouble(s,&t);
           (void) value;
           if (s == t)
             {
@@ -2866,7 +2875,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
       case ArcPrimitive:
       case EllipsePrimitive:
       {
-        MagickRealType
+        double
           alpha,
           beta,
           radius;
@@ -2890,8 +2899,8 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
           (size_t) number_points,sizeof(*primitive_info));
         if (primitive_info == (PrimitiveInfo *) NULL)
           {
-            (void) ThrowMagickException(&image->exception,GetMagickModule(),
-              ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","'%s'",
               image->filename);
             break;
           }
@@ -3091,7 +3100,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
              graphic_context[n-1]->clip_mask) != 0))
           (void) DrawClipPath(image,graphic_context[n],
             graphic_context[n]->clip_mask,exception);
-        (void) DrawPrimitive(image,graphic_context[n],primitive_info);
+        (void) DrawPrimitive(image,graphic_context[n],primitive_info,exception);
       }
     if (primitive_info->text != (char *) NULL)
       primitive_info->text=(char *) RelinquishMagickMemory(
@@ -3135,7 +3144,7 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
 %  The format of the DrawGradientImage method is:
 %
 %      MagickBooleanType DrawGradientImage(Image *image,
-%        const DrawInfo *draw_info)
+%        const DrawInfo *draw_info,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3143,9 +3152,11 @@ MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info,
 %
 %    o draw_info: the draw info.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 
-static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
+static inline double GetStopColorOffset(const GradientInfo *gradient,
   const ssize_t x,const ssize_t y)
 {
   switch (gradient->type)
@@ -3153,7 +3164,7 @@ static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
     case UndefinedGradient:
     case LinearGradient:
     {
-      MagickRealType
+      double
         gamma,
         length,
         offset,
@@ -3173,14 +3184,14 @@ static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
       q.y=(double) y-gradient_vector->y1;
       length=sqrt(q.x*q.x+q.y*q.y);
       gamma=sqrt(p.x*p.x+p.y*p.y)*length;
-      gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+      gamma=MagickEpsilonReciprocal(gamma);
       scale=p.x*q.x+p.y*q.y;
       offset=gamma*scale*length;
       return(offset);
     }
     case RadialGradient:
     {
-      MagickRealType
+      double
         length,
         offset;
 
@@ -3200,7 +3211,7 @@ static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
 }
 
 MagickExport MagickBooleanType DrawGradientImage(Image *image,
-  const DrawInfo *draw_info)
+  const DrawInfo *draw_info,ExceptionInfo *exception)
 {
   CacheView
     *image_view;
@@ -3211,16 +3222,13 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
   const SegmentInfo
     *gradient_vector;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     status;
 
   PixelInfo
     zero;
 
-  MagickRealType
+  double
     length;
 
   PointInfo
@@ -3229,6 +3237,12 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
   RectangleInfo
     bounding_box;
 
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  size_t
+    height,
+    width;
+#endif
+
   ssize_t
     y;
 
@@ -3247,11 +3261,15 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
   length=sqrt(point.x*point.x+point.y*point.y);
   bounding_box=gradient->bounding_box;
   status=MagickTrue;
-  exception=(&image->exception);
   GetPixelInfo(image,&zero);
-  image_view=AcquireCacheView(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+  height=bounding_box.height-bounding_box.y;
+  width=bounding_box.width-bounding_box.x;
+#endif
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    dynamic_number_threads(image,width,height,1)
 #endif
   for (y=bounding_box.y; y < (ssize_t) bounding_box.height; y++)
   {
@@ -3259,7 +3277,7 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
       composite,
       pixel;
 
-    MagickRealType
+    double
       alpha,
       offset;
 
@@ -3288,7 +3306,7 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
       offset/=length;
     for (x=bounding_box.x; x < (ssize_t) bounding_box.width; x++)
     {
-      SetPixelInfo(image,q,&pixel);
+      GetPixelInfoPixel(image,q,&pixel);
       switch (gradient->spread)
       {
         case UndefinedSpread:
@@ -3359,7 +3377,7 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
           MagickBooleanType
             antialias;
 
-          MagickRealType
+          double
             repeat;
 
           antialias=MagickFalse;
@@ -3422,7 +3440,7 @@ MagickExport MagickBooleanType DrawGradientImage(Image *image,
       }
       CompositePixelInfoOver(&composite,composite.alpha,&pixel,pixel.alpha,
         &pixel);
-      SetPixelPixelInfo(image,&pixel,q);
+      SetPixelInfoPixel(image,&pixel,q);
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -3501,11 +3519,11 @@ MagickExport MagickBooleanType DrawPatternPath(Image *image,
     *pattern=DestroyImage(*pattern);
   image_info=AcquireImageInfo();
   image_info->size=AcquireString(geometry);
-  *pattern=AcquireImage(image_info,&image->exception);
+  *pattern=AcquireImage(image_info,exception);
   image_info=DestroyImageInfo(image_info);
   (void) QueryColorCompliance("#00000000",AllCompliance,
-    &(*pattern)->background_color,&image->exception);
-  (void) SetImageBackgroundColor(*pattern);
+    &(*pattern)->background_color,exception);
+  (void) SetImageBackgroundColor(*pattern,exception);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(DrawEvent,GetMagickModule(),
       "begin pattern-path %s %s",name,geometry);
@@ -3536,7 +3554,8 @@ MagickExport MagickBooleanType DrawPatternPath(Image *image,
 %  The format of the DrawPolygonPrimitive method is:
 %
 %      MagickBooleanType DrawPolygonPrimitive(Image *image,
-%        const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+%        const DrawInfo *draw_info,const PrimitiveInfo *primitive_info,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3546,6 +3565,8 @@ MagickExport MagickBooleanType DrawPatternPath(Image *image,
 %
 %    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 
 static PolygonInfo **DestroyPolygonThreadSet(PolygonInfo **polygon_info)
@@ -3554,7 +3575,7 @@ static PolygonInfo **DestroyPolygonThreadSet(PolygonInfo **polygon_info)
     i;
 
   assert(polygon_info != (PolygonInfo **) NULL);
-  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
     if (polygon_info[i] != (PolygonInfo *) NULL)
       polygon_info[i]=DestroyPolygonInfo(polygon_info[i]);
   polygon_info=(PolygonInfo **) RelinquishMagickMemory(polygon_info);
@@ -3576,13 +3597,12 @@ static PolygonInfo **AcquirePolygonThreadSet(const DrawInfo *draw_info,
   size_t
     number_threads;
 
-  number_threads=GetOpenMPMaximumThreads();
+  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
   polygon_info=(PolygonInfo **) AcquireQuantumMemory(number_threads,
     sizeof(*polygon_info));
   if (polygon_info == (PolygonInfo **) NULL)
     return((PolygonInfo **) NULL);
-  (void) ResetMagickMemory(polygon_info,0,GetOpenMPMaximumThreads()*
-    sizeof(*polygon_info));
+  (void) ResetMagickMemory(polygon_info,0,number_threads*sizeof(*polygon_info));
   path_info=ConvertPrimitiveToPath(draw_info,primitive_info);
   if (path_info == (PathInfo *) NULL)
     return(DestroyPolygonThreadSet(polygon_info));
@@ -3596,26 +3616,25 @@ static PolygonInfo **AcquirePolygonThreadSet(const DrawInfo *draw_info,
   return(polygon_info);
 }
 
-static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
-  const MagickRealType mid,const MagickBooleanType fill,
-  const FillRule fill_rule,const double x,const double y,
-  MagickRealType *stroke_opacity)
+static double GetFillAlpha(PolygonInfo *polygon_info,const double mid,
+  const MagickBooleanType fill,const FillRule fill_rule,const ssize_t x,
+  const ssize_t y,double *stroke_alpha)
 {
-  MagickRealType
+  double
     alpha,
     beta,
     distance,
-    subpath_opacity;
+    subpath_alpha;
 
   PointInfo
     delta;
 
-  register EdgeInfo
-    *p;
-
   register const PointInfo
     *q;
 
+  register EdgeInfo
+    *p;
+
   register ssize_t
     i;
 
@@ -3626,30 +3645,31 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
   /*
     Compute fill & stroke opacity for this (x,y) point.
   */
-  *stroke_opacity=0.0;
-  subpath_opacity=0.0;
+  *stroke_alpha=0.0;
+  subpath_alpha=0.0;
   p=polygon_info->edges;
   for (j=0; j < (ssize_t) polygon_info->number_edges; j++, p++)
   {
-    if (y <= (p->bounds.y1-mid-0.5))
+    if ((double) y <= (p->bounds.y1-mid-0.5))
       break;
-    if (y > (p->bounds.y2+mid+0.5))
+    if ((double) y > (p->bounds.y2+mid+0.5))
       {
         (void) DestroyEdge(polygon_info,(size_t) j);
         continue;
       }
-    if ((x <= (p->bounds.x1-mid-0.5)) || (x > (p->bounds.x2+mid+0.5)))
+    if (((double) x <= (p->bounds.x1-mid-0.5)) ||
+        ((double) x > (p->bounds.x2+mid+0.5)))
       continue;
     i=(ssize_t) MagickMax((double) p->highwater,1.0);
     for ( ; i < (ssize_t) p->number_points; i++)
     {
-      if (y <= (p->points[i-1].y-mid-0.5))
+      if ((double) y <= (p->points[i-1].y-mid-0.5))
         break;
-      if (y > (p->points[i].y+mid+0.5))
+      if ((double) y > (p->points[i].y+mid+0.5))
         continue;
-      if (p->scanline != y)
+      if (p->scanline != (double) y)
         {
-          p->scanline=y;
+          p->scanline=(double) y;
           p->highwater=(size_t) i;
         }
       /*
@@ -3661,8 +3681,8 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
       beta=delta.x*(x-q->x)+delta.y*(y-q->y);
       if (beta < 0.0)
         {
-          delta.x=x-q->x;
-          delta.y=y-q->y;
+          delta.x=(double) x-q->x;
+          delta.y=(double) y-q->y;
           distance=delta.x*delta.x+delta.y*delta.y;
         }
       else
@@ -3670,13 +3690,13 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
           alpha=delta.x*delta.x+delta.y*delta.y;
           if (beta > alpha)
             {
-              delta.x=x-(q+1)->x;
-              delta.y=y-(q+1)->y;
+              delta.x=(double) x-(q+1)->x;
+              delta.y=(double) y-(q+1)->y;
               distance=delta.x*delta.x+delta.y*delta.y;
             }
           else
             {
-              alpha=1.0/alpha;
+              alpha=MagickEpsilonReciprocal(alpha);
               beta=delta.x*(y-q->y)-delta.y*(x-q->x);
               distance=alpha*beta*beta;
             }
@@ -3688,28 +3708,28 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
       if (p->ghostline == MagickFalse)
         {
           alpha=mid+0.5;
-          if ((*stroke_opacity < 1.0) &&
+          if ((*stroke_alpha < 1.0) &&
               (distance <= ((alpha+0.25)*(alpha+0.25))))
             {
               alpha=mid-0.5;
               if (distance <= ((alpha+0.25)*(alpha+0.25)))
-                *stroke_opacity=1.0;
+                *stroke_alpha=1.0;
               else
                 {
                   beta=1.0;
                   if (distance != 1.0)
                     beta=sqrt((double) distance);
                   alpha=beta-mid-0.5;
-                  if (*stroke_opacity < ((alpha-0.25)*(alpha-0.25)))
-                    *stroke_opacity=(alpha-0.25)*(alpha-0.25);
+                  if (*stroke_alpha < ((alpha-0.25)*(alpha-0.25)))
+                    *stroke_alpha=(alpha-0.25)*(alpha-0.25);
                 }
             }
         }
-      if ((fill == MagickFalse) || (distance > 1.0) || (subpath_opacity >= 1.0))
+      if ((fill == MagickFalse) || (distance > 1.0) || (subpath_alpha >= 1.0))
         continue;
       if (distance <= 0.0)
         {
-          subpath_opacity=1.0;
+          subpath_alpha=1.0;
           continue;
         }
       if (distance > 1.0)
@@ -3721,8 +3741,8 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
             beta=sqrt(distance);
         }
       alpha=beta-1.0;
-      if (subpath_opacity < (alpha*alpha))
-        subpath_opacity=alpha*alpha;
+      if (subpath_alpha < (alpha*alpha))
+        subpath_alpha=alpha*alpha;
     }
   }
   /*
@@ -3730,7 +3750,7 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
   */
   if (fill == MagickFalse)
     return(0.0);
-  if (subpath_opacity >= 1.0)
+  if (subpath_alpha >= 1.0)
     return(1.0);
   /*
     Determine winding number.
@@ -3739,18 +3759,18 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
   p=polygon_info->edges;
   for (j=0; j < (ssize_t) polygon_info->number_edges; j++, p++)
   {
-    if (y <= p->bounds.y1)
+    if ((double) y <= p->bounds.y1)
       break;
-    if ((y > p->bounds.y2) || (x <= p->bounds.x1))
+    if (((double) y > p->bounds.y2) || ((double) x <= p->bounds.x1))
       continue;
-    if (x > p->bounds.x2)
+    if ((double) x > p->bounds.x2)
       {
         winding_number+=p->direction ? 1 : -1;
         continue;
       }
     i=(ssize_t) MagickMax((double) p->highwater,1.0);
     for ( ; i < (ssize_t) p->number_points; i++)
-      if (y <= p->points[i].y)
+      if ((double) y <= p->points[i].y)
         break;
     q=p->points+i-1;
     if ((((q+1)->x-q->x)*(y-q->y)) <= (((q+1)->y-q->y)*(x-q->x)))
@@ -3764,23 +3784,21 @@ static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
   else
     if (MagickAbsoluteValue(winding_number) != 0)
       return(1.0);
-  return(subpath_opacity);
+  return(subpath_alpha);
 }
 
 static MagickBooleanType DrawPolygonPrimitive(Image *image,
-  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info,
+  ExceptionInfo *exception)
 {
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickBooleanType
     fill,
     status;
 
-  MagickRealType
+  double
     mid;
 
   PolygonInfo
@@ -3795,6 +3813,12 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
   SegmentInfo
     bounds;
 
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  size_t
+    height,
+    width;
+#endif
+
   ssize_t
     start,
     stop,
@@ -3816,7 +3840,7 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
   if (polygon_info == (PolygonInfo **) NULL)
     return(MagickFalse);
   if (0)
-    DrawBoundingRectangles(image,draw_info,polygon_info[0]);
+    DrawBoundingRectangles(image,draw_info,polygon_info[0],exception);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin draw-polygon");
   fill=(primitive_info->method == FillToBorderMethod) ||
@@ -3837,35 +3861,39 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
   }
   bounds.x1-=(mid+1.0);
   bounds.x1=bounds.x1 < 0.0 ? 0.0 : (size_t) ceil(bounds.x1-0.5) >=
-    image->columns ? (double) image->columns-1.0 : bounds.x1;
+    image->columns ? (double) image->columns-1 : bounds.x1;
   bounds.y1-=(mid+1.0);
   bounds.y1=bounds.y1 < 0.0 ? 0.0 : (size_t) ceil(bounds.y1-0.5) >=
-    image->rows ? (double) image->rows-1.0 : bounds.y1;
+    image->rows ? (double) image->rows-1 : bounds.y1;
   bounds.x2+=(mid+1.0);
   bounds.x2=bounds.x2 < 0.0 ? 0.0 : (size_t) floor(bounds.x2+0.5) >=
-    image->columns ? (double) image->columns-1.0 : bounds.x2;
+    image->columns ? (double) image->columns-1 : bounds.x2;
   bounds.y2+=(mid+1.0);
   bounds.y2=bounds.y2 < 0.0 ? 0.0 : (size_t) floor(bounds.y2+0.5) >=
-    image->rows ? (double) image->rows-1.0 : bounds.y2;
+    image->rows ? (double) image->rows-1 : bounds.y2;
   status=MagickTrue;
-  exception=(&image->exception);
-  start=(ssize_t) ceil(bounds.x1-0.5);
-  stop=(ssize_t) floor(bounds.x2+0.5);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  height=(size_t) (floor(bounds.y2+0.5)-ceil(bounds.y1-0.5));
+  width=(size_t) (floor(bounds.x2+0.5)-ceil(bounds.x1-0.5));
+#endif
   if (primitive_info->coordinates == 1)
     {
       /*
         Draw point.
       */
+      start=(ssize_t) ceil(bounds.y1-0.5);
+      stop=(ssize_t) floor(bounds.y2+0.5);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        dynamic_number_threads(image,width,height,1)
 #endif
-      for (y=(ssize_t) ceil(bounds.y1-0.5); y <= (ssize_t) floor(bounds.y2+0.5); y++)
+      for (y=start; y <= stop; y++)
       {
         MagickBooleanType
           sync;
 
-        PixelPacket
+        PixelInfo
           pixel;
 
         register ssize_t
@@ -3874,23 +3902,30 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
         register Quantum
           *restrict q;
 
+        ssize_t
+          start,
+          stop;
+
         if (status == MagickFalse)
           continue;
+        start=(ssize_t) ceil(bounds.x1-0.5);
+        stop=(ssize_t) floor(bounds.x2+0.5);
         x=start;
-        q=GetCacheViewAuthenticPixels(image_view,x,y,(size_t) (stop-x+1),
-          1,exception);
+        q=GetCacheViewAuthenticPixels(image_view,x,y,(size_t) (stop-x+1),1,
+          exception);
         if (q == (Quantum *) NULL)
           {
             status=MagickFalse;
             continue;
           }
+        GetPixelInfo(image,&pixel);
         for ( ; x <= stop; x++)
         {
           if ((x == (ssize_t) ceil(primitive_info->point.x-0.5)) &&
               (y == (ssize_t) ceil(primitive_info->point.y-0.5)))
             {
               (void) GetStrokeColor(draw_info,x,y,&pixel,exception);
-              SetPixelPacket(image,&pixel,q);
+              SetPixelInfoPixel(image,&pixel,q);
             }
           q+=GetPixelChannels(image);
         }
@@ -3908,21 +3943,24 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
   /*
     Draw polygon or line.
   */
-  if (image->matte == MagickFalse)
+  if (image->alpha_trait != BlendPixelTrait)
     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+  start=(ssize_t) ceil(bounds.y1-0.5);
+  stop=(ssize_t) floor(bounds.y2+0.5);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    dynamic_number_threads(image,width,height,1)
 #endif
-  for (y=(ssize_t) ceil(bounds.y1-0.5); y <= (ssize_t) floor(bounds.y2+0.5); y++)
+  for (y=start; y <= stop; y++)
   {
     const int
       id = GetOpenMPThreadId();
 
-    MagickRealType
-      fill_opacity,
-      stroke_opacity;
+    double
+      fill_alpha,
+      stroke_alpha;
 
-    PixelPacket
+    PixelInfo
       fill_color,
       stroke_color;
 
@@ -3932,10 +3970,16 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
     register ssize_t
       x;
 
+    ssize_t
+      start,
+      stop;
+
     if (status == MagickFalse)
       continue;
-    q=GetCacheViewAuthenticPixels(image_view,start,y,(size_t) (stop-
-      start+1),1,exception);
+    start=(ssize_t) ceil(bounds.x1-0.5);
+    stop=(ssize_t) floor(bounds.x2+0.5);
+    q=GetCacheViewAuthenticPixels(image_view,start,y,(size_t) (stop-start+1),1,
+      exception);
     if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
@@ -3946,20 +3990,20 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
       /*
         Fill and/or stroke.
       */
-      fill_opacity=GetPixelOpacity(polygon_info[id],mid,fill,
-        draw_info->fill_rule,(double) x,(double) y,&stroke_opacity);
+      fill_alpha=GetFillAlpha(polygon_info[id],mid,fill,draw_info->fill_rule,
+        x,y,&stroke_alpha);
       if (draw_info->stroke_antialias == MagickFalse)
         {
-          fill_opacity=fill_opacity > 0.25 ? 1.0 : 0.0;
-          stroke_opacity=stroke_opacity > 0.25 ? 1.0 : 0.0;
+          fill_alpha=fill_alpha > 0.25 ? 1.0 : 0.0;
+          stroke_alpha=stroke_alpha > 0.25 ? 1.0 : 0.0;
         }
       (void) GetFillColor(draw_info,x,y,&fill_color,exception);
-      fill_opacity=fill_opacity*fill_color.alpha;
-      CompositePixelOver(image,&fill_color,fill_opacity,q,(MagickRealType)
+      fill_alpha=fill_alpha*fill_color.alpha;
+      CompositePixelOver(image,&fill_color,fill_alpha,q,(double)
         GetPixelAlpha(image,q),q);
       (void) GetStrokeColor(draw_info,x,y,&stroke_color,exception);
-      stroke_opacity=stroke_opacity*stroke_color.alpha;
-      CompositePixelOver(image,&stroke_color,stroke_opacity,q,(MagickRealType)
+      stroke_alpha=stroke_alpha*stroke_color.alpha;
+      CompositePixelOver(image,&stroke_color,stroke_alpha,q,(double)
         GetPixelAlpha(image,q),q);
       q+=GetPixelChannels(image);
     }
@@ -3989,7 +4033,7 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
 %  The format of the DrawPrimitive method is:
 %
 %      MagickBooleanType DrawPrimitive(Image *image,const DrawInfo *draw_info,
-%        PrimitiveInfo *primitive_info)
+%        PrimitiveInfo *primitive_info,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3999,6 +4043,8 @@ static MagickBooleanType DrawPolygonPrimitive(Image *image,
 %
 %    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 
 static void LogPrimitiveInfo(const PrimitiveInfo *primitive_info)
@@ -4082,8 +4128,8 @@ static void LogPrimitiveInfo(const PrimitiveInfo *primitive_info)
         p=point;
       }
     point=primitive_info[i].point;
-    if ((fabs(q.x-point.x) > MagickEpsilon) ||
-        (fabs(q.y-point.y) > MagickEpsilon))
+    if ((fabs(q.x-point.x) >= MagickEpsilon) ||
+        (fabs(q.y-point.y) >= MagickEpsilon))
       (void) LogMagickEvent(DrawEvent,GetMagickModule(),
         "      %.20g: %.18g,%.18g",(double) coordinates,point.x,point.y);
     else
@@ -4093,8 +4139,8 @@ static void LogPrimitiveInfo(const PrimitiveInfo *primitive_info)
     coordinates--;
     if (coordinates > 0)
       continue;
-    if ((fabs(p.x-point.x) > MagickEpsilon) ||
-        (fabs(p.y-point.y) > MagickEpsilon))
+    if ((fabs(p.x-point.x) >= MagickEpsilon) ||
+        (fabs(p.y-point.y) >= MagickEpsilon))
       (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end last (%.20g)",
         (double) coordinates);
     else
@@ -4104,14 +4150,12 @@ static void LogPrimitiveInfo(const PrimitiveInfo *primitive_info)
 }
 
 MagickExport MagickBooleanType DrawPrimitive(Image *image,
-  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info,
+  ExceptionInfo *exception)
 {
   CacheView
     *image_view;
 
-  ExceptionInfo
-    *exception;
-
   MagickStatusType
     status;
 
@@ -4131,16 +4175,19 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
         draw_info->affine.rx,draw_info->affine.ry,draw_info->affine.sy,
         draw_info->affine.tx,draw_info->affine.ty);
     }
+  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
+      ((IsPixelInfoGray(&draw_info->fill) == MagickFalse) ||
+       (IsPixelInfoGray(&draw_info->stroke) == MagickFalse)))
+    (void) SetImageColorspace(image,RGBColorspace,exception);
   status=MagickTrue;
-  exception=(&image->exception);
   x=(ssize_t) ceil(primitive_info->point.x-0.5);
   y=(ssize_t) ceil(primitive_info->point.y-0.5);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
   switch (primitive_info->primitive)
   {
     case PointPrimitive:
     {
-      PixelPacket
+      PixelInfo
         fill_color;
 
       register Quantum
@@ -4154,8 +4201,8 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
       if (q == (Quantum *) NULL)
         break;
       (void) GetFillColor(draw_info,x,y,&fill_color,exception);
-      CompositePixelOver(image,&fill_color,(MagickRealType) fill_color.alpha,q,
-        (MagickRealType) GetPixelAlpha(image,q),q);
+      CompositePixelOver(image,&fill_color,(double) fill_color.alpha,q,
+        (double) GetPixelAlpha(image,q),q);
       (void) SyncCacheViewAuthenticPixels(image_view,exception);
       break;
     }
@@ -4166,7 +4213,7 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
         case PointMethod:
         default:
         {
-          PixelPacket
+          PixelInfo
             pixel;
 
           register Quantum
@@ -4175,8 +4222,9 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
           if (q == (Quantum *) NULL)
             break;
+          GetPixelInfo(image,&pixel);
           (void) GetFillColor(draw_info,x,y,&pixel,exception);
-          SetPixelPacket(image,&pixel,q);
+          SetPixelInfoPixel(image,&pixel,q);
           (void) SyncCacheViewAuthenticPixels(image_view,exception);
           break;
         }
@@ -4185,19 +4233,12 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           MagickBooleanType
             sync;
 
-          PixelPacket
+          PixelInfo
             pixel,
             target;
 
-          Quantum
-            virtual_pixel[MaxPixelChannels];
-
-          (void) GetOneCacheViewVirtualPixel(image_view,x,y,virtual_pixel,
+          (void) GetOneCacheViewVirtualPixelInfo(image_view,x,y,&target,
             exception);
-          target.red=(double) virtual_pixel[RedPixelChannel];
-          target.green=(double) virtual_pixel[GreenPixelChannel];
-          target.blue=(double) virtual_pixel[BluePixelChannel];
-          target.alpha=(double) virtual_pixel[AlphaPixelChannel];
           for (y=0; y < (ssize_t) image->rows; y++)
           {
             register Quantum
@@ -4209,14 +4250,14 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
               break;
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              GetPixelPacketPixel(image,q,&pixel);
-              if (IsFuzzyEquivalencePixelPacket(image,&pixel,&target) == MagickFalse)
+              GetPixelInfoPixel(image,q,&pixel);
+              if (IsFuzzyEquivalencePixelInfo(&pixel,&target) == MagickFalse)
                 {
                   q+=GetPixelChannels(image);
                   continue;
                 }
               (void) GetFillColor(draw_info,x,y,&pixel,exception);
-              SetPixelPacket(image,&pixel,q);
+              SetPixelInfoPixel(image,&pixel,q);
               q+=GetPixelChannels(image);
             }
             sync=SyncCacheViewAuthenticPixels(image_view,exception);
@@ -4231,12 +4272,13 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           PixelInfo
             target;
 
-          (void) GetOneVirtualMagickPixel(image,x,y,&target,exception);
+          (void) GetOneVirtualPixelInfo(image,TileVirtualPixelMethod,x,y,
+            &target,exception);
           if (primitive_info->method == FillToBorderMethod)
             {
-              target.red=(MagickRealType) draw_info->border_color.red;
-              target.green=(MagickRealType) draw_info->border_color.green;
-              target.blue=(MagickRealType) draw_info->border_color.blue;
+              target.red=(double) draw_info->border_color.red;
+              target.green=(double) draw_info->border_color.green;
+              target.blue=(double) draw_info->border_color.blue;
             }
           (void) FloodfillPaintImage(image,draw_info,&target,x,y,
             primitive_info->method == FloodfillMethod ? MagickFalse :
@@ -4248,9 +4290,10 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           MagickBooleanType
             sync;
 
-          PixelPacket
+          PixelInfo
             pixel;
 
+          GetPixelInfo(image,&pixel);
           for (y=0; y < (ssize_t) image->rows; y++)
           {
             register Quantum
@@ -4266,7 +4309,7 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
             for (x=0; x < (ssize_t) image->columns; x++)
             {
               (void) GetFillColor(draw_info,x,y,&pixel,exception);
-              SetPixelPacket(image,&pixel,q);
+              SetPixelInfoPixel(image,&pixel,q);
               q+=GetPixelChannels(image);
             }
             sync=SyncCacheViewAuthenticPixels(image_view,exception);
@@ -4280,14 +4323,14 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
     }
     case MattePrimitive:
     {
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
       switch (primitive_info->method)
       {
         case PointMethod:
         default:
         {
-          PixelPacket
+          PixelInfo
             pixel;
 
           register Quantum
@@ -4306,19 +4349,12 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           MagickBooleanType
             sync;
 
-          PixelPacket
+          PixelInfo
             pixel,
             target;
 
-          Quantum
-            virtual_pixel[MaxPixelChannels];
-
-          (void) GetOneCacheViewVirtualPixel(image_view,x,y,virtual_pixel,
+          (void) GetOneCacheViewVirtualPixelInfo(image_view,x,y,&target,
             exception);
-          target.red=(double) virtual_pixel[RedPixelChannel];
-          target.green=(double) virtual_pixel[GreenPixelChannel];
-          target.blue=(double) virtual_pixel[BluePixelChannel];
-          target.alpha=(double) virtual_pixel[AlphaPixelChannel];
           for (y=0; y < (ssize_t) image->rows; y++)
           {
             register Quantum
@@ -4333,8 +4369,8 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
               break;
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              GetPixelPacketPixel(image,q,&pixel);
-              if (IsFuzzyEquivalencePixelPacket(image,&pixel,&target) == MagickFalse)
+              GetPixelInfoPixel(image,q,&pixel);
+              if (IsFuzzyEquivalencePixelInfo(&pixel,&target) == MagickFalse)
                 {
                   q+=GetPixelChannels(image);
                   continue;
@@ -4358,18 +4394,19 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           PixelInfo
             target;
 
-          (void) GetOneVirtualMagickPixel(image,x,y,&target,exception);
+          (void) GetOneVirtualPixelInfo(image,TileVirtualPixelMethod,x,y,
+            &target,exception);
           if (primitive_info->method == FillToBorderMethod)
             {
-              target.red=(MagickRealType) draw_info->border_color.red;
-              target.green=(MagickRealType) draw_info->border_color.green;
-              target.blue=(MagickRealType) draw_info->border_color.blue;
+              target.red=(double) draw_info->border_color.red;
+              target.green=(double) draw_info->border_color.green;
+              target.blue=(double) draw_info->border_color.blue;
             }
-          channel_mask=SetPixelChannelMask(image,AlphaChannel);
+          channel_mask=SetImageChannelMask(image,AlphaChannel);
           (void) FloodfillPaintImage(image,draw_info,&target,x,y,
             primitive_info->method == FloodfillMethod ? MagickFalse :
             MagickTrue,exception);
-          (void) SetPixelChannelMask(image,channel_mask);
+          (void) SetImageChannelMask(image,channel_mask);
           break;
         }
         case ResetMethod:
@@ -4377,7 +4414,7 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           MagickBooleanType
             sync;
 
-          PixelPacket
+          PixelInfo
             pixel;
 
           for (y=0; y < (ssize_t) image->rows; y++)
@@ -4452,12 +4489,12 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
       clone_info=AcquireImageInfo();
       if (LocaleNCompare(primitive_info->text,"data:",5) == 0)
         composite_image=ReadInlineImage(clone_info,primitive_info->text,
-          &image->exception);
+          exception);
       else
         {
           (void) CopyMagickString(clone_info->filename,primitive_info->text,
             MaxTextExtent);
-          composite_image=ReadImage(clone_info,&image->exception);
+          composite_image=ReadImage(clone_info,exception);
         }
       clone_info=DestroyImageInfo(clone_info);
       if (composite_image == (Image *) NULL)
@@ -4478,13 +4515,14 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g!",
             primitive_info[1].point.x,primitive_info[1].point.y);
           composite_image->filter=image->filter;
-          (void) TransformImage(&composite_image,(char *) NULL,geometry);
+          (void) TransformImage(&composite_image,(char *) NULL,geometry,
+            exception);
         }
-      if (composite_image->matte == MagickFalse)
+      if (composite_image->alpha_trait != BlendPixelTrait)
         (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,
           exception);
       if (draw_info->alpha != OpaqueAlpha)
-        (void) SetImageAlpha(composite_image,draw_info->alpha);
+        (void) SetImageAlpha(composite_image,draw_info->alpha,exception);
       SetGeometry(image,&geometry);
       image->gravity=draw_info->gravity;
       geometry.x=x;
@@ -4492,23 +4530,22 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
       (void) FormatLocaleString(composite_geometry,MaxTextExtent,
         "%.20gx%.20g%+.20g%+.20g",(double) composite_image->columns,(double)
         composite_image->rows,(double) geometry.x,(double) geometry.y);
-      (void) ParseGravityGeometry(image,composite_geometry,&geometry,
-        &image->exception);
+      (void) ParseGravityGeometry(image,composite_geometry,&geometry,exception);
       affine=draw_info->affine;
       affine.tx=(double) geometry.x;
       affine.ty=(double) geometry.y;
       composite_image->interpolate=image->interpolate;
       if (draw_info->compose == OverCompositeOp)
-        (void) DrawAffineImage(image,composite_image,&affine);
+        (void) DrawAffineImage(image,composite_image,&affine,exception);
       else
-        (void) CompositeImage(image,draw_info->compose,composite_image,
-          geometry.x,geometry.y);
+        (void) CompositeImage(image,composite_image,draw_info->compose,
+          MagickTrue,geometry.x,geometry.y,exception);
       composite_image=DestroyImage(composite_image);
       break;
     }
     default:
     {
-      MagickRealType
+      double
         mid,
         scale;
 
@@ -4520,7 +4557,7 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
       scale=ExpandAffine(&draw_info->affine);
       if ((draw_info->dash_pattern != (double *) NULL) &&
           (draw_info->dash_pattern[0] != 0.0) &&
-          ((scale*draw_info->stroke_width) > MagickEpsilon) &&
+          ((scale*draw_info->stroke_width) >= MagickEpsilon) &&
           (draw_info->stroke.alpha != (Quantum) TransparentAlpha))
         {
           /*
@@ -4529,9 +4566,10 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
           clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
           clone_info->stroke_width=0.0;
           clone_info->stroke.alpha=(Quantum) TransparentAlpha;
-          status=DrawPolygonPrimitive(image,clone_info,primitive_info);
+          status=DrawPolygonPrimitive(image,clone_info,primitive_info,
+            exception);
           clone_info=DestroyDrawInfo(clone_info);
-          (void) DrawDashPolygon(draw_info,primitive_info,image);
+          (void) DrawDashPolygon(draw_info,primitive_info,image,exception);
           break;
         }
       mid=ExpandAffine(&draw_info->affine)*draw_info->stroke_width/2.0;
@@ -4555,18 +4593,20 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
                (draw_info->linejoin == RoundJoin)) ||
                (primitive_info[i].primitive != UndefinedPrimitive))
             {
-              (void) DrawPolygonPrimitive(image,draw_info,primitive_info);
+              (void) DrawPolygonPrimitive(image,draw_info,primitive_info,
+                exception);
               break;
             }
           clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
           clone_info->stroke_width=0.0;
           clone_info->stroke.alpha=(Quantum) TransparentAlpha;
-          status=DrawPolygonPrimitive(image,clone_info,primitive_info);
+          status=DrawPolygonPrimitive(image,clone_info,primitive_info,
+            exception);
           clone_info=DestroyDrawInfo(clone_info);
-          status|=DrawStrokePolygon(image,draw_info,primitive_info);
+          status|=DrawStrokePolygon(image,draw_info,primitive_info,exception);
           break;
         }
-      status=DrawPolygonPrimitive(image,draw_info,primitive_info);
+      status=DrawPolygonPrimitive(image,draw_info,primitive_info,exception);
       break;
     }
   }
@@ -4607,7 +4647,7 @@ MagickExport MagickBooleanType DrawPrimitive(Image *image,
 */
 
 static void DrawRoundLinecap(Image *image,const DrawInfo *draw_info,
-  const PrimitiveInfo *primitive_info)
+  const PrimitiveInfo *primitive_info,ExceptionInfo *exception)
 {
   PrimitiveInfo
     linecap[5];
@@ -4623,11 +4663,12 @@ static void DrawRoundLinecap(Image *image,const DrawInfo *draw_info,
   linecap[2].point.y+=(double) (10.0*MagickEpsilon);
   linecap[3].point.y+=(double) (10.0*MagickEpsilon);
   linecap[4].primitive=UndefinedPrimitive;
-  (void) DrawPolygonPrimitive(image,draw_info,linecap);
+  (void) DrawPolygonPrimitive(image,draw_info,linecap,exception);
 }
 
 static MagickBooleanType DrawStrokePolygon(Image *image,
-  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info,
+  ExceptionInfo *exception)
 {
   DrawInfo
     *clone_info;
@@ -4651,6 +4692,11 @@ static MagickBooleanType DrawStrokePolygon(Image *image,
       "    begin draw-stroke-polygon");
   clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
   clone_info->fill=draw_info->stroke;
+  if (clone_info->fill_pattern != (Image *) NULL)
+    clone_info->fill_pattern=DestroyImage(clone_info->fill_pattern);
+  if (clone_info->stroke_pattern != (Image *) NULL)
+    clone_info->fill_pattern=CloneImage(clone_info->stroke_pattern,0,0,
+      MagickTrue,exception);
   clone_info->stroke.alpha=(Quantum) TransparentAlpha;
   clone_info->stroke_width=0.0;
   clone_info->fill_rule=NonZeroRule;
@@ -4658,15 +4704,15 @@ static MagickBooleanType DrawStrokePolygon(Image *image,
   for (p=primitive_info; p->primitive != UndefinedPrimitive; p+=p->coordinates)
   {
     stroke_polygon=TraceStrokePolygon(draw_info,p);
-    status=DrawPolygonPrimitive(image,clone_info,stroke_polygon);
+    status=DrawPolygonPrimitive(image,clone_info,stroke_polygon,exception);
     stroke_polygon=(PrimitiveInfo *) RelinquishMagickMemory(stroke_polygon);
     q=p+p->coordinates-1;
     closed_path=(q->point.x == p->point.x) && (q->point.y == p->point.y) ?
       MagickTrue : MagickFalse;
     if ((draw_info->linecap == RoundCap) && (closed_path == MagickFalse))
       {
-        DrawRoundLinecap(image,draw_info,p);
-        DrawRoundLinecap(image,draw_info,q);
+        DrawRoundLinecap(image,draw_info,p,exception);
+        DrawRoundLinecap(image,draw_info,q,exception);
       }
   }
   clone_info=DestroyDrawInfo(clone_info);
@@ -4782,20 +4828,19 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
         (void) CloneString(&draw_info->encoding,option);
       option=GetImageOption(image_info,"kerning");
       if (option != (const char *) NULL)
-        draw_info->kerning=InterpretLocaleValue(option,(char **) NULL);
+        draw_info->kerning=StringToDouble(option,(char **) NULL);
       option=GetImageOption(image_info,"interline-spacing");
       if (option != (const char *) NULL)
-        draw_info->interline_spacing=InterpretLocaleValue(option,
-          (char **) NULL);
-      draw_info->direction=UndefinedDirection;
+        draw_info->interline_spacing=StringToDouble(option,(char **) NULL);
       option=GetImageOption(image_info,"interword-spacing");
       if (option != (const char *) NULL)
-        draw_info->interword_spacing=InterpretLocaleValue(option,
-          (char **) NULL);
+        draw_info->interword_spacing=StringToDouble(option,(char **) NULL);
       option=GetImageOption(image_info,"direction");
       if (option != (const char *) NULL)
         draw_info->direction=(DirectionType) ParseCommandOption(
           MagickDirectionOptions,MagickFalse,option);
+      else
+        draw_info->direction=UndefinedDirection;
       option=GetImageOption(image_info,"fill");
       if (option != (const char *) NULL)
         (void) QueryColorCompliance(option,AllCompliance,&draw_info->fill,
@@ -4806,7 +4851,7 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
           exception);
       option=GetImageOption(image_info,"strokewidth");
       if (option != (const char *) NULL)
-        draw_info->stroke_width=InterpretLocaleValue(option,(char **) NULL);
+        draw_info->stroke_width=StringToDouble(option,(char **) NULL);
       option=GetImageOption(image_info,"undercolor");
       if (option != (const char *) NULL)
         (void) QueryColorCompliance(option,AllCompliance,&draw_info->undercolor,
@@ -4845,9 +4890,9 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
 %
 %
 */
-static inline MagickRealType Permutate(const ssize_t n,const ssize_t k)
+static inline double Permutate(const ssize_t n,const ssize_t k)
 {
-  MagickRealType
+  double
     r;
 
   register ssize_t
@@ -4892,10 +4937,10 @@ static void TraceArc(PrimitiveInfo *primitive_info,const PointInfo start,
 }
 
 static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
-  const PointInfo end,const PointInfo arc,const MagickRealType angle,
+  const PointInfo end,const PointInfo arc,const double angle,
   const MagickBooleanType large_arc,const MagickBooleanType sweep)
 {
-  MagickRealType
+  double
     alpha,
     beta,
     delta,
@@ -4908,7 +4953,7 @@ static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
     points[3],
     radii;
 
-  register MagickRealType
+  register double
     cosine,
     sine;
 
@@ -4955,7 +5000,7 @@ static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
   points[1].y=(double) (cosine*end.y/radii.y-sine*end.x/radii.y);
   alpha=points[1].x-points[0].x;
   beta=points[1].y-points[0].y;
-  factor=1.0/(alpha*alpha+beta*beta)-0.25;
+  factor=MagickEpsilonReciprocal(alpha*alpha+beta*beta)-0.25;
   if (factor <= 0.0)
     factor=0.0;
   else
@@ -4969,10 +5014,10 @@ static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
   alpha=atan2(points[0].y-center.y,points[0].x-center.x);
   theta=atan2(points[1].y-center.y,points[1].x-center.x)-alpha;
   if ((theta < 0.0) && (sweep != MagickFalse))
-    theta+=(MagickRealType) (2.0*MagickPI);
+    theta+=(double) (2.0*MagickPI);
   else
     if ((theta > 0.0) && (sweep == MagickFalse))
-      theta-=(MagickRealType) (2.0*MagickPI);
+      theta-=(double) (2.0*MagickPI);
   arc_segments=(size_t) ceil(fabs((double) (theta/(0.5*MagickPI+
     MagickEpsilon))));
   p=primitive_info;
@@ -5026,7 +5071,7 @@ static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
 static void TraceBezier(PrimitiveInfo *primitive_info,
   const size_t number_coordinates)
 {
-  MagickRealType
+  double
     alpha,
     *coefficients,
     weight;
@@ -5056,21 +5101,21 @@ static void TraceBezier(PrimitiveInfo *primitive_info,
     for (j=i+1; j < (ssize_t) number_coordinates; j++)
     {
       alpha=fabs(primitive_info[j].point.x-primitive_info[i].point.x);
-      if (alpha > (MagickRealType) quantum)
+      if (alpha > (double) quantum)
         quantum=(size_t) alpha;
       alpha=fabs(primitive_info[j].point.y-primitive_info[i].point.y);
-      if (alpha > (MagickRealType) quantum)
+      if (alpha > (double) quantum)
         quantum=(size_t) alpha;
     }
   }
   quantum=(size_t) MagickMin((double) quantum/number_coordinates,
     (double) BezierQuantum);
   control_points=quantum*number_coordinates;
-  coefficients=(MagickRealType *) AcquireQuantumMemory((size_t)
+  coefficients=(double *) AcquireQuantumMemory((size_t)
     number_coordinates,sizeof(*coefficients));
   points=(PointInfo *) AcquireQuantumMemory((size_t) control_points,
     sizeof(*points));
-  if ((coefficients == (MagickRealType *) NULL) ||
+  if ((coefficients == (double *) NULL) ||
       (points == (PointInfo *) NULL))
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   /*
@@ -5114,13 +5159,13 @@ static void TraceBezier(PrimitiveInfo *primitive_info,
     p--;
   }
   points=(PointInfo *) RelinquishMagickMemory(points);
-  coefficients=(MagickRealType *) RelinquishMagickMemory(coefficients);
+  coefficients=(double *) RelinquishMagickMemory(coefficients);
 }
 
 static void TraceCircle(PrimitiveInfo *primitive_info,const PointInfo start,
   const PointInfo end)
 {
-  MagickRealType
+  double
     alpha,
     beta,
     radius;
@@ -5142,7 +5187,7 @@ static void TraceCircle(PrimitiveInfo *primitive_info,const PointInfo start,
 static void TraceEllipse(PrimitiveInfo *primitive_info,const PointInfo start,
   const PointInfo stop,const PointInfo degrees)
 {
-  MagickRealType
+  double
     delta,
     step,
     y;
@@ -5166,9 +5211,9 @@ static void TraceEllipse(PrimitiveInfo *primitive_info,const PointInfo start,
       return;
     }
   delta=2.0/MagickMax(stop.x,stop.y);
-  step=(MagickRealType) (MagickPI/8.0);
-  if ((delta >= 0.0) && (delta < (MagickRealType) (MagickPI/8.0)))
-    step=(MagickRealType) (MagickPI/(4*(MagickPI/delta/2+0.5)));
+  step=(double) (MagickPI/8.0);
+  if ((delta >= 0.0) && (delta < (double) (MagickPI/8.0)))
+    step=(double) (MagickPI/(4*(MagickPI/delta/2+0.5)));
   angle.x=DegreesToRadians(degrees.x);
   y=degrees.y;
   while (y < degrees.x)
@@ -5197,8 +5242,8 @@ static void TraceLine(PrimitiveInfo *primitive_info,const PointInfo start,
   const PointInfo end)
 {
   TracePoint(primitive_info,start);
-  if ((fabs(start.x-end.x) <= MagickEpsilon) &&
-      (fabs(start.y-end.y) <= MagickEpsilon))
+  if ((fabs(start.x-end.x) < MagickEpsilon) &&
+      (fabs(start.y-end.y) < MagickEpsilon))
     {
       primitive_info->primitive=PointPrimitive;
       primitive_info->coordinates=1;
@@ -5221,7 +5266,7 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
     attribute,
     last_attribute;
 
-  MagickRealType
+  double
     x,
     y;
 
@@ -5270,7 +5315,7 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           large_arc,
           sweep;
 
-        MagickRealType
+        double
           angle;
 
         PointInfo
@@ -5284,15 +5329,15 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          arc.x=InterpretLocaleValue(token,(char **) NULL);
+          arc.x=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          arc.y=InterpretLocaleValue(token,(char **) NULL);
+          arc.y=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          angle=InterpretLocaleValue(token,(char **) NULL);
+          angle=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
@@ -5304,16 +5349,20 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          x=InterpretLocaleValue(token,(char **) NULL);
+          x=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          y=InterpretLocaleValue(token,(char **) NULL);
+          y=StringToDouble(token,(char **) NULL);
           end.x=(double) (attribute == (int) 'A' ? x : point.x+x);
           end.y=(double) (attribute == (int) 'A' ? y : point.y+y);
           TraceArcPath(q,point,end,arc,angle,large_arc,sweep);
           q+=q->coordinates;
           point=end;
+          while (isspace((int) ((unsigned char) *p)) != 0)
+            p++;
+          if (*p == ',')
+            p++;
         } while (IsPoint(p) != MagickFalse);
         break;
       }
@@ -5331,11 +5380,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            x=InterpretLocaleValue(token,(char **) NULL);
+            x=StringToDouble(token,(char **) NULL);
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            y=InterpretLocaleValue(token,(char **) NULL);
+            y=StringToDouble(token,(char **) NULL);
             end.x=(double) (attribute == (int) 'C' ? x : point.x+x);
             end.y=(double) (attribute == (int) 'C' ? y : point.y+y);
             points[i]=end;
@@ -5356,7 +5405,7 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          x=InterpretLocaleValue(token,(char **) NULL);
+          x=StringToDouble(token,(char **) NULL);
           point.x=(double) (attribute == (int) 'H' ? x: point.x+x);
           TracePoint(q,point);
           q+=q->coordinates;
@@ -5371,11 +5420,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          x=InterpretLocaleValue(token,(char **) NULL);
+          x=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          y=InterpretLocaleValue(token,(char **) NULL);
+          y=StringToDouble(token,(char **) NULL);
           point.x=(double) (attribute == (int) 'L' ? x : point.x+x);
           point.y=(double) (attribute == (int) 'L' ? y : point.y+y);
           TracePoint(q,point);
@@ -5398,11 +5447,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          x=InterpretLocaleValue(token,(char **) NULL);
+          x=StringToDouble(token,(char **) NULL);
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          y=InterpretLocaleValue(token,(char **) NULL);
+          y=StringToDouble(token,(char **) NULL);
           point.x=(double) (attribute == (int) 'M' ? x : point.x+x);
           point.y=(double) (attribute == (int) 'M' ? y : point.y+y);
           if (i == 0)
@@ -5432,11 +5481,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            x=InterpretLocaleValue(token,(char **) NULL);
+            x=StringToDouble(token,(char **) NULL);
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            y=InterpretLocaleValue(token,(char **) NULL);
+            y=StringToDouble(token,(char **) NULL);
             if (*p == ',')
               p++;
             end.x=(double) (attribute == (int) 'Q' ? x : point.x+x);
@@ -5467,11 +5516,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            x=InterpretLocaleValue(token,(char **) NULL);
+            x=StringToDouble(token,(char **) NULL);
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            y=InterpretLocaleValue(token,(char **) NULL);
+            y=StringToDouble(token,(char **) NULL);
             if (*p == ',')
               p++;
             end.x=(double) (attribute == (int) 'S' ? x : point.x+x);
@@ -5507,11 +5556,11 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            x=InterpretLocaleValue(token,(char **) NULL);
+            x=StringToDouble(token,(char **) NULL);
             GetMagickToken(p,&p,token);
             if (*token == ',')
               GetMagickToken(p,&p,token);
-            y=InterpretLocaleValue(token,(char **) NULL);
+            y=StringToDouble(token,(char **) NULL);
             end.x=(double) (attribute == (int) 'T' ? x : point.x+x);
             end.y=(double) (attribute == (int) 'T' ? y : point.y+y);
             points[i]=end;
@@ -5537,7 +5586,7 @@ static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
           GetMagickToken(p,&p,token);
           if (*token == ',')
             GetMagickToken(p,&p,token);
-          y=InterpretLocaleValue(token,(char **) NULL);
+          y=StringToDouble(token,(char **) NULL);
           point.y=(double) (attribute == (int) 'V' ? y : point.y+y);
           TracePoint(q,point);
           q+=q->coordinates;
@@ -5669,12 +5718,12 @@ static void TraceRoundRectangle(PrimitiveInfo *primitive_info,
 }
 
 static void TraceSquareLinecap(PrimitiveInfo *primitive_info,
-  const size_t number_vertices,const MagickRealType offset)
+  const size_t number_vertices,const double offset)
 {
-  MagickRealType
+  double
     distance;
 
-  register MagickRealType
+  register double
     dx,
     dy;
 
@@ -5716,6 +5765,16 @@ static void TraceSquareLinecap(PrimitiveInfo *primitive_info,
     dy*(distance+offset)/distance);
 }
 
+static inline double DrawEpsilonReciprocal(const double x)
+{
+#define DrawEpsilon  ((double) 1.0e-10)
+
+  double sign = x < (double) 0.0 ? (double) -1.0 :
+    (double) 1.0;
+  return((sign*x) >= DrawEpsilon ? (double) 1.0/x : sign*(
+    (double) 1.0/DrawEpsilon));
+}
+
 static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
   const PrimitiveInfo *primitive_info)
 {
@@ -5736,7 +5795,7 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
   MagickBooleanType
     closed_path;
 
-  MagickRealType
+  double
     delta_theta,
     dot_product,
     mid,
@@ -5809,30 +5868,10 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
   }
   if (n == (ssize_t) number_vertices)
     n=(ssize_t) number_vertices-1L;
-  slope.p=0.0;
-  inverse_slope.p=0.0;
-  if (fabs(dx.p) <= MagickEpsilon)
-    {
-      if (dx.p >= 0.0)
-        slope.p=dy.p < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
-      else
-        slope.p=dy.p < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
-    }
-  else
-    if (fabs(dy.p) <= MagickEpsilon)
-      {
-        if (dy.p >= 0.0)
-          inverse_slope.p=dx.p < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
-        else
-          inverse_slope.p=dx.p < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
-      }
-    else
-      {
-        slope.p=dy.p/dx.p;
-        inverse_slope.p=(-1.0/slope.p);
-      }
+  slope.p=DrawEpsilonReciprocal(dx.p)*dy.p;
+  inverse_slope.p=(-1.0*DrawEpsilonReciprocal(slope.p));
   mid=ExpandAffine(&draw_info->affine)*draw_info->stroke_width/2.0;
-  miterlimit=(MagickRealType) (draw_info->miterlimit*draw_info->miterlimit*
+  miterlimit=(double) (draw_info->miterlimit*draw_info->miterlimit*
     mid*mid);
   if ((draw_info->linecap == SquareCap) && (closed_path == MagickFalse))
     TraceSquareLinecap(polygon_primitive,number_vertices,mid);
@@ -5877,28 +5916,8 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
     dot_product=dx.q*dx.q+dy.q*dy.q;
     if (dot_product < 0.25)
       continue;
-    slope.q=0.0;
-    inverse_slope.q=0.0;
-    if (fabs(dx.q) < MagickEpsilon)
-      {
-        if (dx.q >= 0.0)
-          slope.q=dy.q < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
-        else
-          slope.q=dy.q < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
-      }
-    else
-      if (fabs(dy.q) <= MagickEpsilon)
-        {
-          if (dy.q >= 0.0)
-            inverse_slope.q=dx.q < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
-          else
-            inverse_slope.q=dx.q < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
-        }
-      else
-        {
-          slope.q=dy.q/dx.q;
-          inverse_slope.q=(-1.0/slope.q);
-        }
+    slope.q=DrawEpsilonReciprocal(dx.q)*dy.q;
+    inverse_slope.q=(-1.0*DrawEpsilonReciprocal(slope.q));
     offset.x=sqrt((double) (mid*mid/(inverse_slope.q*inverse_slope.q+1.0)));
     offset.y=(double) (offset.x*inverse_slope.q);
     dot_product=dy.q*offset.x-dx.q*offset.y;
@@ -5924,7 +5943,7 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
         box_q[3].x=polygon_primitive[i].point.x-offset.x;
         box_q[3].y=polygon_primitive[i].point.y-offset.y;
       }
-    if (fabs((double) (slope.p-slope.q)) <= MagickEpsilon)
+    if (fabs((double) (slope.p-slope.q)) < MagickEpsilon)
       {
         box_p[4]=box_p[1];
         box_q[4]=box_q[1];
@@ -6004,7 +6023,7 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
           theta.p=atan2(box_q[1].y-center.y,box_q[1].x-center.x);
           theta.q=atan2(box_q[2].y-center.y,box_q[2].x-center.x);
           if (theta.q < theta.p)
-            theta.q+=(MagickRealType) (2.0*MagickPI);
+            theta.q+=(double) (2.0*MagickPI);
           arc_segments=(size_t) ceil((double) ((theta.q-theta.p)/
             (2.0*sqrt((double) (1.0/mid)))));
           path_q[q].x=box_q[1].x;
@@ -6012,7 +6031,7 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
           q++;
           for (j=1; j < (ssize_t) arc_segments; j++)
           {
-            delta_theta=(MagickRealType) (j*(theta.q-theta.p)/arc_segments);
+            delta_theta=(double) (j*(theta.q-theta.p)/arc_segments);
             path_q[q].x=(double) (center.x+mid*cos(fmod((double)
               (theta.p+delta_theta),DegreesToRadians(360.0))));
             path_q[q].y=(double) (center.y+mid*sin(fmod((double)
@@ -6076,13 +6095,13 @@ static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
           theta.p=atan2(box_p[1].y-center.y,box_p[1].x-center.x);
           theta.q=atan2(box_p[2].y-center.y,box_p[2].x-center.x);
           if (theta.p < theta.q)
-            theta.p+=(MagickRealType) (2.0*MagickPI);
+            theta.p+=(double) (2.0*MagickPI);
           arc_segments=(size_t) ceil((double) ((theta.p-theta.q)/
             (2.0*sqrt((double) (1.0/mid)))));
           path_p[p++]=box_p[1];
           for (j=1; j < (ssize_t) arc_segments; j++)
           {
-            delta_theta=(MagickRealType) (j*(theta.q-theta.p)/arc_segments);
+            delta_theta=(double) (j*(theta.q-theta.p)/arc_segments);
             path_p[p].x=(double) (center.x+mid*cos(fmod((double)
               (theta.p+delta_theta),DegreesToRadians(360.0))));
             path_p[p].y=(double) (center.y+mid*sin(fmod((double)