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