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