13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      PPPP    AAA   IIIII  N   N  TTTTT                      %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      P   P  A   A    I    NN  N    T                        %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      PPPP   AAAAA    I    N N N    T                        %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      P      A   A    I    N  NN    T                        %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      P      A   A  IIIII  N   N    T                        %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        Methods to Paint on an Image                         %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                 July 1998                                   %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
207ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Include declarations.
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
424c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
43542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy#include "MagickCore/artifact.h"
446a2180cee55312a7c0c633670803f9face88a82acristy#include "MagickCore/channel.h"
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace-private.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite.h"
494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite-private.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw.h"
514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw-private.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h"
558ea81224e9ff022e56eb2cddb12860a8b2e90411cristy#include "MagickCore/gem-private.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h"
58971aac4f549b1ff5321a6514714dae9354bfa459Cristy#include "MagickCore/option.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/paint.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
61ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h"
6295f562af68c6bc67f4137b985c7d05c4eff4fddacristy#include "MagickCore/statistic.h"
634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
6416f2933cdc208138fe39595082c0d3841d93739cCristy#include "MagickCore/string-private.h"
654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/thread-private.h"
663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   F l o o d f i l l P a i n t I m a g e                                     %
733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  FloodfillPaintImage() changes the color value of any pixel that matches
793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  target and is an immediate neighbor.  If the method FillToBorderMethod is
803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specified, the color value is changed for any neighbor pixel that does not
813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  match the bordercolor member of image.
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
83908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  By default target must match a particular pixel color exactly.  However,
84908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  in many cases two colors may differ by a small amount.  The fuzz member of
85908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  image defines how much tolerance is acceptable to consider two colors as
86908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  the same.  For example, set fuzz to 10 and the color red at intensities of
87908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  100 and 102 respectively are now interpreted as the same color for the
88908a0004c30aade661256ab433bdbe5c4dbce23ccristy%  purposes of the floodfill.
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the FloodfillPaintImage method is:
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType FloodfillPaintImage(Image *image,
93d42d995b9cb2a16e13221e665554417a5b7ec7fbcristy%        const DrawInfo *draw_info,const PixelInfo target,
94d42d995b9cb2a16e13221e665554417a5b7ec7fbcristy%        const ssize_t x_offset,const ssize_t y_offset,
95189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%        const MagickBooleanType invert,ExceptionInfo *exception)
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o draw_info: the draw info.
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o target: the RGB value of the target color.
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o x_offset,y_offset: the starting location of the operation.
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o invert: paint any pixel that does not match the target color.
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
109189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%    o exception: return any errors or warnings in this structure.
110189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType FloodfillPaintImage(Image *image,
113d42d995b9cb2a16e13221e665554417a5b7ec7fbcristy  const DrawInfo *draw_info,const PixelInfo *target,const ssize_t x_offset,
114189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  const ssize_t y_offset,const MagickBooleanType invert,
115189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  ExceptionInfo *exception)
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
117712467450377a5c8642d6f4aead1f11d803c78a9Cristy#define MaxStacksize  524288UL
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define PushSegmentStack(up,left,right,delta) \
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ \
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (s >= (segment_stack+MaxStacksize)) \
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else \
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    { \
124bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        { \
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          s->x1=(double) (left); \
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          s->y1=(double) (up); \
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          s->x2=(double) (right); \
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          s->y2=(double) (delta); \
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          s++; \
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        } \
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    } \
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
135b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy  CacheView
136b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    *floodplane_view,
137b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    *image_view;
138b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
1403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *floodplane_image;
1413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
14314973baa8fa5c79889bc4db247200bb7d4626324cristy    skip,
14414973baa8fa5c79889bc4db247200bb7d4626324cristy    status;
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
146aaaff84e53c6dba4988fc076523eb820fdecd084cristy  MemoryInfo
147aaaff84e53c6dba4988fc076523eb820fdecd084cristy    *segment_info;
148aaaff84e53c6dba4988fc076523eb820fdecd084cristy
1494c08aed51c5899665ade97263692328eea4af106cristy  PixelInfo
150fdcc0185fe19084d4009bfc6e2fead8d86c67e64cristy    fill_color,
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel;
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register SegmentInfo
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *s;
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SegmentInfo
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *segment_stack;
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1599d314ff2c17a77996c05413c2013880387e50f0ecristy  ssize_t
1609d314ff2c17a77996c05413c2013880387e50f0ecristy    offset,
1619d314ff2c17a77996c05413c2013880387e50f0ecristy    start,
1629d314ff2c17a77996c05413c2013880387e50f0ecristy    x1,
1639d314ff2c17a77996c05413c2013880387e50f0ecristy    x2,
1649d314ff2c17a77996c05413c2013880387e50f0ecristy    y;
1659d314ff2c17a77996c05413c2013880387e50f0ecristy
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Check boundary conditions.
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
170e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(draw_info != (DrawInfo *) NULL);
174e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(draw_info->signature == MagickCoreSignature);
175bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
177bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
179574cc26500992189f637cd1cdf93d0654e7df7aecristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
181a6400b1cfc3594644a0f02f3d77d920092f078eecristy  if (IsGrayColorspace(image->colorspace) != MagickFalse)
1820c81d063030f7b30a97c7856e95534243cdc9e13cristy    (void) SetImageColorspace(image,sRGBColorspace,exception);
18317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy  if ((image->alpha_trait == UndefinedPixelTrait) &&
18417f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      (draw_info->fill.alpha_trait != UndefinedPixelTrait))
1855b67d4ea6079617babbc0142af28ed2d23040239cristy    (void) SetImageAlpha(image,OpaqueAlpha,exception);
1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
1873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Set floodfill state.
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
18995f562af68c6bc67f4137b985c7d05c4eff4fddacristy  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
19095f562af68c6bc67f4137b985c7d05c4eff4fddacristy    exception);
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (floodplane_image == (Image *) NULL)
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
1938a46d827a124555f0c48fb2368ec1bba8e079ab6cristy  floodplane_image->alpha_trait=UndefinedPixelTrait;
1942099010c8d4783cea99527ba89e157023c13ff95cristy  floodplane_image->colorspace=GRAYColorspace;
1952099010c8d4783cea99527ba89e157023c13ff95cristy  (void) QueryColorCompliance("#000",AllCompliance,
1962099010c8d4783cea99527ba89e157023c13ff95cristy    &floodplane_image->background_color,exception);
1972099010c8d4783cea99527ba89e157023c13ff95cristy  (void) SetImageBackgroundColor(floodplane_image,exception);
198aaaff84e53c6dba4988fc076523eb820fdecd084cristy  segment_info=AcquireVirtualMemory(MaxStacksize,sizeof(*segment_stack));
199aaaff84e53c6dba4988fc076523eb820fdecd084cristy  if (segment_info == (MemoryInfo *) NULL)
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      floodplane_image=DestroyImage(floodplane_image);
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        image->filename);
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
205aaaff84e53c6dba4988fc076523eb820fdecd084cristy  segment_stack=(SegmentInfo *) GetVirtualMemoryBlob(segment_info);
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Push initial segment on stack.
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
20914973baa8fa5c79889bc4db247200bb7d4626324cristy  status=MagickTrue;
2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  start=0;
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=segment_stack;
212aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk  PushSegmentStack(y_offset,x_offset,x_offset,1);
213aa6a11c893e812e2b1f1c425353eaf72d3501a9edirk  PushSegmentStack(y_offset+1,x_offset,x_offset,-1);
2144c08aed51c5899665ade97263692328eea4af106cristy  GetPixelInfo(image,&pixel);
21546ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireVirtualCacheView(image,exception);
21646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  floodplane_view=AcquireAuthenticCacheView(floodplane_image,exception);
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  while (s > segment_stack)
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
2194c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
22005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2224c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
22305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22514973baa8fa5c79889bc4db247200bb7d4626324cristy    register ssize_t
22614973baa8fa5c79889bc4db247200bb7d4626324cristy      x;
22714973baa8fa5c79889bc4db247200bb7d4626324cristy
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Pop segment off stack.
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    s--;
232bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    x1=(ssize_t) s->x1;
233bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    x2=(ssize_t) s->x2;
234bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    offset=(ssize_t) s->y2;
235bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    y=(ssize_t) s->y1+offset;
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Recolor neighboring pixels.
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
239b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
240b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
2424c08aed51c5899665ade97263692328eea4af106cristy    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
244ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy    p+=x1*GetPixelChannels(image);
245ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy    q+=x1*GetPixelChannels(floodplane_image);
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for (x=x1; x >= 0; x--)
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
24895f562af68c6bc67f4137b985c7d05c4eff4fddacristy      if (GetPixelGray(floodplane_image,q) != 0)
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
250803640d20a6a664315eddfff6f8531d0c5e0871dcristy      GetPixelInfoPixel(image,p,&pixel);
2514c08aed51c5899665ade97263692328eea4af106cristy      if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
25395f562af68c6bc67f4137b985c7d05c4eff4fddacristy      SetPixelGray(floodplane_image,QuantumRange,q);
254ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p-=GetPixelChannels(image);
255ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q-=GetPixelChannels(floodplane_image);
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
257b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    skip=x >= x1 ? MagickTrue : MagickFalse;
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (skip == MagickFalse)
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        start=x+1;
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (start < x1)
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          PushSegmentStack(y,start,x1-1,-offset);
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        x=x1+1;
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    do
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (skip == MagickFalse)
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
271bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          if (x < (ssize_t) image->columns)
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
273b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy              p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                exception);
275fdcc0185fe19084d4009bfc6e2fead8d86c67e64cristy              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,image->columns-
276fdcc0185fe19084d4009bfc6e2fead8d86c67e64cristy                x,1,exception);
277636dcb5dafb00d5c92540bb56bd04724f1535bf2cristy              if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                break;
279bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy              for ( ; x < (ssize_t) image->columns; x++)
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              {
28195f562af68c6bc67f4137b985c7d05c4eff4fddacristy                if (GetPixelGray(floodplane_image,q) != 0)
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  break;
283803640d20a6a664315eddfff6f8531d0c5e0871dcristy                GetPixelInfoPixel(image,p,&pixel);
2844c08aed51c5899665ade97263692328eea4af106cristy                if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  break;
28695f562af68c6bc67f4137b985c7d05c4eff4fddacristy                SetPixelGray(floodplane_image,QuantumRange,q);
287ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy                p+=GetPixelChannels(image);
288ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy                q+=GetPixelChannels(floodplane_image);
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              }
29014973baa8fa5c79889bc4db247200bb7d4626324cristy              status=SyncCacheViewAuthenticPixels(floodplane_view,exception);
29114973baa8fa5c79889bc4db247200bb7d4626324cristy              if (status == MagickFalse)
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                break;
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          PushSegmentStack(y,start,x-1,offset);
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (x > (x2+1))
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            PushSegmentStack(y,x2+1,x-1,-offset);
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      skip=MagickFalse;
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x++;
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (x <= x2)
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
302b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy          p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
303b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy            exception);
304b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy          q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            exception);
306636dcb5dafb00d5c92540bb56bd04724f1535bf2cristy          if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          for ( ; x <= x2; x++)
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
31095f562af68c6bc67f4137b985c7d05c4eff4fddacristy            if (GetPixelGray(floodplane_image,q) != 0)
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
312803640d20a6a664315eddfff6f8531d0c5e0871dcristy            GetPixelInfoPixel(image,p,&pixel);
3134c08aed51c5899665ade97263692328eea4af106cristy            if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
315ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy            p+=GetPixelChannels(image);
316ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy            q+=GetPixelChannels(floodplane_image);
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      start=x;
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    } while (x <= x2);
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
322aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk  status=MagickTrue;
323aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk#if defined(MAGICKCORE_OPENMP_SUPPORT)
324aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk  #pragma omp parallel for schedule(static,4) shared(status) \
325aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk    magick_threads(floodplane_image,image,floodplane_image->rows,1)
326aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk#endif
327bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3294c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
33005d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3324c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
33305d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
33514973baa8fa5c79889bc4db247200bb7d4626324cristy    register ssize_t
33614973baa8fa5c79889bc4db247200bb7d4626324cristy      x;
33714973baa8fa5c79889bc4db247200bb7d4626324cristy
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Tile fill color onto floodplane.
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
341aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk    if (status == MagickFalse)
342aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk      continue;
34395f562af68c6bc67f4137b985c7d05c4eff4fddacristy    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,exception);
344b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3454c08aed51c5899665ade97263692328eea4af106cristy    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
346aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk      {
347aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk        status=MagickFalse;
348aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk        continue;
349aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk      }
350bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
35295f562af68c6bc67f4137b985c7d05c4eff4fddacristy      if (GetPixelGray(floodplane_image,p) != 0)
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
35450be538de7d724dfbd0cba7d434d1404b49ce90ddirk          GetFillColor(draw_info,x,y,&fill_color,exception);
35511a06d3f2cac0f17af7963e83bc6e9ebd2a377c0cristy          SetPixelViaPixelInfo(image,&fill_color,q);
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
357ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      p+=GetPixelChannels(floodplane_image);
358ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
360b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
361aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk      status=MagickFalse;
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
363b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy  floodplane_view=DestroyCacheView(floodplane_view);
364b0d3bb93a8f69add9d2d000ff20e6951e3c1f885cristy  image_view=DestroyCacheView(image_view);
365aaaff84e53c6dba4988fc076523eb820fdecd084cristy  segment_info=RelinquishVirtualMemory(segment_info);
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  floodplane_image=DestroyImage(floodplane_image);
367aff02c2233a720f8a115f32d6d8db0dbe179dc86dirk  return(status);
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+     G r a d i e n t I m a g e                                               %
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
381cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy%  GradientImage() applies a continuously smooth color transitions along a
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  vector from one color to another.
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Note, the interface of this method will change in the future to support
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  more than one transistion.
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the GradientImage method is:
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType GradientImage(Image *image,const GradientType type,
390101ab708b0574518ac5715da4d3915400e9df79acristy%        const SpreadMethod method,const PixelInfo *start_color,
391101ab708b0574518ac5715da4d3915400e9df79acristy%        const PixelInfo *stop_color,ExceptionInfo *exception)
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o type: the gradient type: linear or radial.
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o spread: the gradient spread meathod: pad, reflect, or repeat.
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o start_color: the start color.
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o stop_color: the stop color.
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
405189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%    o exception: return any errors or warnings in this structure.
406189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
4087b575810f9584064cacda46e4917a1999199b06ddirkMagickExport MagickBooleanType GradientImage(Image *image,
40916f2933cdc208138fe39595082c0d3841d93739cCristy  const GradientType type,const SpreadMethod method,const StopInfo *stops,
41016f2933cdc208138fe39595082c0d3841d93739cCristy  const size_t number_stops,ExceptionInfo *exception)
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
41216f2933cdc208138fe39595082c0d3841d93739cCristy  const char
413542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy    *artifact;
41416f2933cdc208138fe39595082c0d3841d93739cCristy
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DrawInfo
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *draw_info;
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GradientInfo
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *gradient;
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Set gradient start-stop end points.
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (const Image *) NULL);
428e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
431b6f578bf802306a759e9c1b51c8edc4d2041ec9bdirk  assert(stops != (const StopInfo *) NULL);
432b6f578bf802306a759e9c1b51c8edc4d2041ec9bdirk  assert(number_stops > 0);
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  draw_info=AcquireDrawInfo();
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient=(&draw_info->gradient);
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->type=type;
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->bounding_box.width=image->columns;
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->bounding_box.height=image->rows;
438542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy  artifact=GetImageArtifact(image,"gradient:bounding-box");
439542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy  if (artifact != (const char *) NULL)
440542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy    (void) ParseAbsoluteGeometry(artifact,&gradient->bounding_box);
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->gradient_vector.x2=(double) image->columns-1.0;
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->gradient_vector.y2=(double) image->rows-1.0;
443971aac4f549b1ff5321a6514714dae9354bfa459Cristy  artifact=GetImageArtifact(image,"gradient:direction");
444542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy  if (artifact != (const char *) NULL)
44516f2933cdc208138fe39595082c0d3841d93739cCristy    {
446971aac4f549b1ff5321a6514714dae9354bfa459Cristy      GravityType
447971aac4f549b1ff5321a6514714dae9354bfa459Cristy        direction;
448971aac4f549b1ff5321a6514714dae9354bfa459Cristy
449971aac4f549b1ff5321a6514714dae9354bfa459Cristy      direction=(GravityType) ParseCommandOption(MagickGravityOptions,
450971aac4f549b1ff5321a6514714dae9354bfa459Cristy        MagickFalse,artifact);
451971aac4f549b1ff5321a6514714dae9354bfa459Cristy      switch (direction)
452971aac4f549b1ff5321a6514714dae9354bfa459Cristy      {
453971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case NorthWestGravity:
454971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
455971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=(double) image->columns-1.0;
456971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=(double) image->rows-1.0;
457971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=0.0;
458971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=0.0;
459971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
460971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
461971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case NorthGravity:
462971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
463971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=0.0;
464971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=(double) image->rows-1.0;
465971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=0.0;
466971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=0.0;
467971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
468971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
469971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case NorthEastGravity:
470971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
471971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=0.0;
472971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=(double) image->rows-1.0;
473971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=(double) image->columns-1.0;
474971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=0.0;
475971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
476971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
477971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case WestGravity:
478971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
479971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=(double) image->columns-1.0;
480971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=0.0;
481971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=0.0;
482971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=0.0;
483971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
484971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
485971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case EastGravity:
486971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
487971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=0.0;
488971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=0.0;
489971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=(double) image->columns-1.0;
490971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=0.0;
491971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
492971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
493971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case SouthWestGravity:
494971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
495971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=(double) image->columns-1.0;
496971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=0.0;
497971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=0.0;
498971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=(double) image->rows-1.0;
499971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
500971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
501971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case SouthGravity:
502971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
503971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=0.0;
504971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=0.0;
505971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=0.0;
506971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=(double) image->columns-1.0;
507971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
508971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
509971aac4f549b1ff5321a6514714dae9354bfa459Cristy        case SouthEastGravity:
510971aac4f549b1ff5321a6514714dae9354bfa459Cristy        {
511971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x1=0.0;
512971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y1=0.0;
513971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.x2=(double) image->columns-1.0;
514971aac4f549b1ff5321a6514714dae9354bfa459Cristy          gradient->gradient_vector.y2=(double) image->rows-1.0;
515971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
516971aac4f549b1ff5321a6514714dae9354bfa459Cristy        }
517971aac4f549b1ff5321a6514714dae9354bfa459Cristy        default:
518971aac4f549b1ff5321a6514714dae9354bfa459Cristy          break;
519971aac4f549b1ff5321a6514714dae9354bfa459Cristy      }
52016f2933cdc208138fe39595082c0d3841d93739cCristy    }
521971aac4f549b1ff5321a6514714dae9354bfa459Cristy  artifact=GetImageArtifact(image,"gradient:angle");
522971aac4f549b1ff5321a6514714dae9354bfa459Cristy  if (artifact != (const char *) NULL)
52395264c47a4a04033f2c1688819282e27bcf3f8b5Cristy    gradient->angle=StringToDouble(artifact,(char **) NULL);
524971aac4f549b1ff5321a6514714dae9354bfa459Cristy  artifact=GetImageArtifact(image,"gradient:vector");
525971aac4f549b1ff5321a6514714dae9354bfa459Cristy  if (artifact != (const char *) NULL)
526971aac4f549b1ff5321a6514714dae9354bfa459Cristy    (void) sscanf(artifact,"%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf",
527971aac4f549b1ff5321a6514714dae9354bfa459Cristy      &gradient->gradient_vector.x1,&gradient->gradient_vector.y1,
528971aac4f549b1ff5321a6514714dae9354bfa459Cristy      &gradient->gradient_vector.x2,&gradient->gradient_vector.y2);
529f70f909b81f1b22be16a68856e56a975bd4c5454Cristy  if ((GetImageArtifact(image,"gradient:angle") == (const char *) NULL) &&
530f70f909b81f1b22be16a68856e56a975bd4c5454Cristy      (GetImageArtifact(image,"gradient:direction") == (const char *) NULL) &&
531f70f909b81f1b22be16a68856e56a975bd4c5454Cristy      (GetImageArtifact(image,"gradient:extent") == (const char *) NULL) &&
5329e46e8aa51c9bd73e8512c530ce3a74aef688f11Cristy      (GetImageArtifact(image,"gradient:vector") == (const char *) NULL))
5334f11a391a1d0ded2b4af92311fca972977661a88Cristy    if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
5344f11a391a1d0ded2b4af92311fca972977661a88Cristy      gradient->gradient_vector.x2=0.0;
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
537542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy  artifact=GetImageArtifact(image,"gradient:center");
538542697a1562bf7aef0df9d3e26add9e29373b3a9Cristy  if (artifact != (const char *) NULL)
539971aac4f549b1ff5321a6514714dae9354bfa459Cristy    (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->center.x,
540971aac4f549b1ff5321a6514714dae9354bfa459Cristy      &gradient->center.y);
541c757d75f28b1234bc1e466ca740f5c146f37936eCristy  artifact=GetImageArtifact(image,"gradient:angle");
542c757d75f28b1234bc1e466ca740f5c146f37936eCristy  if ((type == LinearGradient) && (artifact != (const char *) NULL))
543c757d75f28b1234bc1e466ca740f5c146f37936eCristy    {
544c757d75f28b1234bc1e466ca740f5c146f37936eCristy      double
545c757d75f28b1234bc1e466ca740f5c146f37936eCristy        sine,
546c757d75f28b1234bc1e466ca740f5c146f37936eCristy        cosine,
547c757d75f28b1234bc1e466ca740f5c146f37936eCristy        distance;
548c757d75f28b1234bc1e466ca740f5c146f37936eCristy
549c757d75f28b1234bc1e466ca740f5c146f37936eCristy      /*
550c757d75f28b1234bc1e466ca740f5c146f37936eCristy        Reference https://drafts.csswg.org/css-images-3/#linear-gradients.
551c757d75f28b1234bc1e466ca740f5c146f37936eCristy      */
552c757d75f28b1234bc1e466ca740f5c146f37936eCristy      sine=sin((double) DegreesToRadians(gradient->angle-90.0));
553c757d75f28b1234bc1e466ca740f5c146f37936eCristy      cosine=cos((double) DegreesToRadians(gradient->angle-90.0));
554c757d75f28b1234bc1e466ca740f5c146f37936eCristy      distance=fabs((double) image->columns*cosine)+
555c757d75f28b1234bc1e466ca740f5c146f37936eCristy        fabs((double) image->rows*sine);
556c757d75f28b1234bc1e466ca740f5c146f37936eCristy      gradient->gradient_vector.x1=0.5*(image->columns-distance*cosine);
557c757d75f28b1234bc1e466ca740f5c146f37936eCristy      gradient->gradient_vector.y1=0.5*(image->rows-distance*sine);
558c757d75f28b1234bc1e466ca740f5c146f37936eCristy      gradient->gradient_vector.x2=0.5*(image->columns+distance*cosine);
559c757d75f28b1234bc1e466ca740f5c146f37936eCristy      gradient->gradient_vector.y2=0.5*(image->rows+distance*sine);
560c757d75f28b1234bc1e466ca740f5c146f37936eCristy    }
561b2d350c97b5b7796cb5c867cfcf92c73b1cf44e1Cristy  gradient->radii.x=(double) MagickMax(image->columns,image->rows)/2.0;
562abd2f5a29e1239a14c10f5219f4c18d1815ab9e3Cristy  gradient->radii.y=gradient->radii.x;
563f70f909b81f1b22be16a68856e56a975bd4c5454Cristy  artifact=GetImageArtifact(image,"gradient:extent");
564f70f909b81f1b22be16a68856e56a975bd4c5454Cristy  if (artifact != (const char *) NULL)
565f70f909b81f1b22be16a68856e56a975bd4c5454Cristy    {
566c9dbca3091582bcb9f705775e798d58e6360908dCristy      if (LocaleCompare(artifact,"Circle") == 0)
567c9dbca3091582bcb9f705775e798d58e6360908dCristy        {
568b2d350c97b5b7796cb5c867cfcf92c73b1cf44e1Cristy          gradient->radii.x=(double) MagickMax(image->columns,image->rows)/2.0;
569c9dbca3091582bcb9f705775e798d58e6360908dCristy          gradient->radii.y=gradient->radii.x;
570c9dbca3091582bcb9f705775e798d58e6360908dCristy        }
571f70f909b81f1b22be16a68856e56a975bd4c5454Cristy      if (LocaleCompare(artifact,"Diagonal") == 0)
572f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        {
5732526e880b74424d234db67a26e7d466bc920c068Cristy          gradient->radii.x=(double) (sqrt(image->columns*image->columns+
5742526e880b74424d234db67a26e7d466bc920c068Cristy            image->rows*image->rows))/2.0;
5750357183a8cdd6769d3e3879b9bd3ea9cd7c2491dCristy          gradient->radii.y=gradient->radii.x;
576f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        }
577f70f909b81f1b22be16a68856e56a975bd4c5454Cristy      if (LocaleCompare(artifact,"Ellipse") == 0)
578f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        {
5790357183a8cdd6769d3e3879b9bd3ea9cd7c2491dCristy          gradient->radii.x=(double) image->columns/2.0;
5800357183a8cdd6769d3e3879b9bd3ea9cd7c2491dCristy          gradient->radii.y=(double) image->rows/2.0;
581f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        }
582c9dbca3091582bcb9f705775e798d58e6360908dCristy      if (LocaleCompare(artifact,"Maximum") == 0)
583c9dbca3091582bcb9f705775e798d58e6360908dCristy        {
584b2d350c97b5b7796cb5c867cfcf92c73b1cf44e1Cristy          gradient->radii.x=(double) MagickMax(image->columns,image->rows)/2.0;
585c9dbca3091582bcb9f705775e798d58e6360908dCristy          gradient->radii.y=gradient->radii.x;
586c9dbca3091582bcb9f705775e798d58e6360908dCristy        }
587a578020ecc9886360d733960cf33ecc611344550Cristy      if (LocaleCompare(artifact,"Minimum") == 0)
588f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        {
5892526e880b74424d234db67a26e7d466bc920c068Cristy          gradient->radii.x=(double) (MagickMin(image->columns,image->rows))/
5902526e880b74424d234db67a26e7d466bc920c068Cristy            2.0;
591f70f909b81f1b22be16a68856e56a975bd4c5454Cristy          gradient->radii.y=gradient->radii.x;
592f70f909b81f1b22be16a68856e56a975bd4c5454Cristy        }
593f70f909b81f1b22be16a68856e56a975bd4c5454Cristy    }
594c757d75f28b1234bc1e466ca740f5c146f37936eCristy  artifact=GetImageArtifact(image,"gradient:radii");
595c757d75f28b1234bc1e466ca740f5c146f37936eCristy  if (artifact != (const char *) NULL)
596c757d75f28b1234bc1e466ca740f5c146f37936eCristy    (void) sscanf(artifact,"%lf%*[ ,]%lf",&gradient->radii.x,
597c757d75f28b1234bc1e466ca740f5c146f37936eCristy      &gradient->radii.y);
59850a6c9d68214f8b6a551d0e07b84035c1794213bCristy  gradient->radius=MagickMax(gradient->radii.x,gradient->radii.y);
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->spread=method;
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Define the gradient to fill between the stops.
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
603b6f578bf802306a759e9c1b51c8edc4d2041ec9bdirk  gradient->number_stops=number_stops;
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*gradient->stops));
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (gradient->stops == (StopInfo *) NULL)
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
609b6f578bf802306a759e9c1b51c8edc4d2041ec9bdirk  (void) CopyMagickMemory(gradient->stops,stops,(size_t) number_stops*
610b6f578bf802306a759e9c1b51c8edc4d2041ec9bdirk    sizeof(*stops));
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Draw a gradient on the image.
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
614947cb4c68bebf79b15b6f3e824bc973491a77709cristy  status=DrawGradientImage(image,draw_info,exception);
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  draw_info=DestroyDrawInfo(draw_info);
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     O i l P a i n t I m a g e                                               %
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  OilPaintImage() applies a special effect filter that simulates an oil
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  painting.  Each pixel is replaced by the most frequent color occurring
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  in a circular region defined by radius.
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the OilPaintImage method is:
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Image *OilPaintImage(const Image *image,const double radius,
63714973baa8fa5c79889bc4db247200bb7d4626324cristy%        const double sigma,ExceptionInfo *exception)
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o radius: the radius of the circular neighborhood.
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
64514973baa8fa5c79889bc4db247200bb7d4626324cristy%    o sigma: the standard deviation of the Gaussian, in pixels.
64614973baa8fa5c79889bc4db247200bb7d4626324cristy%
6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
651bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic size_t **DestroyHistogramThreadSet(size_t **histogram)
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
653bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
656bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  assert(histogram != (size_t **) NULL);
657ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
658bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    if (histogram[i] != (size_t *) NULL)
659bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      histogram[i]=(size_t *) RelinquishMagickMemory(histogram[i]);
660b41ee108904d5e1e75fd6a944caeceb5c7d6e64acristy  histogram=(size_t **) RelinquishMagickMemory(histogram);
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(histogram);
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
664bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic size_t **AcquireHistogramThreadSet(const size_t count)
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
666bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
669bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    **histogram,
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_threads;
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6739357bdd9a30c3d65ef8812e45220f7552dc4376bcristy  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
67414973baa8fa5c79889bc4db247200bb7d4626324cristy  histogram=(size_t **) AcquireQuantumMemory(number_threads,sizeof(*histogram));
675bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if (histogram == (size_t **) NULL)
676bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    return((size_t **) NULL);
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
678bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) number_threads; i++)
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
68014973baa8fa5c79889bc4db247200bb7d4626324cristy    histogram[i]=(size_t *) AcquireQuantumMemory(count,sizeof(**histogram));
681bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    if (histogram[i] == (size_t *) NULL)
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(DestroyHistogramThreadSet(histogram));
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(histogram);
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport Image *OilPaintImage(const Image *image,const double radius,
68814973baa8fa5c79889bc4db247200bb7d4626324cristy  const double sigma,ExceptionInfo *exception)
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define NumberPaintBins  256
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define OilPaintImageTag  "OilPaint/Image"
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
693fa11211cadba55e3e038b805478e55b25908a152cristy  CacheView
694fa11211cadba55e3e038b805478e55b25908a152cristy    *image_view,
695fa11211cadba55e3e038b805478e55b25908a152cristy    *paint_view;
696fa11211cadba55e3e038b805478e55b25908a152cristy
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
698404d0da35379e582eac5248a1b44184decd13eefcristy    *linear_image,
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *paint_image;
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
704bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  MagickOffsetType
705bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    progress;
706bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
707bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
70814973baa8fa5c79889bc4db247200bb7d4626324cristy    **histograms,
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    width;
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
711bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
712f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy    center,
713bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    y;
714bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize painted image attributes.
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (const Image *) NULL);
719e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
723e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
72414973baa8fa5c79889bc4db247200bb7d4626324cristy  width=GetOptimalKernelWidth2D(radius,sigma);
725404d0da35379e582eac5248a1b44184decd13eefcristy  linear_image=CloneImage(image,0,0,MagickTrue,exception);
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
727404d0da35379e582eac5248a1b44184decd13eefcristy  if ((linear_image == (Image *) NULL) || (paint_image == (Image *) NULL))
728404d0da35379e582eac5248a1b44184decd13eefcristy    {
729404d0da35379e582eac5248a1b44184decd13eefcristy      if (linear_image != (Image *) NULL)
730404d0da35379e582eac5248a1b44184decd13eefcristy        linear_image=DestroyImage(linear_image);
731404d0da35379e582eac5248a1b44184decd13eefcristy      if (paint_image != (Image *) NULL)
732404d0da35379e582eac5248a1b44184decd13eefcristy        linear_image=DestroyImage(paint_image);
733404d0da35379e582eac5248a1b44184decd13eefcristy      return((Image *) NULL);
734404d0da35379e582eac5248a1b44184decd13eefcristy    }
735574cc26500992189f637cd1cdf93d0654e7df7aecristy  if (SetImageStorageClass(paint_image,DirectClass,exception) == MagickFalse)
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
737404d0da35379e582eac5248a1b44184decd13eefcristy      linear_image=DestroyImage(linear_image);
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      paint_image=DestroyImage(paint_image);
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return((Image *) NULL);
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  histograms=AcquireHistogramThreadSet(NumberPaintBins);
742bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  if (histograms == (size_t **) NULL)
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
744404d0da35379e582eac5248a1b44184decd13eefcristy      linear_image=DestroyImage(linear_image);
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      paint_image=DestroyImage(paint_image);
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Oil paint image.
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  progress=0;
753404d0da35379e582eac5248a1b44184decd13eefcristy  center=(ssize_t) GetPixelChannels(linear_image)*(linear_image->columns+width)*
754404d0da35379e582eac5248a1b44184decd13eefcristy    (width/2L)+GetPixelChannels(linear_image)*(width/2L);
755404d0da35379e582eac5248a1b44184decd13eefcristy  image_view=AcquireVirtualCacheView(linear_image,exception);
75646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  paint_view=AcquireAuthenticCacheView(paint_image,exception);
757b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
758ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
759404d0da35379e582eac5248a1b44184decd13eefcristy    magick_threads(linear_image,paint_image,linear_image->rows,1)
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
761404d0da35379e582eac5248a1b44184decd13eefcristy  for (y=0; y < (ssize_t) linear_image->rows; y++)
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
7634c08aed51c5899665ade97263692328eea4af106cristy    register const Quantum
76405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict p;
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7664c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
76705d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
769bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register size_t
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *histogram;
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
77214973baa8fa5c79889bc4db247200bb7d4626324cristy    register ssize_t
77314973baa8fa5c79889bc4db247200bb7d4626324cristy      x;
77414973baa8fa5c79889bc4db247200bb7d4626324cristy
7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      continue;
777fe4ba002ee50b147659ea0f84ad1526c3758f2f8cristy    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
778404d0da35379e582eac5248a1b44184decd13eefcristy      (width/2L),linear_image->columns+width,width,exception);
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
7803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      exception);
7814c08aed51c5899665ade97263692328eea4af106cristy    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
7823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickFalse;
7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        continue;
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    histogram=histograms[GetOpenMPThreadId()];
787404d0da35379e582eac5248a1b44184decd13eefcristy    for (x=0; x < (ssize_t) linear_image->columns; x++)
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
789bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      register ssize_t
7903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        i,
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        u;
7923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
793bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      size_t
7943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        count;
7953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7969d314ff2c17a77996c05413c2013880387e50f0ecristy      ssize_t
7979d314ff2c17a77996c05413c2013880387e50f0ecristy        j,
7989d314ff2c17a77996c05413c2013880387e50f0ecristy        k,
799f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy        n,
8009d314ff2c17a77996c05413c2013880387e50f0ecristy        v;
8019d314ff2c17a77996c05413c2013880387e50f0ecristy
8023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
8033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Assign most frequent color.
8043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
805f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy      k=0;
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      j=0;
8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      count=0;
808f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy      (void) ResetMagickMemory(histogram,0,NumberPaintBins* sizeof(*histogram));
809bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (v=0; v < (ssize_t) width; v++)
8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
811bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (u=0; u < (ssize_t) width; u++)
8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
813404d0da35379e582eac5248a1b44184decd13eefcristy          n=(ssize_t) ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity(
814404d0da35379e582eac5248a1b44184decd13eefcristy            linear_image,p+GetPixelChannels(linear_image)*(u+k))));
815f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy          histogram[n]++;
816f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy          if (histogram[n] > count)
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
818f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy              j=k+u;
819f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy              count=histogram[n];
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
822034ade9cf59ba9bf412eb2da3bab31b1de25929ecristy        k+=(ssize_t) (linear_image->columns+width);
823f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy      }
824404d0da35379e582eac5248a1b44184decd13eefcristy      for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
825f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy      {
8265a23c55ddcfdf6ae717dd42d8a1c1a2ff8c6305fcristy        PixelChannel channel=GetPixelChannelChannel(linear_image,i);
8275a23c55ddcfdf6ae717dd42d8a1c1a2ff8c6305fcristy        PixelTrait traits=GetPixelChannelTraits(linear_image,channel);
8285a23c55ddcfdf6ae717dd42d8a1c1a2ff8c6305fcristy        PixelTrait paint_traits=GetPixelChannelTraits(paint_image,channel);
829f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy        if ((traits == UndefinedPixelTrait) ||
830f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy            (paint_traits == UndefinedPixelTrait))
831f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy          continue;
8321eced097f7f4f51d5aa14d46079292fa1dcf0e77cristy        if (((paint_traits & CopyPixelTrait) != 0) ||
833883fde11debec15cedb05dc5d7228d8588066bc0cristy            (GetPixelReadMask(linear_image,p) == 0))
834f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy          {
835f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy            SetPixelChannel(paint_image,channel,p[center+i],q);
836f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy            continue;
837f8561541d3e184b4f8ace71d6274cd27f40fbc79cristy          }
838404d0da35379e582eac5248a1b44184decd13eefcristy        SetPixelChannel(paint_image,channel,p[j*GetPixelChannels(linear_image)+
839404d0da35379e582eac5248a1b44184decd13eefcristy          i],q);
8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
841404d0da35379e582eac5248a1b44184decd13eefcristy      p+=GetPixelChannels(linear_image);
842ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(paint_image);
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickFalse;
846404d0da35379e582eac5248a1b44184decd13eefcristy    if (linear_image->progress_monitor != (MagickProgressMonitor) NULL)
8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
8483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          proceed;
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
851b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
85295338b312d2239543881a93d7bed923eed6eaff9cristy        #pragma omp critical (MagickCore_OilPaintImage)
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
854404d0da35379e582eac5248a1b44184decd13eefcristy        proceed=SetImageProgress(linear_image,OilPaintImageTag,progress++,
855404d0da35379e582eac5248a1b44184decd13eefcristy          linear_image->rows);
8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (proceed == MagickFalse)
8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  paint_view=DestroyCacheView(paint_view);
8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  histograms=DestroyHistogramThreadSet(histograms);
863404d0da35379e582eac5248a1b44184decd13eefcristy  linear_image=DestroyImage(linear_image);
8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    paint_image=DestroyImage(paint_image);
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(paint_image);
8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     O p a q u e P a i n t I m a g e                                         %
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  OpaquePaintImage() changes any pixel that matches color with the color
8811f07555d1773dac3acebfce4ba017128246923c2cristy%  defined by fill argument.
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
88314973baa8fa5c79889bc4db247200bb7d4626324cristy%  By default color must match a particular pixel color exactly.  However, in
88414973baa8fa5c79889bc4db247200bb7d4626324cristy%  many cases two colors may differ by a small amount.  Fuzz defines how much
88514973baa8fa5c79889bc4db247200bb7d4626324cristy%  tolerance is acceptable to consider two colors as the same.  For example,
88614973baa8fa5c79889bc4db247200bb7d4626324cristy%  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
88714973baa8fa5c79889bc4db247200bb7d4626324cristy%  are now interpreted as the same color.
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the OpaquePaintImage method is:
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8911f07555d1773dac3acebfce4ba017128246923c2cristy%      MagickBooleanType OpaquePaintImage(Image *image,const PixelInfo *target,
8921f07555d1773dac3acebfce4ba017128246923c2cristy%        const PixelInfo *fill,const MagickBooleanType invert,
8931f07555d1773dac3acebfce4ba017128246923c2cristy%        ExceptionInfo *exception)
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o target: the RGB value of the target color.
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o fill: the replacement color.
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o invert: paint any pixel that does not match the target color.
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
905189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%    o exception: return any errors or warnings in this structure.
906189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%
9073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType OpaquePaintImage(Image *image,
909189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert,
910189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  ExceptionInfo *exception)
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define OpaquePaintImageTag  "Opaque/Image"
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
914c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
915c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
916c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
920bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  MagickOffsetType
921bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    progress;
922bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
9234c08aed51c5899665ade97263692328eea4af106cristy  PixelInfo
9241f07555d1773dac3acebfce4ba017128246923c2cristy    conform_fill,
9251f07555d1773dac3acebfce4ba017128246923c2cristy    conform_target,
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    zero;
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
928bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
929bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    y;
930bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
932e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
9334c08aed51c5899665ade97263692328eea4af106cristy  assert(target != (PixelInfo *) NULL);
9344c08aed51c5899665ade97263692328eea4af106cristy  assert(fill != (PixelInfo *) NULL);
9353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
937574cc26500992189f637cd1cdf93d0654e7df7aecristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
939bfdd5bc06830778f14dfa0659b389ff630b7fbfedirk  ConformPixelInfo(image,fill,&conform_fill,exception);
940bfdd5bc06830778f14dfa0659b389ff630b7fbfedirk  ConformPixelInfo(image,target,&conform_target,exception);
9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Make image color opaque.
9433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
9453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  progress=0;
9464c08aed51c5899665ade97263692328eea4af106cristy  GetPixelInfo(image,&zero);
94746ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
948b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
949ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
9505e6b259130f9dbe0da4666f734937017babe573acristy    magick_threads(image,image,image->rows,1)
9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
952bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
9544c08aed51c5899665ade97263692328eea4af106cristy    PixelInfo
9553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel;
9563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9574c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
95805d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
9593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
96014973baa8fa5c79889bc4db247200bb7d4626324cristy    register ssize_t
96114973baa8fa5c79889bc4db247200bb7d4626324cristy      x;
96214973baa8fa5c79889bc4db247200bb7d4626324cristy
9633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
9643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      continue;
9653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
96614973baa8fa5c79889bc4db247200bb7d4626324cristy    if (q == (Quantum *) NULL)
9673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
9683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickFalse;
9693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        continue;
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
9713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel=zero;
972bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
9733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
974803640d20a6a664315eddfff6f8531d0c5e0871dcristy      GetPixelInfoPixel(image,q,&pixel);
9751f07555d1773dac3acebfce4ba017128246923c2cristy      if (IsFuzzyEquivalencePixelInfo(&pixel,&conform_target) != invert)
97611a06d3f2cac0f17af7963e83bc6e9ebd2a377c0cristy        SetPixelViaPixelInfo(image,&conform_fill,q);
977ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickFalse;
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (image->progress_monitor != (MagickProgressMonitor) NULL)
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          proceed;
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
986b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
98795338b312d2239543881a93d7bed923eed6eaff9cristy        #pragma omp critical (MagickCore_OpaquePaintImage)
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->rows);
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (proceed == MagickFalse)
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     T r a n s p a r e n t P a i n t I m a g e                               %
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  TransparentPaintImage() changes the opacity value associated with any pixel
10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  that matches color to the value defined by opacity.
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
101314973baa8fa5c79889bc4db247200bb7d4626324cristy%  By default color must match a particular pixel color exactly.  However, in
101414973baa8fa5c79889bc4db247200bb7d4626324cristy%  many cases two colors may differ by a small amount.  Fuzz defines how much
101514973baa8fa5c79889bc4db247200bb7d4626324cristy%  tolerance is acceptable to consider two colors as the same.  For example,
101614973baa8fa5c79889bc4db247200bb7d4626324cristy%  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
101714973baa8fa5c79889bc4db247200bb7d4626324cristy%  are now interpreted as the same color.
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the TransparentPaintImage method is:
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType TransparentPaintImage(Image *image,
10224c08aed51c5899665ade97263692328eea4af106cristy%        const PixelInfo *target,const Quantum opacity,
1023189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%        const MagickBooleanType invert,ExceptionInfo *exception)
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o target: the target color.
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o opacity: the replacement opacity value.
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o invert: paint any pixel that does not match the target color.
10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1035189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%    o exception: return any errors or warnings in this structure.
1036189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType TransparentPaintImage(Image *image,
103914973baa8fa5c79889bc4db247200bb7d4626324cristy  const PixelInfo *target,const Quantum opacity,const MagickBooleanType invert,
104014973baa8fa5c79889bc4db247200bb7d4626324cristy  ExceptionInfo *exception)
10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define TransparentPaintImageTag  "Transparent/Image"
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1044c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
1045c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
1046c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1050bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  MagickOffsetType
1051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    progress;
1052bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
10534c08aed51c5899665ade97263692328eea4af106cristy  PixelInfo
10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    zero;
10553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1056bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1057bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    y;
1058bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
1060e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
10614c08aed51c5899665ade97263692328eea4af106cristy  assert(target != (PixelInfo *) NULL);
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1064574cc26500992189f637cd1cdf93d0654e7df7aecristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
10653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
106617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy  if (image->alpha_trait == UndefinedPixelTrait)
106763240888c3975789a09c2494a4654b523931df96cristy    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
10683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
10693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Make image color transparent.
10703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  progress=0;
10734c08aed51c5899665ade97263692328eea4af106cristy  GetPixelInfo(image,&zero);
107446ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
1075b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1076ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
10775e6b259130f9dbe0da4666f734937017babe573acristy    magick_threads(image,image,image->rows,1)
10783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
1079bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
10803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
10814c08aed51c5899665ade97263692328eea4af106cristy    PixelInfo
10823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel;
10833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1084bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    register ssize_t
10853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      x;
10863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10874c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
108805d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
10913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      continue;
10923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
109314973baa8fa5c79889bc4db247200bb7d4626324cristy    if (q == (Quantum *) NULL)
10943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickFalse;
10963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        continue;
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel=zero;
1099bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
11003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1101803640d20a6a664315eddfff6f8531d0c5e0871dcristy      GetPixelInfoPixel(image,q,&pixel);
11024c08aed51c5899665ade97263692328eea4af106cristy      if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
11034c08aed51c5899665ade97263692328eea4af106cristy        SetPixelAlpha(image,opacity,q);
1104ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickFalse;
11083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (image->progress_monitor != (MagickProgressMonitor) NULL)
11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
11103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
11113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          proceed;
11123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1113b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
111495338b312d2239543881a93d7bed923eed6eaff9cristy        #pragma omp critical (MagickCore_TransparentPaintImage)
11153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
11173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->rows);
11183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (proceed == MagickFalse)
11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
11243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     T r a n s p a r e n t P a i n t I m a g e C h r o m a                   %
11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  TransparentPaintImageChroma() changes the opacity value associated with any
11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pixel that matches color to the value defined by opacity.
11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
114014973baa8fa5c79889bc4db247200bb7d4626324cristy%  As there is one fuzz value for the all the channels, TransparentPaintImage()
114114973baa8fa5c79889bc4db247200bb7d4626324cristy%  is not suitable for the operations like chroma, where the tolerance for
114214973baa8fa5c79889bc4db247200bb7d4626324cristy%  similarity of two color component (RGB) can be different. Thus we define
114314973baa8fa5c79889bc4db247200bb7d4626324cristy%  this method to take two target pixels (one low and one high) and all the
114414973baa8fa5c79889bc4db247200bb7d4626324cristy%  pixels of an image which are lying between these two pixels are made
114514973baa8fa5c79889bc4db247200bb7d4626324cristy%  transparent.
11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
114714973baa8fa5c79889bc4db247200bb7d4626324cristy%  The format of the TransparentPaintImageChroma method is:
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
114914973baa8fa5c79889bc4db247200bb7d4626324cristy%      MagickBooleanType TransparentPaintImageChroma(Image *image,
115014973baa8fa5c79889bc4db247200bb7d4626324cristy%        const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
115114973baa8fa5c79889bc4db247200bb7d4626324cristy%        const MagickBooleanType invert,ExceptionInfo *exception)
11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o low: the low target color.
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o high: the high target color.
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o opacity: the replacement opacity value.
11623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o invert: paint any pixel that does not match the target color.
11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1165189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%    o exception: return any errors or warnings in this structure.
1166189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy%
11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
1169189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
1170189e84ce7da8fbf4eb57c908846bcc0bdcbdc688cristy  const MagickBooleanType invert,ExceptionInfo *exception)
11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define TransparentPaintImageTag  "Transparent/Image"
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1174c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  CacheView
1175c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image_view;
1176c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1180bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  MagickOffsetType
1181bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    progress;
1182bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
1183bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1184bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    y;
1185bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy
11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
1187e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
11884c08aed51c5899665ade97263692328eea4af106cristy  assert(high != (PixelInfo *) NULL);
11894c08aed51c5899665ade97263692328eea4af106cristy  assert(low != (PixelInfo *) NULL);
11903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1192574cc26500992189f637cd1cdf93d0654e7df7aecristy  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
119417f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy  if (image->alpha_trait == UndefinedPixelTrait)
119563240888c3975789a09c2494a4654b523931df96cristy    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Make image color transparent.
11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  progress=0;
120146ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy  image_view=AcquireAuthenticCacheView(image,exception);
1202b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
1203ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy  #pragma omp parallel for schedule(static,4) shared(progress,status) \
12045e6b259130f9dbe0da4666f734937017babe573acristy    magick_threads(image,image,image->rows,1)
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
1206bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (y=0; y < (ssize_t) image->rows; y++)
12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    MagickBooleanType
12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      match;
12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12114c08aed51c5899665ade97263692328eea4af106cristy    PixelInfo
12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel;
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12144c08aed51c5899665ade97263692328eea4af106cristy    register Quantum
121505d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
121714973baa8fa5c79889bc4db247200bb7d4626324cristy    register ssize_t
121814973baa8fa5c79889bc4db247200bb7d4626324cristy      x;
121914973baa8fa5c79889bc4db247200bb7d4626324cristy
12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (status == MagickFalse)
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      continue;
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
122314973baa8fa5c79889bc4db247200bb7d4626324cristy    if (q == (Quantum *) NULL)
12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=MagickFalse;
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        continue;
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12284c08aed51c5899665ade97263692328eea4af106cristy    GetPixelInfo(image,&pixel);
1229bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (x=0; x < (ssize_t) image->columns; x++)
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1231803640d20a6a664315eddfff6f8531d0c5e0871dcristy      GetPixelInfoPixel(image,q,&pixel);
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (pixel.green >= low->green) && (pixel.green <= high->green) &&
123414973baa8fa5c79889bc4db247200bb7d4626324cristy        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ? MagickTrue :
123514973baa8fa5c79889bc4db247200bb7d4626324cristy        MagickFalse;
12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (match != invert)
12374c08aed51c5899665ade97263692328eea4af106cristy        SetPixelAlpha(image,opacity,q);
1238ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy      q+=GetPixelChannels(image);
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=MagickFalse;
12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (image->progress_monitor != (MagickProgressMonitor) NULL)
12433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        MagickBooleanType
12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          proceed;
12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1247b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT)
124895338b312d2239543881a93d7bed923eed6eaff9cristy        #pragma omp critical (MagickCore_TransparentPaintImageChroma)
12493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
12503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->rows);
12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (proceed == MagickFalse)
12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
12543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
12553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image_view=DestroyCacheView(image_view);
12573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
12583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1259