MagickCore  6.7.5
paint.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                      PPPP    AAA   IIIII  N   N  TTTTT                      %
00007 %                      P   P  A   A    I    NN  N    T                        %
00008 %                      PPPP   AAAAA    I    N N N    T                        %
00009 %                      P      A   A    I    N  NN    T                        %
00010 %                      P      A   A  IIIII  N   N    T                        %
00011 %                                                                             %
00012 %                                                                             %
00013 %                        Methods to Paint on an Image                         %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1998                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040  Include declarations.
00041 */
00042 #include "MagickCore/studio.h"
00043 #include "MagickCore/color.h"
00044 #include "MagickCore/color-private.h"
00045 #include "MagickCore/colorspace-private.h"
00046 #include "MagickCore/composite.h"
00047 #include "MagickCore/composite-private.h"
00048 #include "MagickCore/draw.h"
00049 #include "MagickCore/draw-private.h"
00050 #include "MagickCore/exception.h"
00051 #include "MagickCore/exception-private.h"
00052 #include "MagickCore/gem.h"
00053 #include "MagickCore/gem-private.h"
00054 #include "MagickCore/monitor.h"
00055 #include "MagickCore/monitor-private.h"
00056 #include "MagickCore/paint.h"
00057 #include "MagickCore/pixel-accessor.h"
00058 #include "MagickCore/statistic.h"
00059 #include "MagickCore/string_.h"
00060 #include "MagickCore/thread-private.h"
00061 
00062 /*
00063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00064 %                                                                             %
00065 %                                                                             %
00066 %                                                                             %
00067 %   F l o o d f i l l P a i n t I m a g e                                     %
00068 %                                                                             %
00069 %                                                                             %
00070 %                                                                             %
00071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00072 %
00073 %  FloodfillPaintImage() changes the color value of any pixel that matches
00074 %  target and is an immediate neighbor.  If the method FillToBorderMethod is
00075 %  specified, the color value is changed for any neighbor pixel that does not
00076 %  match the bordercolor member of image.
00077 %
00078 %  By default target must match a particular pixel color exactly.  However,
00079 %  in many cases two colors may differ by a small amount.  The fuzz member of
00080 %  image defines how much tolerance is acceptable to consider two colors as
00081 %  the same.  For example, set fuzz to 10 and the color red at intensities of
00082 %  100 and 102 respectively are now interpreted as the same color for the
00083 %  purposes of the floodfill.
00084 %
00085 %  The format of the FloodfillPaintImage method is:
00086 %
00087 %      MagickBooleanType FloodfillPaintImage(Image *image,
00088 %        const DrawInfo *draw_info,const PixelInfo target,
00089 %        const ssize_t x_offset,const ssize_t y_offset,
00090 %        const MagickBooleanType invert,ExceptionInfo *exception)
00091 %
00092 %  A description of each parameter follows:
00093 %
00094 %    o image: the image.
00095 %
00096 %    o draw_info: the draw info.
00097 %
00098 %    o target: the RGB value of the target color.
00099 %
00100 %    o x_offset,y_offset: the starting location of the operation.
00101 %
00102 %    o invert: paint any pixel that does not match the target color.
00103 %
00104 %    o exception: return any errors or warnings in this structure.
00105 %
00106 */
00107 MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
00108   const DrawInfo *draw_info,const PixelInfo *target,const ssize_t x_offset,
00109   const ssize_t y_offset,const MagickBooleanType invert,
00110   ExceptionInfo *exception)
00111 {
00112 #define MaxStacksize  (1UL << 15)
00113 #define PushSegmentStack(up,left,right,delta) \
00114 { \
00115   if (s >= (segment_stack+MaxStacksize)) \
00116     ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
00117   else \
00118     { \
00119       if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
00120         { \
00121           s->x1=(double) (left); \
00122           s->y1=(double) (up); \
00123           s->x2=(double) (right); \
00124           s->y2=(double) (delta); \
00125           s++; \
00126         } \
00127     } \
00128 }
00129 
00130   CacheView
00131     *floodplane_view,
00132     *image_view;
00133 
00134   Image
00135     *floodplane_image;
00136 
00137   MagickBooleanType
00138     skip,
00139     status;
00140 
00141   PixelInfo
00142     fill_color,
00143     pixel;
00144 
00145   register SegmentInfo
00146     *s;
00147 
00148   SegmentInfo
00149     *segment_stack;
00150 
00151   ssize_t
00152     offset,
00153     start,
00154     x,
00155     x1,
00156     x2,
00157     y;
00158 
00159   /*
00160     Check boundary conditions.
00161   */
00162   assert(image != (Image *) NULL);
00163   assert(image->signature == MagickSignature);
00164   if (image->debug != MagickFalse)
00165     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00166   assert(draw_info != (DrawInfo *) NULL);
00167   assert(draw_info->signature == MagickSignature);
00168   if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
00169     return(MagickFalse);
00170   if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
00171     return(MagickFalse);
00172   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00173     return(MagickFalse);
00174   if (image->matte == MagickFalse)
00175     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
00176   /*
00177     Set floodfill state.
00178   */
00179   floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
00180     exception);
00181   if (floodplane_image == (Image *) NULL)
00182     return(MagickFalse);
00183   floodplane_image->colorspace=GRAYColorspace;
00184   (void) EvaluateImage(floodplane_image,SetEvaluateOperator,0.0,exception);
00185   segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
00186     sizeof(*segment_stack));
00187   if (segment_stack == (SegmentInfo *) NULL)
00188     {
00189       floodplane_image=DestroyImage(floodplane_image);
00190       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00191         image->filename);
00192     }
00193   /*
00194     Push initial segment on stack.
00195   */
00196   status=MagickTrue;
00197   x=x_offset;
00198   y=y_offset;
00199   start=0;
00200   s=segment_stack;
00201   PushSegmentStack(y,x,x,1);
00202   PushSegmentStack(y+1,x,x,-1);
00203   GetPixelInfo(image,&pixel);
00204   image_view=AcquireCacheView(image);
00205   floodplane_view=AcquireCacheView(floodplane_image);
00206   while (s > segment_stack)
00207   {
00208     register const Quantum
00209       *restrict p;
00210 
00211     register Quantum
00212       *restrict q;
00213 
00214     register ssize_t
00215       x;
00216 
00217     /*
00218       Pop segment off stack.
00219     */
00220     s--;
00221     x1=(ssize_t) s->x1;
00222     x2=(ssize_t) s->x2;
00223     offset=(ssize_t) s->y2;
00224     y=(ssize_t) s->y1+offset;
00225     /*
00226       Recolor neighboring pixels.
00227     */
00228     p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
00229     q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
00230       exception);
00231     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00232       break;
00233     p+=x1*GetPixelChannels(image);
00234     q+=x1*GetPixelChannels(floodplane_image);
00235     for (x=x1; x >= 0; x--)
00236     {
00237       if (GetPixelGray(floodplane_image,q) != 0)
00238         break;
00239       GetPixelInfoPixel(image,p,&pixel);
00240       if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
00241         break;
00242       SetPixelGray(floodplane_image,QuantumRange,q);
00243       p-=GetPixelChannels(image);
00244       q-=GetPixelChannels(floodplane_image);
00245     }
00246     if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
00247       break;
00248     skip=x >= x1 ? MagickTrue : MagickFalse;
00249     if (skip == MagickFalse)
00250       {
00251         start=x+1;
00252         if (start < x1)
00253           PushSegmentStack(y,start,x1-1,-offset);
00254         x=x1+1;
00255       }
00256     do
00257     {
00258       if (skip == MagickFalse)
00259         {
00260           if (x < (ssize_t) image->columns)
00261             {
00262               p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
00263                 exception);
00264               q=GetCacheViewAuthenticPixels(floodplane_view,x,y,image->columns-
00265                 x,1,exception);
00266               if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00267                 break;
00268               for ( ; x < (ssize_t) image->columns; x++)
00269               {
00270                 if (GetPixelGray(floodplane_image,q) != 0)
00271                   break;
00272                 GetPixelInfoPixel(image,p,&pixel);
00273                 if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
00274                   break;
00275                 SetPixelGray(floodplane_image,QuantumRange,q);
00276                 p+=GetPixelChannels(image);
00277                 q+=GetPixelChannels(floodplane_image);
00278               }
00279               status=SyncCacheViewAuthenticPixels(floodplane_view,exception);
00280               if (status == MagickFalse)
00281                 break;
00282             }
00283           PushSegmentStack(y,start,x-1,offset);
00284           if (x > (x2+1))
00285             PushSegmentStack(y,x2+1,x-1,-offset);
00286         }
00287       skip=MagickFalse;
00288       x++;
00289       if (x <= x2)
00290         {
00291           p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
00292             exception);
00293           q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
00294             exception);
00295           if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00296             break;
00297           for ( ; x <= x2; x++)
00298           {
00299             if (GetPixelGray(floodplane_image,q) != 0)
00300               break;
00301             GetPixelInfoPixel(image,p,&pixel);
00302             if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
00303               break;
00304             p+=GetPixelChannels(image);
00305             q+=GetPixelChannels(floodplane_image);
00306           }
00307         }
00308       start=x;
00309     } while (x <= x2);
00310   }
00311   for (y=0; y < (ssize_t) image->rows; y++)
00312   {
00313     register const Quantum
00314       *restrict p;
00315 
00316     register Quantum
00317       *restrict q;
00318 
00319     register ssize_t
00320       x;
00321 
00322     /*
00323       Tile fill color onto floodplane.
00324     */
00325     p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,exception);
00326     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00327     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00328       break;
00329     for (x=0; x < (ssize_t) image->columns; x++)
00330     {
00331       if (GetPixelGray(floodplane_image,p) != 0)
00332         {
00333           (void) GetFillColor(draw_info,x,y,&fill_color,exception);
00334           SetPixelInfoPixel(image,&fill_color,q);
00335         }
00336       p+=GetPixelChannels(floodplane_image);
00337       q+=GetPixelChannels(image);
00338     }
00339     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00340       break;
00341   }
00342   floodplane_view=DestroyCacheView(floodplane_view);
00343   image_view=DestroyCacheView(image_view);
00344   segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
00345   floodplane_image=DestroyImage(floodplane_image);
00346   return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
00347 }
00348 
00349 /*
00350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00351 %                                                                             %
00352 %                                                                             %
00353 %                                                                             %
00354 +     G r a d i e n t I m a g e                                               %
00355 %                                                                             %
00356 %                                                                             %
00357 %                                                                             %
00358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00359 %
00360 %  GradientImage() applies a continuously smooth color transitions along a
00361 %  vector from one color to another.
00362 %
00363 %  Note, the interface of this method will change in the future to support
00364 %  more than one transistion.
00365 %
00366 %  The format of the GradientImage method is:
00367 %
00368 %      MagickBooleanType GradientImage(Image *image,const GradientType type,
00369 %        const SpreadMethod method,const PixelInfo *start_color,
00370 %        const PixelInfo *stop_color,ExceptionInfo *exception)
00371 %
00372 %  A description of each parameter follows:
00373 %
00374 %    o image: the image.
00375 %
00376 %    o type: the gradient type: linear or radial.
00377 %
00378 %    o spread: the gradient spread meathod: pad, reflect, or repeat.
00379 %
00380 %    o start_color: the start color.
00381 %
00382 %    o stop_color: the stop color.
00383 %
00384 %    o exception: return any errors or warnings in this structure.
00385 %
00386 */
00387 
00388 static inline double MagickMax(const double x,const double y)
00389 {
00390   return(x > y ? x : y);
00391 }
00392 
00393 MagickExport MagickBooleanType GradientImage(Image *image,
00394   const GradientType type,const SpreadMethod method,
00395   const PixelInfo *start_color,const PixelInfo *stop_color,
00396   ExceptionInfo *exception)
00397 {
00398   DrawInfo
00399     *draw_info;
00400 
00401   GradientInfo
00402     *gradient;
00403 
00404   MagickBooleanType
00405     status;
00406 
00407   register ssize_t
00408     i;
00409 
00410   /*
00411     Set gradient start-stop end points.
00412   */
00413   assert(image != (const Image *) NULL);
00414   assert(image->signature == MagickSignature);
00415   if (image->debug != MagickFalse)
00416     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00417   assert(start_color != (const PixelInfo *) NULL);
00418   assert(stop_color != (const PixelInfo *) NULL);
00419   draw_info=AcquireDrawInfo();
00420   gradient=(&draw_info->gradient);
00421   gradient->type=type;
00422   gradient->bounding_box.width=image->columns;
00423   gradient->bounding_box.height=image->rows;
00424   gradient->gradient_vector.x2=(double) image->columns-1.0;
00425   gradient->gradient_vector.y2=(double) image->rows-1.0;
00426   if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
00427     gradient->gradient_vector.x2=0.0;
00428   gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
00429   gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
00430   gradient->radius=MagickMax(gradient->center.x,gradient->center.y);
00431   gradient->spread=method;
00432   /*
00433     Define the gradient to fill between the stops.
00434   */
00435   gradient->number_stops=2;
00436   gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
00437     sizeof(*gradient->stops));
00438   if (gradient->stops == (StopInfo *) NULL)
00439     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
00440       image->filename);
00441   (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops*
00442     sizeof(*gradient->stops));
00443   for (i=0; i < (ssize_t) gradient->number_stops; i++)
00444     GetPixelInfo(image,&gradient->stops[i].color);
00445   gradient->stops[0].color=(*start_color);
00446   gradient->stops[0].offset=0.0;
00447   gradient->stops[1].color=(*stop_color);
00448   gradient->stops[1].offset=1.0;
00449   /*
00450     Draw a gradient on the image.
00451   */
00452   status=DrawGradientImage(image,draw_info,exception);
00453   draw_info=DestroyDrawInfo(draw_info);
00454   if ((start_color->alpha == OpaqueAlpha) && (stop_color->alpha == OpaqueAlpha))
00455     image->matte=MagickFalse;
00456   if ((IsPixelInfoGray(start_color) != MagickFalse) &&
00457       (IsPixelInfoGray(stop_color) != MagickFalse))
00458     image->type=GrayscaleType;
00459   return(status);
00460 }
00461 
00462 /*
00463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00464 %                                                                             %
00465 %                                                                             %
00466 %                                                                             %
00467 %     O i l P a i n t I m a g e                                               %
00468 %                                                                             %
00469 %                                                                             %
00470 %                                                                             %
00471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00472 %
00473 %  OilPaintImage() applies a special effect filter that simulates an oil
00474 %  painting.  Each pixel is replaced by the most frequent color occurring
00475 %  in a circular region defined by radius.
00476 %
00477 %  The format of the OilPaintImage method is:
00478 %
00479 %      Image *OilPaintImage(const Image *image,const double radius,
00480 %        const double sigma,ExceptionInfo *exception)
00481 %
00482 %  A description of each parameter follows:
00483 %
00484 %    o image: the image.
00485 %
00486 %    o radius: the radius of the circular neighborhood.
00487 %
00488 %    o sigma: the standard deviation of the Gaussian, in pixels.
00489 %
00490 %    o exception: return any errors or warnings in this structure.
00491 %
00492 */
00493 
00494 static size_t **DestroyHistogramThreadSet(size_t **histogram)
00495 {
00496   register ssize_t
00497     i;
00498 
00499   assert(histogram != (size_t **) NULL);
00500   for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
00501     if (histogram[i] != (size_t *) NULL)
00502       histogram[i]=(size_t *) RelinquishMagickMemory(histogram[i]);
00503   histogram=(size_t **) RelinquishMagickMemory(histogram);
00504   return(histogram);
00505 }
00506 
00507 static size_t **AcquireHistogramThreadSet(const size_t count)
00508 {
00509   register ssize_t
00510     i;
00511 
00512   size_t
00513     **histogram,
00514     number_threads;
00515 
00516   number_threads=GetOpenMPMaximumThreads();
00517   histogram=(size_t **) AcquireQuantumMemory(number_threads,sizeof(*histogram));
00518   if (histogram == (size_t **) NULL)
00519     return((size_t **) NULL);
00520   (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
00521   for (i=0; i < (ssize_t) number_threads; i++)
00522   {
00523     histogram[i]=(size_t *) AcquireQuantumMemory(count,sizeof(**histogram));
00524     if (histogram[i] == (size_t *) NULL)
00525       return(DestroyHistogramThreadSet(histogram));
00526   }
00527   return(histogram);
00528 }
00529 
00530 MagickExport Image *OilPaintImage(const Image *image,const double radius,
00531   const double sigma,ExceptionInfo *exception)
00532 {
00533 #define NumberPaintBins  256
00534 #define OilPaintImageTag  "OilPaint/Image"
00535 
00536   CacheView
00537     *image_view,
00538     *paint_view;
00539 
00540   Image
00541     *paint_image;
00542 
00543   MagickBooleanType
00544     status;
00545 
00546   MagickOffsetType
00547     progress;
00548 
00549   size_t
00550     **histograms,
00551     width;
00552 
00553   ssize_t
00554     center,
00555     y;
00556 
00557   /*
00558     Initialize painted image attributes.
00559   */
00560   assert(image != (const Image *) NULL);
00561   assert(image->signature == MagickSignature);
00562   if (image->debug != MagickFalse)
00563     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00564   assert(exception != (ExceptionInfo *) NULL);
00565   assert(exception->signature == MagickSignature);
00566   width=GetOptimalKernelWidth2D(radius,sigma);
00567   paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
00568   if (paint_image == (Image *) NULL)
00569     return((Image *) NULL);
00570   if (SetImageStorageClass(paint_image,DirectClass,exception) == MagickFalse)
00571     {
00572       paint_image=DestroyImage(paint_image);
00573       return((Image *) NULL);
00574     }
00575   histograms=AcquireHistogramThreadSet(NumberPaintBins);
00576   if (histograms == (size_t **) NULL)
00577     {
00578       paint_image=DestroyImage(paint_image);
00579       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
00580     }
00581   /*
00582     Oil paint image.
00583   */
00584   status=MagickTrue;
00585   progress=0;
00586   center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(width/2L)+
00587     GetPixelChannels(image)*(width/2L);
00588   image_view=AcquireCacheView(image);
00589   paint_view=AcquireCacheView(paint_image);
00590 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00591   #pragma omp parallel for schedule(static,4) shared(progress,status)
00592 #endif
00593   for (y=0; y < (ssize_t) image->rows; y++)
00594   {
00595     register const Quantum
00596       *restrict p;
00597 
00598     register Quantum
00599       *restrict q;
00600 
00601     register size_t
00602       *histogram;
00603 
00604     register ssize_t
00605       x;
00606 
00607     if (status == MagickFalse)
00608       continue;
00609     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
00610       (width/2L),image->columns+width,width,exception);
00611     q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
00612       exception);
00613     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00614       {
00615         status=MagickFalse;
00616         continue;
00617       }
00618     histogram=histograms[GetOpenMPThreadId()];
00619     for (x=0; x < (ssize_t) image->columns; x++)
00620     {
00621       register ssize_t
00622         i,
00623         u;
00624 
00625       size_t
00626         count;
00627 
00628       ssize_t
00629         j,
00630         k,
00631         n,
00632         v;
00633 
00634       /*
00635         Assign most frequent color.
00636       */
00637       k=0;
00638       j=0;
00639       count=0;
00640       (void) ResetMagickMemory(histogram,0,NumberPaintBins* sizeof(*histogram));
00641       for (v=0; v < (ssize_t) width; v++)
00642       {
00643         for (u=0; u < (ssize_t) width; u++)
00644         {
00645           n=(ssize_t) ScaleQuantumToChar(GetPixelIntensity(image,p+
00646             GetPixelChannels(image)*(u+k)));
00647           histogram[n]++;
00648           if (histogram[n] > count)
00649             {
00650               j=k+u;
00651               count=histogram[n];
00652             }
00653         }
00654         k+=(ssize_t) (image->columns+width);
00655       }
00656       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00657       {
00658         PixelChannel
00659           channel;
00660 
00661         PixelTrait
00662           paint_traits,
00663           traits;
00664 
00665         channel=GetPixelChannelMapChannel(image,i);
00666         traits=GetPixelChannelMapTraits(image,channel);
00667         paint_traits=GetPixelChannelMapTraits(paint_image,channel);
00668         if ((traits == UndefinedPixelTrait) ||
00669             (paint_traits == UndefinedPixelTrait))
00670           continue;
00671         if (((paint_traits & CopyPixelTrait) != 0) ||
00672             (GetPixelMask(image,p) != 0))
00673           {
00674             SetPixelChannel(paint_image,channel,p[center+i],q);
00675             continue;
00676           }
00677         SetPixelChannel(paint_image,channel,p[j*GetPixelChannels(image)+i],q);
00678       }
00679       p+=GetPixelChannels(image);
00680       q+=GetPixelChannels(paint_image);
00681     }
00682     if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
00683       status=MagickFalse;
00684     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00685       {
00686         MagickBooleanType
00687           proceed;
00688 
00689 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00690         #pragma omp critical (MagickCore_OilPaintImage)
00691 #endif
00692         proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
00693         if (proceed == MagickFalse)
00694           status=MagickFalse;
00695       }
00696   }
00697   paint_view=DestroyCacheView(paint_view);
00698   image_view=DestroyCacheView(image_view);
00699   histograms=DestroyHistogramThreadSet(histograms);
00700   if (status == MagickFalse)
00701     paint_image=DestroyImage(paint_image);
00702   return(paint_image);
00703 }
00704 
00705 /*
00706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00707 %                                                                             %
00708 %                                                                             %
00709 %                                                                             %
00710 %     O p a q u e P a i n t I m a g e                                         %
00711 %                                                                             %
00712 %                                                                             %
00713 %                                                                             %
00714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00715 %
00716 %  OpaquePaintImage() changes any pixel that matches color with the color
00717 %  defined by fill.
00718 %
00719 %  By default color must match a particular pixel color exactly.  However, in
00720 %  many cases two colors may differ by a small amount.  Fuzz defines how much
00721 %  tolerance is acceptable to consider two colors as the same.  For example,
00722 %  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
00723 %  are now interpreted as the same color.
00724 %
00725 %  The format of the OpaquePaintImage method is:
00726 %
00727 %      MagickBooleanType OpaquePaintImage(Image *image,
00728 %        const PixelInfo *target,const PixelInfo *fill,
00729 %        const MagickBooleanType invert,ExceptionInfo *exception)
00730 %
00731 %  A description of each parameter follows:
00732 %
00733 %    o image: the image.
00734 %
00735 %    o target: the RGB value of the target color.
00736 %
00737 %    o fill: the replacement color.
00738 %
00739 %    o invert: paint any pixel that does not match the target color.
00740 %
00741 %    o exception: return any errors or warnings in this structure.
00742 %
00743 */
00744 MagickExport MagickBooleanType OpaquePaintImage(Image *image,
00745   const PixelInfo *target,const PixelInfo *fill,const MagickBooleanType invert,
00746   ExceptionInfo *exception)
00747 {
00748 #define OpaquePaintImageTag  "Opaque/Image"
00749 
00750   CacheView
00751     *image_view;
00752 
00753   MagickBooleanType
00754     status;
00755 
00756   MagickOffsetType
00757     progress;
00758 
00759   PixelInfo
00760     zero;
00761 
00762   ssize_t
00763     y;
00764 
00765   assert(image != (Image *) NULL);
00766   assert(image->signature == MagickSignature);
00767   assert(target != (PixelInfo *) NULL);
00768   assert(fill != (PixelInfo *) NULL);
00769   if (image->debug != MagickFalse)
00770     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00771   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00772     return(MagickFalse);
00773   /*
00774     Make image color opaque.
00775   */
00776   status=MagickTrue;
00777   progress=0;
00778   GetPixelInfo(image,&zero);
00779   image_view=AcquireCacheView(image);
00780 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00781   #pragma omp parallel for schedule(static,4) shared(progress,status)
00782 #endif
00783   for (y=0; y < (ssize_t) image->rows; y++)
00784   {
00785     PixelInfo
00786       pixel;
00787 
00788     register Quantum
00789       *restrict q;
00790 
00791     register ssize_t
00792       x;
00793 
00794     if (status == MagickFalse)
00795       continue;
00796     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00797     if (q == (Quantum *) NULL)
00798       {
00799         status=MagickFalse;
00800         continue;
00801       }
00802     pixel=zero;
00803     for (x=0; x < (ssize_t) image->columns; x++)
00804     {
00805       GetPixelInfoPixel(image,q,&pixel);
00806       if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
00807         SetPixelInfoPixel(image,fill,q);
00808       q+=GetPixelChannels(image);
00809     }
00810     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00811       status=MagickFalse;
00812     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00813       {
00814         MagickBooleanType
00815           proceed;
00816 
00817 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00818         #pragma omp critical (MagickCore_OpaquePaintImage)
00819 #endif
00820         proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
00821           image->rows);
00822         if (proceed == MagickFalse)
00823           status=MagickFalse;
00824       }
00825   }
00826   image_view=DestroyCacheView(image_view);
00827   return(status);
00828 }
00829 
00830 /*
00831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00832 %                                                                             %
00833 %                                                                             %
00834 %                                                                             %
00835 %     T r a n s p a r e n t P a i n t I m a g e                               %
00836 %                                                                             %
00837 %                                                                             %
00838 %                                                                             %
00839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00840 %
00841 %  TransparentPaintImage() changes the opacity value associated with any pixel
00842 %  that matches color to the value defined by opacity.
00843 %
00844 %  By default color must match a particular pixel color exactly.  However, in
00845 %  many cases two colors may differ by a small amount.  Fuzz defines how much
00846 %  tolerance is acceptable to consider two colors as the same.  For example,
00847 %  set fuzz to 10 and the color red at intensities of 100 and 102 respectively
00848 %  are now interpreted as the same color.
00849 %
00850 %  The format of the TransparentPaintImage method is:
00851 %
00852 %      MagickBooleanType TransparentPaintImage(Image *image,
00853 %        const PixelInfo *target,const Quantum opacity,
00854 %        const MagickBooleanType invert,ExceptionInfo *exception)
00855 %
00856 %  A description of each parameter follows:
00857 %
00858 %    o image: the image.
00859 %
00860 %    o target: the target color.
00861 %
00862 %    o opacity: the replacement opacity value.
00863 %
00864 %    o invert: paint any pixel that does not match the target color.
00865 %
00866 %    o exception: return any errors or warnings in this structure.
00867 %
00868 */
00869 MagickExport MagickBooleanType TransparentPaintImage(Image *image,
00870   const PixelInfo *target,const Quantum opacity,const MagickBooleanType invert,
00871   ExceptionInfo *exception)
00872 {
00873 #define TransparentPaintImageTag  "Transparent/Image"
00874 
00875   CacheView
00876     *image_view;
00877 
00878   MagickBooleanType
00879     status;
00880 
00881   MagickOffsetType
00882     progress;
00883 
00884   PixelInfo
00885     zero;
00886 
00887   ssize_t
00888     y;
00889 
00890   assert(image != (Image *) NULL);
00891   assert(image->signature == MagickSignature);
00892   assert(target != (PixelInfo *) NULL);
00893   if (image->debug != MagickFalse)
00894     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00895   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00896     return(MagickFalse);
00897   if (image->matte == MagickFalse)
00898     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
00899   /*
00900     Make image color transparent.
00901   */
00902   status=MagickTrue;
00903   progress=0;
00904   GetPixelInfo(image,&zero);
00905   image_view=AcquireCacheView(image);
00906 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00907   #pragma omp parallel for schedule(static,4) shared(progress,status)
00908 #endif
00909   for (y=0; y < (ssize_t) image->rows; y++)
00910   {
00911     PixelInfo
00912       pixel;
00913 
00914     register ssize_t
00915       x;
00916 
00917     register Quantum
00918       *restrict q;
00919 
00920     if (status == MagickFalse)
00921       continue;
00922     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00923     if (q == (Quantum *) NULL)
00924       {
00925         status=MagickFalse;
00926         continue;
00927       }
00928     pixel=zero;
00929     for (x=0; x < (ssize_t) image->columns; x++)
00930     {
00931       GetPixelInfoPixel(image,q,&pixel);
00932       if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
00933         SetPixelAlpha(image,opacity,q);
00934       q+=GetPixelChannels(image);
00935     }
00936     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00937       status=MagickFalse;
00938     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00939       {
00940         MagickBooleanType
00941           proceed;
00942 
00943 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00944         #pragma omp critical (MagickCore_TransparentPaintImage)
00945 #endif
00946         proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
00947           image->rows);
00948         if (proceed == MagickFalse)
00949           status=MagickFalse;
00950       }
00951   }
00952   image_view=DestroyCacheView(image_view);
00953   return(status);
00954 }
00955 
00956 /*
00957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00958 %                                                                             %
00959 %                                                                             %
00960 %                                                                             %
00961 %     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                   %
00962 %                                                                             %
00963 %                                                                             %
00964 %                                                                             %
00965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00966 %
00967 %  TransparentPaintImageChroma() changes the opacity value associated with any
00968 %  pixel that matches color to the value defined by opacity.
00969 %
00970 %  As there is one fuzz value for the all the channels, TransparentPaintImage()
00971 %  is not suitable for the operations like chroma, where the tolerance for
00972 %  similarity of two color component (RGB) can be different. Thus we define
00973 %  this method to take two target pixels (one low and one high) and all the
00974 %  pixels of an image which are lying between these two pixels are made
00975 %  transparent.
00976 %
00977 %  The format of the TransparentPaintImageChroma method is:
00978 %
00979 %      MagickBooleanType TransparentPaintImageChroma(Image *image,
00980 %        const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
00981 %        const MagickBooleanType invert,ExceptionInfo *exception)
00982 %
00983 %  A description of each parameter follows:
00984 %
00985 %    o image: the image.
00986 %
00987 %    o low: the low target color.
00988 %
00989 %    o high: the high target color.
00990 %
00991 %    o opacity: the replacement opacity value.
00992 %
00993 %    o invert: paint any pixel that does not match the target color.
00994 %
00995 %    o exception: return any errors or warnings in this structure.
00996 %
00997 */
00998 MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
00999   const PixelInfo *low,const PixelInfo *high,const Quantum opacity,
01000   const MagickBooleanType invert,ExceptionInfo *exception)
01001 {
01002 #define TransparentPaintImageTag  "Transparent/Image"
01003 
01004   CacheView
01005     *image_view;
01006 
01007   MagickBooleanType
01008     status;
01009 
01010   MagickOffsetType
01011     progress;
01012 
01013   ssize_t
01014     y;
01015 
01016   assert(image != (Image *) NULL);
01017   assert(image->signature == MagickSignature);
01018   assert(high != (PixelInfo *) NULL);
01019   assert(low != (PixelInfo *) NULL);
01020   if (image->debug != MagickFalse)
01021     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01022   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01023     return(MagickFalse);
01024   if (image->matte == MagickFalse)
01025     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
01026   /*
01027     Make image color transparent.
01028   */
01029   status=MagickTrue;
01030   progress=0;
01031   image_view=AcquireCacheView(image);
01032 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01033   #pragma omp parallel for schedule(static,4) shared(progress,status)
01034 #endif
01035   for (y=0; y < (ssize_t) image->rows; y++)
01036   {
01037     MagickBooleanType
01038       match;
01039 
01040     PixelInfo
01041       pixel;
01042 
01043     register Quantum
01044       *restrict q;
01045 
01046     register ssize_t
01047       x;
01048 
01049     if (status == MagickFalse)
01050       continue;
01051     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01052     if (q == (Quantum *) NULL)
01053       {
01054         status=MagickFalse;
01055         continue;
01056       }
01057     GetPixelInfo(image,&pixel);
01058     for (x=0; x < (ssize_t) image->columns; x++)
01059     {
01060       GetPixelInfoPixel(image,q,&pixel);
01061       match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
01062         (pixel.green >= low->green) && (pixel.green <= high->green) &&
01063         (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ? MagickTrue :
01064         MagickFalse;
01065       if (match != invert)
01066         SetPixelAlpha(image,opacity,q);
01067       q+=GetPixelChannels(image);
01068     }
01069     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01070       status=MagickFalse;
01071     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01072       {
01073         MagickBooleanType
01074           proceed;
01075 
01076 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01077         #pragma omp critical (MagickCore_TransparentPaintImageChroma)
01078 #endif
01079         proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
01080           image->rows);
01081         if (proceed == MagickFalse)
01082           status=MagickFalse;
01083       }
01084   }
01085   image_view=DestroyCacheView(image_view);
01086   return(status);
01087 }