]> granicus.if.org Git - imagemagick/blob - MagickCore/effect.c
(no commit message)
[imagemagick] / MagickCore / effect.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                   EEEEE  FFFFF  FFFFF  EEEEE  CCCC  TTTTT                   %
7 %                   E      F      F      E     C        T                     %
8 %                   EEE    FFF    FFF    EEE   C        T                     %
9 %                   E      F      F      E     C        T                     %
10 %                   EEEEE  F      F      EEEEE  CCCC    T                     %
11 %                                                                             %
12 %                                                                             %
13 %                       MagickCore Image Effects Methods                      %
14 %                                                                             %
15 %                               Software Design                               %
16 %                                 John Cristy                                 %
17 %                                 October 1996                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/accelerate.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/decorate.h"
52 #include "MagickCore/distort.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/enhance.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/effect.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/gem-private.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/memory-private.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/montage.h"
70 #include "MagickCore/morphology.h"
71 #include "MagickCore/paint.h"
72 #include "MagickCore/pixel-accessor.h"
73 #include "MagickCore/pixel-private.h"
74 #include "MagickCore/property.h"
75 #include "MagickCore/quantize.h"
76 #include "MagickCore/quantum.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/random_.h"
79 #include "MagickCore/random-private.h"
80 #include "MagickCore/resample.h"
81 #include "MagickCore/resample-private.h"
82 #include "MagickCore/resize.h"
83 #include "MagickCore/resource_.h"
84 #include "MagickCore/segment.h"
85 #include "MagickCore/shear.h"
86 #include "MagickCore/signature-private.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/thread-private.h"
90 #include "MagickCore/transform.h"
91 #include "MagickCore/threshold.h"
92 \f
93 /*
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 %                                                                             %
96 %                                                                             %
97 %                                                                             %
98 %     A d a p t i v e B l u r I m a g e                                       %
99 %                                                                             %
100 %                                                                             %
101 %                                                                             %
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 %
104 %  AdaptiveBlurImage() adaptively blurs the image by blurring less
105 %  intensely near image edges and more intensely far from edges.  We blur the
106 %  image with a Gaussian operator of the given radius and standard deviation
107 %  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
108 %  radius of 0 and AdaptiveBlurImage() selects a suitable radius for you.
109 %
110 %  The format of the AdaptiveBlurImage method is:
111 %
112 %      Image *AdaptiveBlurImage(const Image *image,const double radius,
113 %        const double sigma,ExceptionInfo *exception)
114 %
115 %  A description of each parameter follows:
116 %
117 %    o image: the image.
118 %
119 %    o radius: the radius of the Gaussian, in pixels, not counting the center
120 %      pixel.
121 %
122 %    o sigma: the standard deviation of the Laplacian, in pixels.
123 %
124 %    o exception: return any errors or warnings in this structure.
125 %
126 */
127
128 MagickExport MagickBooleanType AdaptiveLevelImage(Image *image,
129   const char *levels,ExceptionInfo *exception)
130 {
131   double
132     black_point,
133     gamma,
134     white_point;
135
136   GeometryInfo
137     geometry_info;
138
139   MagickBooleanType
140     status;
141
142   MagickStatusType
143     flags;
144
145   /*
146     Parse levels.
147   */
148   if (levels == (char *) NULL)
149     return(MagickFalse);
150   flags=ParseGeometry(levels,&geometry_info);
151   black_point=geometry_info.rho;
152   white_point=(double) QuantumRange;
153   if ((flags & SigmaValue) != 0)
154     white_point=geometry_info.sigma;
155   gamma=1.0;
156   if ((flags & XiValue) != 0)
157     gamma=geometry_info.xi;
158   if ((flags & PercentValue) != 0)
159     {
160       black_point*=(double) image->columns*image->rows/100.0;
161       white_point*=(double) image->columns*image->rows/100.0;
162     }
163   if ((flags & SigmaValue) == 0)
164     white_point=(double) QuantumRange-black_point;
165   if ((flags & AspectValue ) == 0)
166     status=LevelImage(image,black_point,white_point,gamma,exception);
167   else
168     status=LevelizeImage(image,black_point,white_point,gamma,exception);
169   return(status);
170 }
171
172 MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
173   const double sigma,ExceptionInfo *exception)
174 {
175 #define AdaptiveBlurImageTag  "Convolve/Image"
176 #define MagickSigma  (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
177
178   CacheView
179     *blur_view,
180     *edge_view,
181     *image_view;
182
183   double
184     normalize;
185
186   Image
187     *blur_image,
188     *edge_image,
189     *gaussian_image;
190
191   MagickBooleanType
192     status;
193
194   MagickOffsetType
195     progress;
196
197   MagickRealType
198     **kernel;
199
200   register ssize_t
201     i;
202
203   size_t
204     width;
205
206   ssize_t
207     j,
208     k,
209     u,
210     v,
211     y;
212
213   assert(image != (const Image *) NULL);
214   assert(image->signature == MagickSignature);
215   if (image->debug != MagickFalse)
216     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
217   assert(exception != (ExceptionInfo *) NULL);
218   assert(exception->signature == MagickSignature);
219   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
220   if (blur_image == (Image *) NULL)
221     return((Image *) NULL);
222   if (fabs(sigma) < MagickEpsilon)
223     return(blur_image);
224   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
225     {
226       blur_image=DestroyImage(blur_image);
227       return((Image *) NULL);
228     }
229   /*
230     Edge detect the image brighness channel, level, blur, and level again.
231   */
232   edge_image=EdgeImage(image,radius,sigma,exception);
233   if (edge_image == (Image *) NULL)
234     {
235       blur_image=DestroyImage(blur_image);
236       return((Image *) NULL);
237     }
238   (void) AdaptiveLevelImage(edge_image,"20%,95%",exception);
239   gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
240   if (gaussian_image != (Image *) NULL)
241     {
242       edge_image=DestroyImage(edge_image);
243       edge_image=gaussian_image;
244     }
245   (void) AdaptiveLevelImage(edge_image,"10%,95%",exception);
246   /*
247     Create a set of kernels from maximum (radius,sigma) to minimum.
248   */
249   width=GetOptimalKernelWidth2D(radius,sigma);
250   kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
251     width,sizeof(*kernel)));
252   if (kernel == (MagickRealType  **) NULL)
253     {
254       edge_image=DestroyImage(edge_image);
255       blur_image=DestroyImage(blur_image);
256       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
257     }
258   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
259   for (i=0; i < (ssize_t) width; i+=2)
260   {
261     kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
262       (size_t) (width-i),(width-i)*sizeof(**kernel)));
263     if (kernel[i] == (MagickRealType *) NULL)
264       break;
265     normalize=0.0;
266     j=(ssize_t) (width-i)/2;
267     k=0;
268     for (v=(-j); v <= j; v++)
269     {
270       for (u=(-j); u <= j; u++)
271       {
272         kernel[i][k]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
273           MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
274         normalize+=kernel[i][k];
275         k++;
276       }
277     }
278     if (fabs(normalize) < MagickEpsilon)
279       normalize=MagickEpsilon;
280     normalize=PerceptibleReciprocal(normalize);
281     for (k=0; k < (j*j); k++)
282       kernel[i][k]=normalize*kernel[i][k];
283   }
284   if (i < (ssize_t) width)
285     {
286       for (i-=2; i >= 0; i-=2)
287         kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
288       kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
289       edge_image=DestroyImage(edge_image);
290       blur_image=DestroyImage(blur_image);
291       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
292     }
293   /*
294     Adaptively blur image.
295   */
296   status=MagickTrue;
297   progress=0;
298   image_view=AcquireVirtualCacheView(image,exception);
299   edge_view=AcquireVirtualCacheView(edge_image,exception);
300   blur_view=AcquireAuthenticCacheView(blur_image,exception);
301 #if defined(MAGICKCORE_OPENMP_SUPPORT)
302   #pragma omp parallel for schedule(static,4) shared(progress,status) \
303     magick_threads(image,blur_image,blur_image->rows,1)
304 #endif
305   for (y=0; y < (ssize_t) blur_image->rows; y++)
306   {
307     register const Quantum
308       *restrict r;
309
310     register Quantum
311       *restrict q;
312
313     register ssize_t
314       x;
315
316     if (status == MagickFalse)
317       continue;
318     r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
319     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
320       exception);
321     if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
322       {
323         status=MagickFalse;
324         continue;
325       }
326     for (x=0; x < (ssize_t) blur_image->columns; x++)
327     {
328       register const Quantum
329         *restrict p;
330
331       register ssize_t
332         i;
333
334       ssize_t
335         center,
336         j;
337
338       j=(ssize_t) ceil((double) width*QuantumScale*
339         GetPixelIntensity(edge_image,r)-0.5);
340       if (j < 0)
341         j=0;
342       else
343         if (j > (ssize_t) width)
344           j=(ssize_t) width;
345       if ((j & 0x01) != 0)
346         j--;
347       p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
348         (ssize_t) ((width-j)/2L),width-j,width-j,exception);
349       if (p == (const Quantum *) NULL)
350         break;
351       center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
352         GetPixelChannels(image)*((width-j)/2L);
353       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
354       {
355         double
356           alpha,
357           gamma,
358           pixel;
359
360         PixelChannel
361           channel;
362
363         PixelTrait
364           blur_traits,
365           traits;
366
367         register const MagickRealType
368           *restrict k;
369
370         register const Quantum
371           *restrict pixels;
372
373         register ssize_t
374           u;
375
376         ssize_t
377           v;
378
379         channel=GetPixelChannelChannel(image,i);
380         traits=GetPixelChannelTraits(image,channel);
381         blur_traits=GetPixelChannelTraits(blur_image,channel);
382         if ((traits == UndefinedPixelTrait) ||
383             (blur_traits == UndefinedPixelTrait))
384           continue;
385         if (((blur_traits & CopyPixelTrait) != 0) ||
386             (GetPixelMask(image,p+center) != 0))
387           {
388             SetPixelChannel(blur_image,channel,p[center+i],q);
389             continue;
390           }
391         k=kernel[j];
392         pixels=p;
393         pixel=0.0;
394         gamma=0.0;
395         if ((blur_traits & BlendPixelTrait) == 0)
396           {
397             /*
398               No alpha blending.
399             */
400             for (v=0; v < (ssize_t) (width-j); v++)
401             {
402               for (u=0; u < (ssize_t) (width-j); u++)
403               {
404                 pixel+=(*k)*pixels[i];
405                 gamma+=(*k);
406                 k++;
407                 pixels+=GetPixelChannels(image);
408               }
409             }
410             gamma=PerceptibleReciprocal(gamma);
411             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
412             continue;
413           }
414         /*
415           Alpha blending.
416         */
417         for (v=0; v < (ssize_t) (width-j); v++)
418         {
419           for (u=0; u < (ssize_t) (width-j); u++)
420           {
421             alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
422             pixel+=(*k)*alpha*pixels[i];
423             gamma+=(*k)*alpha;
424             k++;
425             pixels+=GetPixelChannels(image);
426           }
427         }
428         gamma=PerceptibleReciprocal(gamma);
429         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
430       }
431       q+=GetPixelChannels(blur_image);
432       r+=GetPixelChannels(edge_image);
433     }
434     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
435       status=MagickFalse;
436     if (image->progress_monitor != (MagickProgressMonitor) NULL)
437       {
438         MagickBooleanType
439           proceed;
440
441 #if defined(MAGICKCORE_OPENMP_SUPPORT)
442         #pragma omp critical (MagickCore_AdaptiveBlurImage)
443 #endif
444         proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress++,
445           image->rows);
446         if (proceed == MagickFalse)
447           status=MagickFalse;
448       }
449   }
450   blur_image->type=image->type;
451   blur_view=DestroyCacheView(blur_view);
452   edge_view=DestroyCacheView(edge_view);
453   image_view=DestroyCacheView(image_view);
454   edge_image=DestroyImage(edge_image);
455   for (i=0; i < (ssize_t) width;  i+=2)
456     kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
457   kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
458   if (status == MagickFalse)
459     blur_image=DestroyImage(blur_image);
460   return(blur_image);
461 }
462 \f
463 /*
464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 %                                                                             %
466 %                                                                             %
467 %                                                                             %
468 %     A d a p t i v e S h a r p e n I m a g e                                 %
469 %                                                                             %
470 %                                                                             %
471 %                                                                             %
472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 %
474 %  AdaptiveSharpenImage() adaptively sharpens the image by sharpening more
475 %  intensely near image edges and less intensely far from edges. We sharpen the
476 %  image with a Gaussian operator of the given radius and standard deviation
477 %  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
478 %  radius of 0 and AdaptiveSharpenImage() selects a suitable radius for you.
479 %
480 %  The format of the AdaptiveSharpenImage method is:
481 %
482 %      Image *AdaptiveSharpenImage(const Image *image,const double radius,
483 %        const double sigma,ExceptionInfo *exception)
484 %
485 %  A description of each parameter follows:
486 %
487 %    o image: the image.
488 %
489 %    o radius: the radius of the Gaussian, in pixels, not counting the center
490 %      pixel.
491 %
492 %    o sigma: the standard deviation of the Laplacian, in pixels.
493 %
494 %    o exception: return any errors or warnings in this structure.
495 %
496 */
497 MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
498   const double sigma,ExceptionInfo *exception)
499 {
500 #define AdaptiveSharpenImageTag  "Convolve/Image"
501 #define MagickSigma  (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
502
503   CacheView
504     *sharp_view,
505     *edge_view,
506     *image_view;
507
508   double
509     normalize;
510
511   Image
512     *sharp_image,
513     *edge_image,
514     *gaussian_image;
515
516   MagickBooleanType
517     status;
518
519   MagickOffsetType
520     progress;
521
522   MagickRealType
523     **kernel;
524
525   register ssize_t
526     i;
527
528   size_t
529     width;
530
531   ssize_t
532     j,
533     k,
534     u,
535     v,
536     y;
537
538   assert(image != (const Image *) NULL);
539   assert(image->signature == MagickSignature);
540   if (image->debug != MagickFalse)
541     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
542   assert(exception != (ExceptionInfo *) NULL);
543   assert(exception->signature == MagickSignature);
544   sharp_image=CloneImage(image,0,0,MagickTrue,exception);
545   if (sharp_image == (Image *) NULL)
546     return((Image *) NULL);
547   if (fabs(sigma) < MagickEpsilon)
548     return(sharp_image);
549   if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
550     {
551       sharp_image=DestroyImage(sharp_image);
552       return((Image *) NULL);
553     }
554   /*
555     Edge detect the image brighness channel, level, sharp, and level again.
556   */
557   edge_image=EdgeImage(image,radius,sigma,exception);
558   if (edge_image == (Image *) NULL)
559     {
560       sharp_image=DestroyImage(sharp_image);
561       return((Image *) NULL);
562     }
563   (void) AdaptiveLevelImage(edge_image,"20%,95%",exception);
564   gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
565   if (gaussian_image != (Image *) NULL)
566     {
567       edge_image=DestroyImage(edge_image);
568       edge_image=gaussian_image;
569     }
570   (void) AdaptiveLevelImage(edge_image,"10%,95%",exception);
571   /*
572     Create a set of kernels from maximum (radius,sigma) to minimum.
573   */
574   width=GetOptimalKernelWidth2D(radius,sigma);
575   kernel=(MagickRealType **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
576     width,sizeof(*kernel)));
577   if (kernel == (MagickRealType **) NULL)
578     {
579       edge_image=DestroyImage(edge_image);
580       sharp_image=DestroyImage(sharp_image);
581       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
582     }
583   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
584   for (i=0; i < (ssize_t) width; i+=2)
585   {
586     kernel[i]=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
587       (size_t) (width-i),(width-i)*sizeof(**kernel)));
588     if (kernel[i] == (MagickRealType *) NULL)
589       break;
590     normalize=0.0;
591     j=(ssize_t) (width-i)/2;
592     k=0;
593     for (v=(-j); v <= j; v++)
594     {
595       for (u=(-j); u <= j; u++)
596       {
597         kernel[i][k]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
598           MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
599         normalize+=kernel[i][k];
600         k++;
601       }
602     }
603     if (fabs(normalize) < MagickEpsilon)
604       normalize=MagickEpsilon;
605     normalize=PerceptibleReciprocal(normalize);
606     for (k=0; k < (j*j); k++)
607       kernel[i][k]=normalize*kernel[i][k];
608   }
609   if (i < (ssize_t) width)
610     {
611       for (i-=2; i >= 0; i-=2)
612         kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
613       kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
614       edge_image=DestroyImage(edge_image);
615       sharp_image=DestroyImage(sharp_image);
616       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
617     }
618   /*
619     Adaptively sharpen image.
620   */
621   status=MagickTrue;
622   progress=0;
623   image_view=AcquireVirtualCacheView(image,exception);
624   edge_view=AcquireVirtualCacheView(edge_image,exception);
625   sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
626 #if defined(MAGICKCORE_OPENMP_SUPPORT)
627   #pragma omp parallel for schedule(static,4) shared(progress,status) \
628     magick_threads(image,sharp_image,sharp_image->rows,1)
629 #endif
630   for (y=0; y < (ssize_t) sharp_image->rows; y++)
631   {
632     register const Quantum
633       *restrict r;
634
635     register Quantum
636       *restrict q;
637
638     register ssize_t
639       x;
640
641     if (status == MagickFalse)
642       continue;
643     r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
644     q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
645       exception);
646     if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
647       {
648         status=MagickFalse;
649         continue;
650       }
651     for (x=0; x < (ssize_t) sharp_image->columns; x++)
652     {
653       register const Quantum
654         *restrict p;
655
656       register ssize_t
657         i;
658
659       ssize_t
660         center,
661         j;
662
663       j=(ssize_t) ceil((double) width*QuantumScale*
664         GetPixelIntensity(edge_image,r)-0.5);
665       if (j < 0)
666         j=0;
667       else
668         if (j > (ssize_t) width)
669           j=(ssize_t) width;
670       if ((j & 0x01) != 0)
671         j--;
672       p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
673         (ssize_t) ((width-j)/2L),width-j,width-j,exception);
674       if (p == (const Quantum *) NULL)
675         break;
676       center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
677         GetPixelChannels(image)*((width-j)/2);
678       for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
679       {
680         double
681           alpha,
682           gamma,
683           pixel;
684
685         PixelChannel
686           channel;
687
688         PixelTrait
689           sharp_traits,
690           traits;
691
692         register const MagickRealType
693           *restrict k;
694
695         register const Quantum
696           *restrict pixels;
697
698         register ssize_t
699           u;
700
701         ssize_t
702           v;
703
704         channel=GetPixelChannelChannel(image,i);
705         traits=GetPixelChannelTraits(image,channel);
706         sharp_traits=GetPixelChannelTraits(sharp_image,channel);
707         if ((traits == UndefinedPixelTrait) ||
708             (sharp_traits == UndefinedPixelTrait))
709           continue;
710         if (((sharp_traits & CopyPixelTrait) != 0) ||
711             (GetPixelMask(image,p+center) != 0))
712           {
713             SetPixelChannel(sharp_image,channel,p[center+i],q);
714             continue;
715           }
716         k=kernel[j];
717         pixels=p;
718         pixel=0.0;
719         gamma=0.0;
720         if ((sharp_traits & BlendPixelTrait) == 0)
721           {
722             /*
723               No alpha blending.
724             */
725             for (v=0; v < (ssize_t) (width-j); v++)
726             {
727               for (u=0; u < (ssize_t) (width-j); u++)
728               {
729                 pixel+=(*k)*pixels[i];
730                 gamma+=(*k);
731                 k++;
732                 pixels+=GetPixelChannels(image);
733               }
734             }
735             gamma=PerceptibleReciprocal(gamma);
736             SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
737             continue;
738           }
739         /*
740           Alpha blending.
741         */
742         for (v=0; v < (ssize_t) (width-j); v++)
743         {
744           for (u=0; u < (ssize_t) (width-j); u++)
745           {
746             alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
747             pixel+=(*k)*alpha*pixels[i];
748             gamma+=(*k)*alpha;
749             k++;
750             pixels+=GetPixelChannels(image);
751           }
752         }
753         gamma=PerceptibleReciprocal(gamma);
754         SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
755       }
756       q+=GetPixelChannels(sharp_image);
757       r+=GetPixelChannels(edge_image);
758     }
759     if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
760       status=MagickFalse;
761     if (image->progress_monitor != (MagickProgressMonitor) NULL)
762       {
763         MagickBooleanType
764           proceed;
765
766 #if defined(MAGICKCORE_OPENMP_SUPPORT)
767         #pragma omp critical (MagickCore_AdaptiveSharpenImage)
768 #endif
769         proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress++,
770           image->rows);
771         if (proceed == MagickFalse)
772           status=MagickFalse;
773       }
774   }
775   sharp_image->type=image->type;
776   sharp_view=DestroyCacheView(sharp_view);
777   edge_view=DestroyCacheView(edge_view);
778   image_view=DestroyCacheView(image_view);
779   edge_image=DestroyImage(edge_image);
780   for (i=0; i < (ssize_t) width;  i+=2)
781     kernel[i]=(MagickRealType *) RelinquishAlignedMemory(kernel[i]);
782   kernel=(MagickRealType **) RelinquishAlignedMemory(kernel);
783   if (status == MagickFalse)
784     sharp_image=DestroyImage(sharp_image);
785   return(sharp_image);
786 }
787 \f
788 /*
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 %                                                                             %
791 %                                                                             %
792 %                                                                             %
793 %     B l u r I m a g e                                                       %
794 %                                                                             %
795 %                                                                             %
796 %                                                                             %
797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 %
799 %  BlurImage() blurs an image.  We convolve the image with a Gaussian operator
800 %  of the given radius and standard deviation (sigma).  For reasonable results,
801 %  the radius should be larger than sigma.  Use a radius of 0 and BlurImage()
802 %  selects a suitable radius for you.
803 %
804 %  The format of the BlurImage method is:
805 %
806 %      Image *BlurImage(const Image *image,const double radius,
807 %        const double sigma,ExceptionInfo *exception)
808 %
809 %  A description of each parameter follows:
810 %
811 %    o image: the image.
812 %
813 %    o radius: the radius of the Gaussian, in pixels, not counting the center
814 %      pixel.
815 %
816 %    o sigma: the standard deviation of the Gaussian, in pixels.
817 %
818 %    o exception: return any errors or warnings in this structure.
819 %
820 */
821 MagickExport Image *BlurImage(const Image *image,const double radius,
822   const double sigma,ExceptionInfo *exception)
823 {
824   double
825     normalize;
826
827   Image
828     *blur_image;
829
830   KernelInfo
831     *kernel_info;
832
833   register ssize_t
834     i;
835
836   size_t
837     width;
838
839   ssize_t
840     j,
841     u,
842     v;
843
844   assert(image != (const Image *) NULL);
845   assert(image->signature == MagickSignature);
846   if (image->debug != MagickFalse)
847     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
848   assert(exception != (ExceptionInfo *) NULL);
849   assert(exception->signature == MagickSignature);
850   width=GetOptimalKernelWidth2D(radius,sigma);
851   kernel_info=AcquireKernelInfo((const char *) NULL);
852   if (kernel_info == (KernelInfo *) NULL)
853     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
854   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
855   kernel_info->width=width;
856   kernel_info->height=width;
857   kernel_info->x=(ssize_t) width/2;
858   kernel_info->y=(ssize_t) width/2;
859   kernel_info->signature=MagickSignature;
860   kernel_info->values=(MagickRealType *) MagickAssumeAligned(
861     AcquireAlignedMemory(kernel_info->width,kernel_info->width*
862     sizeof(*kernel_info->values)));
863   if (kernel_info->values == (MagickRealType *) NULL)
864     {
865       kernel_info=DestroyKernelInfo(kernel_info);
866       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
867     }
868   normalize=0.0;
869   j=(ssize_t) kernel_info->width/2;
870   i=0;
871   for (v=(-j); v <= j; v++)
872   {
873     for (u=(-j); u <= j; u++)
874     {
875       kernel_info->values[i]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*
876         MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
877       normalize+=kernel_info->values[i];
878       i++;
879     }
880   }
881   kernel_info->values[i/2]+=(1.0-normalize);
882   blur_image=ConvolveImage(image,kernel_info,exception);
883   kernel_info=DestroyKernelInfo(kernel_info);
884   return(blur_image);
885 }
886 \f
887 /*
888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 %                                                                             %
890 %                                                                             %
891 %                                                                             %
892 %     C o n v o l v e I m a g e                                               %
893 %                                                                             %
894 %                                                                             %
895 %                                                                             %
896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897 %
898 %  ConvolveImage() applies a custom convolution kernel to the image.
899 %
900 %  The format of the ConvolveImage method is:
901 %
902 %      Image *ConvolveImage(const Image *image,const KernelInfo *kernel,
903 %        ExceptionInfo *exception)
904 %
905 %  A description of each parameter follows:
906 %
907 %    o image: the image.
908 %
909 %    o kernel: the filtering kernel.
910 %
911 %    o exception: return any errors or warnings in this structure.
912 %
913 */
914 MagickExport Image *ConvolveImage(const Image *image,
915   const KernelInfo *kernel_info,ExceptionInfo *exception)
916 {
917   return(MorphologyImage(image,CorrelateMorphology,1,kernel_info,exception));
918 }
919 \f
920 /*
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 %                                                                             %
923 %                                                                             %
924 %                                                                             %
925 %     D e s p e c k l e I m a g e                                             %
926 %                                                                             %
927 %                                                                             %
928 %                                                                             %
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
930 %
931 %  DespeckleImage() reduces the speckle noise in an image while perserving the
932 %  edges of the original image.  A speckle removing filter uses a complementary %  hulling technique (raising pixels that are darker than their surrounding
933 %  neighbors, then complementarily lowering pixels that are brighter than their
934 %  surrounding neighbors) to reduce the speckle index of that image (reference
935 %  Crimmins speckle removal).
936 %
937 %  The format of the DespeckleImage method is:
938 %
939 %      Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
940 %
941 %  A description of each parameter follows:
942 %
943 %    o image: the image.
944 %
945 %    o exception: return any errors or warnings in this structure.
946 %
947 */
948
949 static void Hull(const Image *image,const ssize_t x_offset,
950   const ssize_t y_offset,const size_t columns,const size_t rows,
951   const int polarity,Quantum *restrict f,Quantum *restrict g)
952 {
953   register Quantum
954     *p,
955     *q,
956     *r,
957     *s;
958
959   ssize_t
960     y;
961
962   assert(f != (Quantum *) NULL);
963   assert(g != (Quantum *) NULL);
964   p=f+(columns+2);
965   q=g+(columns+2);
966   r=p+(y_offset*(columns+2)+x_offset);
967 #if defined(MAGICKCORE_OPENMP_SUPPORT)
968   #pragma omp parallel for schedule(static,4) \
969     magick_threads(image,image,1,1)
970 #endif
971   for (y=0; y < (ssize_t) rows; y++)
972   {
973     MagickRealType
974       v;
975
976     register ssize_t
977       i,
978       x;
979
980     i=(2*y+1)+y*columns;
981     if (polarity > 0)
982       for (x=0; x < (ssize_t) columns; x++)
983       {
984         v=(MagickRealType) p[i];
985         if ((MagickRealType) r[i] >= (v+ScaleCharToQuantum(2)))
986           v+=ScaleCharToQuantum(1);
987         q[i]=(Quantum) v;
988         i++;
989       }
990     else
991       for (x=0; x < (ssize_t) columns; x++)
992       {
993         v=(MagickRealType) p[i];
994         if ((MagickRealType) r[i] <= (v-ScaleCharToQuantum(2)))
995           v-=ScaleCharToQuantum(1);
996         q[i]=(Quantum) v;
997         i++;
998       }
999   }
1000   p=f+(columns+2);
1001   q=g+(columns+2);
1002   r=q+(y_offset*(columns+2)+x_offset);
1003   s=q-(y_offset*(columns+2)+x_offset);
1004 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1005   #pragma omp parallel for schedule(static,4) \
1006     magick_threads(image,image,1,1)
1007 #endif
1008   for (y=0; y < (ssize_t) rows; y++)
1009   {
1010     register ssize_t
1011       i,
1012       x;
1013
1014     MagickRealType
1015       v;
1016
1017     i=(2*y+1)+y*columns;
1018     if (polarity > 0)
1019       for (x=0; x < (ssize_t) columns; x++)
1020       {
1021         v=(MagickRealType) q[i];
1022         if (((MagickRealType) s[i] >= (v+ScaleCharToQuantum(2))) &&
1023             ((MagickRealType) r[i] > v))
1024           v+=ScaleCharToQuantum(1);
1025         p[i]=(Quantum) v;
1026         i++;
1027       }
1028     else
1029       for (x=0; x < (ssize_t) columns; x++)
1030       {
1031         v=(MagickRealType) q[i];
1032         if (((MagickRealType) s[i] <= (v-ScaleCharToQuantum(2))) &&
1033             ((MagickRealType) r[i] < v))
1034           v-=ScaleCharToQuantum(1);
1035         p[i]=(Quantum) v;
1036         i++;
1037       }
1038   }
1039 }
1040
1041 MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
1042 {
1043 #define DespeckleImageTag  "Despeckle/Image"
1044
1045   CacheView
1046     *despeckle_view,
1047     *image_view;
1048
1049   Image
1050     *despeckle_image;
1051
1052   MagickBooleanType
1053     status;
1054
1055   Quantum
1056     *restrict buffer,
1057     *restrict pixels;
1058
1059   register ssize_t
1060     i;
1061
1062   size_t
1063     length;
1064
1065   static const ssize_t
1066     X[4] = {0, 1, 1,-1},
1067     Y[4] = {1, 0, 1, 1};
1068
1069   /*
1070     Allocate despeckled image.
1071   */
1072   assert(image != (const Image *) NULL);
1073   assert(image->signature == MagickSignature);
1074   if (image->debug != MagickFalse)
1075     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1076   assert(exception != (ExceptionInfo *) NULL);
1077   assert(exception->signature == MagickSignature);
1078   despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1079   if (despeckle_image == (Image *) NULL)
1080     return((Image *) NULL);
1081   status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1082   if (status == MagickFalse)
1083     {
1084       despeckle_image=DestroyImage(despeckle_image);
1085       return((Image *) NULL);
1086     }
1087   /*
1088     Allocate image buffer.
1089   */
1090   length=(size_t) ((image->columns+2)*(image->rows+2));
1091   pixels=(Quantum *) AcquireQuantumMemory(length,sizeof(*pixels));
1092   buffer=(Quantum *) AcquireQuantumMemory(length,sizeof(*buffer));
1093   if ((pixels == (Quantum *) NULL) || (buffer == (Quantum *) NULL))
1094     {
1095       if (buffer != (Quantum *) NULL)
1096         buffer=(Quantum *) RelinquishMagickMemory(buffer);
1097       if (pixels != (Quantum *) NULL)
1098         pixels=(Quantum *) RelinquishMagickMemory(pixels);
1099       despeckle_image=DestroyImage(despeckle_image);
1100       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1101     }
1102   /*
1103     Reduce speckle in the image.
1104   */
1105   status=MagickTrue;
1106   image_view=AcquireVirtualCacheView(image,exception);
1107   despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1108   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1109   {
1110     PixelChannel
1111        channel;
1112
1113     PixelTrait
1114       despeckle_traits,
1115       traits;
1116
1117     register ssize_t
1118       k,
1119       x;
1120
1121     ssize_t
1122       j,
1123       y;
1124
1125     if (status == MagickFalse)
1126       continue;
1127     channel=GetPixelChannelChannel(image,i);
1128     traits=GetPixelChannelTraits(image,channel);
1129     despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1130     if ((traits == UndefinedPixelTrait) ||
1131         (despeckle_traits == UndefinedPixelTrait))
1132       continue;
1133     if ((despeckle_traits & CopyPixelTrait) != 0)
1134       continue;
1135     (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
1136     j=(ssize_t) image->columns+2;
1137     for (y=0; y < (ssize_t) image->rows; y++)
1138     {
1139       register const Quantum
1140         *restrict p;
1141
1142       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1143       if (p == (const Quantum *) NULL)
1144         {
1145           status=MagickFalse;
1146           continue;
1147         }
1148       j++;
1149       for (x=0; x < (ssize_t) image->columns; x++)
1150       {
1151         pixels[j++]=p[i];
1152         p+=GetPixelChannels(image);
1153       }
1154       j++;
1155     }
1156     (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
1157     for (k=0; k < 4; k++)
1158     {
1159       Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1160       Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1161       Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1162       Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1163     }
1164     j=(ssize_t) image->columns+2;
1165     for (y=0; y < (ssize_t) image->rows; y++)
1166     {
1167       MagickBooleanType
1168         sync;
1169
1170       register Quantum
1171         *restrict q;
1172
1173       q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1174         1,exception);
1175       if (q == (Quantum *) NULL)
1176         {
1177           status=MagickFalse;
1178           continue;
1179         }
1180       j++;
1181       for (x=0; x < (ssize_t) image->columns; x++)
1182       {
1183         SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1184         q+=GetPixelChannels(despeckle_image);
1185       }
1186       sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1187       if (sync == MagickFalse)
1188         status=MagickFalse;
1189       j++;
1190     }
1191     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1192       {
1193         MagickBooleanType
1194           proceed;
1195
1196         proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1197           GetPixelChannels(image));
1198         if (proceed == MagickFalse)
1199           status=MagickFalse;
1200       }
1201   }
1202   despeckle_view=DestroyCacheView(despeckle_view);
1203   image_view=DestroyCacheView(image_view);
1204   buffer=(Quantum *) RelinquishMagickMemory(buffer);
1205   pixels=(Quantum *) RelinquishMagickMemory(pixels);
1206   despeckle_image->type=image->type;
1207   if (status == MagickFalse)
1208     despeckle_image=DestroyImage(despeckle_image);
1209   return(despeckle_image);
1210 }
1211 \f
1212 /*
1213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214 %                                                                             %
1215 %                                                                             %
1216 %                                                                             %
1217 %     E d g e I m a g e                                                       %
1218 %                                                                             %
1219 %                                                                             %
1220 %                                                                             %
1221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1222 %
1223 %  EdgeImage() finds edges in an image.  Radius defines the radius of the
1224 %  convolution filter.  Use a radius of 0 and EdgeImage() selects a suitable
1225 %  radius for you.
1226 %
1227 %  The format of the EdgeImage method is:
1228 %
1229 %      Image *EdgeImage(const Image *image,const double radius,
1230 %        const double sigma,ExceptionInfo *exception)
1231 %
1232 %  A description of each parameter follows:
1233 %
1234 %    o image: the image.
1235 %
1236 %    o radius: the radius of the pixel neighborhood.
1237 %
1238 %    o sigma: the standard deviation of the Gaussian, in pixels.
1239 %
1240 %    o exception: return any errors or warnings in this structure.
1241 %
1242 */
1243 MagickExport Image *EdgeImage(const Image *image,const double radius,
1244   const double sigma,ExceptionInfo *exception)
1245 {
1246   Image
1247     *edge_image;
1248
1249   KernelInfo
1250     *kernel_info;
1251
1252   register ssize_t
1253     i;
1254
1255   size_t
1256     width;
1257
1258   ssize_t
1259     j,
1260     u,
1261     v;
1262
1263   assert(image != (const Image *) NULL);
1264   assert(image->signature == MagickSignature);
1265   if (image->debug != MagickFalse)
1266     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1267   assert(exception != (ExceptionInfo *) NULL);
1268   assert(exception->signature == MagickSignature);
1269   width=GetOptimalKernelWidth1D(radius,sigma);
1270   kernel_info=AcquireKernelInfo((const char *) NULL);
1271   if (kernel_info == (KernelInfo *) NULL)
1272     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1273   kernel_info->width=width;
1274   kernel_info->height=width;
1275   kernel_info->x=(ssize_t) width/2;
1276   kernel_info->y=(ssize_t) width/2;
1277   kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1278     AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1279     sizeof(*kernel_info->values)));
1280   if (kernel_info->values == (MagickRealType *) NULL)
1281     {
1282       kernel_info=DestroyKernelInfo(kernel_info);
1283       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1284     }
1285   j=(ssize_t) kernel_info->width/2;
1286   i=0;
1287   for (v=(-j); v <= j; v++)
1288   {
1289     for (u=(-j); u <= j; u++)
1290     {
1291       kernel_info->values[i]=(MagickRealType) (-1.0);
1292       i++;
1293     }
1294   }
1295   kernel_info->values[i/2]=(MagickRealType) (width*width-1.0);
1296   edge_image=ConvolveImage(image,kernel_info,exception);
1297   kernel_info=DestroyKernelInfo(kernel_info);
1298   return(edge_image);
1299 }
1300 \f
1301 /*
1302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 %                                                                             %
1304 %                                                                             %
1305 %                                                                             %
1306 %     E m b o s s I m a g e                                                   %
1307 %                                                                             %
1308 %                                                                             %
1309 %                                                                             %
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 %
1312 %  EmbossImage() returns a grayscale image with a three-dimensional effect.
1313 %  We convolve the image with a Gaussian operator of the given radius and
1314 %  standard deviation (sigma).  For reasonable results, radius should be
1315 %  larger than sigma.  Use a radius of 0 and Emboss() selects a suitable
1316 %  radius for you.
1317 %
1318 %  The format of the EmbossImage method is:
1319 %
1320 %      Image *EmbossImage(const Image *image,const double radius,
1321 %        const double sigma,ExceptionInfo *exception)
1322 %
1323 %  A description of each parameter follows:
1324 %
1325 %    o image: the image.
1326 %
1327 %    o radius: the radius of the pixel neighborhood.
1328 %
1329 %    o sigma: the standard deviation of the Gaussian, in pixels.
1330 %
1331 %    o exception: return any errors or warnings in this structure.
1332 %
1333 */
1334 MagickExport Image *EmbossImage(const Image *image,const double radius,
1335   const double sigma,ExceptionInfo *exception)
1336 {
1337   Image
1338     *emboss_image;
1339
1340   KernelInfo
1341     *kernel_info;
1342
1343   register ssize_t
1344     i;
1345
1346   size_t
1347     width;
1348
1349   ssize_t
1350     j,
1351     k,
1352     u,
1353     v;
1354
1355   assert(image != (const Image *) NULL);
1356   assert(image->signature == MagickSignature);
1357   if (image->debug != MagickFalse)
1358     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1359   assert(exception != (ExceptionInfo *) NULL);
1360   assert(exception->signature == MagickSignature);
1361   width=GetOptimalKernelWidth1D(radius,sigma);
1362   kernel_info=AcquireKernelInfo((const char *) NULL);
1363   if (kernel_info == (KernelInfo *) NULL)
1364     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1365   kernel_info->width=width;
1366   kernel_info->height=width;
1367   kernel_info->x=(ssize_t) width/2;
1368   kernel_info->y=(ssize_t) width/2;
1369   kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1370     AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1371     sizeof(*kernel_info->values)));
1372   if (kernel_info->values == (MagickRealType *) NULL)
1373     {
1374       kernel_info=DestroyKernelInfo(kernel_info);
1375       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1376     }
1377   j=(ssize_t) kernel_info->width/2;
1378   k=j;
1379   i=0;
1380   for (v=(-j); v <= j; v++)
1381   {
1382     for (u=(-j); u <= j; u++)
1383     {
1384       kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1385         8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1386         (2.0*MagickPI*MagickSigma*MagickSigma));
1387       if (u != k)
1388         kernel_info->values[i]=0.0;
1389       i++;
1390     }
1391     k--;
1392   }
1393   emboss_image=ConvolveImage(image,kernel_info,exception);
1394   kernel_info=DestroyKernelInfo(kernel_info);
1395   if (emboss_image != (Image *) NULL)
1396     (void) EqualizeImage(emboss_image,exception);
1397   return(emboss_image);
1398 }
1399 \f
1400 /*
1401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 %                                                                             %
1403 %                                                                             %
1404 %                                                                             %
1405 %     G a u s s i a n B l u r I m a g e                                       %
1406 %                                                                             %
1407 %                                                                             %
1408 %                                                                             %
1409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 %
1411 %  GaussianBlurImage() blurs an image.  We convolve the image with a
1412 %  Gaussian operator of the given radius and standard deviation (sigma).
1413 %  For reasonable results, the radius should be larger than sigma.  Use a
1414 %  radius of 0 and GaussianBlurImage() selects a suitable radius for you
1415 %
1416 %  The format of the GaussianBlurImage method is:
1417 %
1418 %      Image *GaussianBlurImage(const Image *image,onst double radius,
1419 %        const double sigma,ExceptionInfo *exception)
1420 %
1421 %  A description of each parameter follows:
1422 %
1423 %    o image: the image.
1424 %
1425 %    o radius: the radius of the Gaussian, in pixels, not counting the center
1426 %      pixel.
1427 %
1428 %    o sigma: the standard deviation of the Gaussian, in pixels.
1429 %
1430 %    o exception: return any errors or warnings in this structure.
1431 %
1432 */
1433 MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
1434   const double sigma,ExceptionInfo *exception)
1435 {
1436   Image
1437     *blur_image;
1438
1439   KernelInfo
1440     *kernel_info;
1441
1442   register ssize_t
1443     i;
1444
1445   size_t
1446     width;
1447
1448   ssize_t
1449     j,
1450     u,
1451     v;
1452
1453   assert(image != (const Image *) NULL);
1454   assert(image->signature == MagickSignature);
1455   if (image->debug != MagickFalse)
1456     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1457   assert(exception != (ExceptionInfo *) NULL);
1458   assert(exception->signature == MagickSignature);
1459   width=GetOptimalKernelWidth2D(radius,sigma);
1460   kernel_info=AcquireKernelInfo((const char *) NULL);
1461   if (kernel_info == (KernelInfo *) NULL)
1462     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1463   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
1464   kernel_info->width=width;
1465   kernel_info->height=width;
1466   kernel_info->x=(ssize_t) width/2;
1467   kernel_info->y=(ssize_t) width/2;
1468   kernel_info->signature=MagickSignature;
1469   kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1470     AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1471     sizeof(*kernel_info->values)));
1472   if (kernel_info->values == (MagickRealType *) NULL)
1473     {
1474       kernel_info=DestroyKernelInfo(kernel_info);
1475       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1476     }
1477   j=(ssize_t) kernel_info->width/2;
1478   i=0;
1479   for (v=(-j); v <= j; v++)
1480   {
1481     for (u=(-j); u <= j; u++)
1482     {
1483       kernel_info->values[i]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*
1484         MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
1485       i++;
1486     }
1487   }
1488   blur_image=ConvolveImage(image,kernel_info,exception);
1489   kernel_info=DestroyKernelInfo(kernel_info);
1490   return(blur_image);
1491 }
1492 \f
1493 /*
1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495 %                                                                             %
1496 %                                                                             %
1497 %                                                                             %
1498 %     M o t i o n B l u r I m a g e                                           %
1499 %                                                                             %
1500 %                                                                             %
1501 %                                                                             %
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 %
1504 %  MotionBlurImage() simulates motion blur.  We convolve the image with a
1505 %  Gaussian operator of the given radius and standard deviation (sigma).
1506 %  For reasonable results, radius should be larger than sigma.  Use a
1507 %  radius of 0 and MotionBlurImage() selects a suitable radius for you.
1508 %  Angle gives the angle of the blurring motion.
1509 %
1510 %  Andrew Protano contributed this effect.
1511 %
1512 %  The format of the MotionBlurImage method is:
1513 %
1514 %    Image *MotionBlurImage(const Image *image,const double radius,
1515 %      const double sigma,const double angle,ExceptionInfo *exception)
1516 %
1517 %  A description of each parameter follows:
1518 %
1519 %    o image: the image.
1520 %
1521 %    o radius: the radius of the Gaussian, in pixels, not counting
1522 %      the center pixel.
1523 %
1524 %    o sigma: the standard deviation of the Gaussian, in pixels.
1525 %
1526 %    o angle: Apply the effect along this angle.
1527 %
1528 %    o exception: return any errors or warnings in this structure.
1529 %
1530 */
1531
1532 static MagickRealType *GetMotionBlurKernel(const size_t width,
1533   const double sigma)
1534 {
1535   MagickRealType
1536     *kernel,
1537     normalize;
1538
1539   register ssize_t
1540     i;
1541
1542   /*
1543    Generate a 1-D convolution kernel.
1544   */
1545   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1546   kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
1547     width,sizeof(*kernel)));
1548   if (kernel == (MagickRealType *) NULL)
1549     return(kernel);
1550   normalize=0.0;
1551   for (i=0; i < (ssize_t) width; i++)
1552   {
1553     kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
1554       MagickSigma)))/(MagickSQ2PI*MagickSigma));
1555     normalize+=kernel[i];
1556   }
1557   for (i=0; i < (ssize_t) width; i++)
1558     kernel[i]/=normalize;
1559   return(kernel);
1560 }
1561
1562 MagickExport Image *MotionBlurImage(const Image *image,const double radius,
1563   const double sigma,const double angle,ExceptionInfo *exception)
1564 {
1565 #define BlurImageTag  "Blur/Image"
1566
1567   CacheView
1568     *blur_view,
1569     *image_view,
1570     *motion_view;
1571
1572   Image
1573     *blur_image;
1574
1575   MagickBooleanType
1576     status;
1577
1578   MagickOffsetType
1579     progress;
1580
1581   MagickRealType
1582     *kernel;
1583
1584   OffsetInfo
1585     *offset;
1586
1587   PointInfo
1588     point;
1589
1590   register ssize_t
1591     i;
1592
1593   size_t
1594     width;
1595
1596   ssize_t
1597     y;
1598
1599   assert(image != (Image *) NULL);
1600   assert(image->signature == MagickSignature);
1601   if (image->debug != MagickFalse)
1602     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1603   assert(exception != (ExceptionInfo *) NULL);
1604   width=GetOptimalKernelWidth1D(radius,sigma);
1605   kernel=GetMotionBlurKernel(width,sigma);
1606   if (kernel == (MagickRealType *) NULL)
1607     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1608   offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
1609   if (offset == (OffsetInfo *) NULL)
1610     {
1611       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
1612       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1613     }
1614   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1615   if (blur_image == (Image *) NULL)
1616     {
1617       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
1618       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
1619       return((Image *) NULL);
1620     }
1621   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
1622     {
1623       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
1624       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
1625       blur_image=DestroyImage(blur_image);
1626       return((Image *) NULL);
1627     }
1628   point.x=(double) width*sin(DegreesToRadians(angle));
1629   point.y=(double) width*cos(DegreesToRadians(angle));
1630   for (i=0; i < (ssize_t) width; i++)
1631   {
1632     offset[i].x=(ssize_t) ceil((double) (i*point.y)/hypot(point.x,point.y)-0.5);
1633     offset[i].y=(ssize_t) ceil((double) (i*point.x)/hypot(point.x,point.y)-0.5);
1634   }
1635   /*
1636     Motion blur image.
1637   */
1638   status=MagickTrue;
1639   progress=0;
1640   image_view=AcquireVirtualCacheView(image,exception);
1641   motion_view=AcquireVirtualCacheView(image,exception);
1642   blur_view=AcquireAuthenticCacheView(blur_image,exception);
1643 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1644   #pragma omp parallel for schedule(static,4) shared(progress,status) \
1645     magick_threads(image,blur_image,image->rows,1)
1646 #endif
1647   for (y=0; y < (ssize_t) image->rows; y++)
1648   {
1649     register const Quantum
1650       *restrict p;
1651
1652     register Quantum
1653       *restrict q;
1654
1655     register ssize_t
1656       x;
1657
1658     if (status == MagickFalse)
1659       continue;
1660     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1661     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
1662       exception);
1663     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1664       {
1665         status=MagickFalse;
1666         continue;
1667       }
1668     for (x=0; x < (ssize_t) image->columns; x++)
1669     {
1670       register ssize_t
1671         i;
1672
1673       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1674       {
1675         double
1676           alpha,
1677           gamma,
1678           pixel;
1679
1680         PixelChannel
1681           channel;
1682
1683         PixelTrait
1684           blur_traits,
1685           traits;
1686
1687         register const Quantum
1688           *restrict r;
1689
1690         register MagickRealType
1691           *restrict k;
1692
1693         register ssize_t
1694           j;
1695
1696         channel=GetPixelChannelChannel(image,i);
1697         traits=GetPixelChannelTraits(image,channel);
1698         blur_traits=GetPixelChannelTraits(blur_image,channel);
1699         if ((traits == UndefinedPixelTrait) ||
1700             (blur_traits == UndefinedPixelTrait))
1701           continue;
1702         if (((blur_traits & CopyPixelTrait) != 0) ||
1703             (GetPixelMask(image,p) != 0))
1704           {
1705             SetPixelChannel(blur_image,channel,p[i],q);
1706             continue;
1707           }
1708         k=kernel;
1709         pixel=0.0;
1710         if ((blur_traits & BlendPixelTrait) == 0)
1711           {
1712             for (j=0; j < (ssize_t) width; j++)
1713             {
1714               r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
1715                 offset[j].y,1,1,exception);
1716               if (r == (const Quantum *) NULL)
1717                 {
1718                   status=MagickFalse;
1719                   continue;
1720                 }
1721               pixel+=(*k)*r[i];
1722               k++;
1723             }
1724             SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
1725             continue;
1726           }
1727         alpha=0.0;
1728         gamma=0.0;
1729         for (j=0; j < (ssize_t) width; j++)
1730         {
1731           r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
1732             1,exception);
1733           if (r == (const Quantum *) NULL)
1734             {
1735               status=MagickFalse;
1736               continue;
1737             }
1738           alpha=(double) (QuantumScale*GetPixelAlpha(image,r));
1739           pixel+=(*k)*alpha*r[i];
1740           gamma+=(*k)*alpha;
1741           k++;
1742         }
1743         gamma=PerceptibleReciprocal(gamma);
1744         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
1745       }
1746       p+=GetPixelChannels(image);
1747       q+=GetPixelChannels(blur_image);
1748     }
1749     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1750       status=MagickFalse;
1751     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1752       {
1753         MagickBooleanType
1754           proceed;
1755
1756 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1757         #pragma omp critical (MagickCore_MotionBlurImage)
1758 #endif
1759         proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
1760         if (proceed == MagickFalse)
1761           status=MagickFalse;
1762       }
1763   }
1764   blur_view=DestroyCacheView(blur_view);
1765   motion_view=DestroyCacheView(motion_view);
1766   image_view=DestroyCacheView(image_view);
1767   kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
1768   offset=(OffsetInfo *) RelinquishMagickMemory(offset);
1769   if (status == MagickFalse)
1770     blur_image=DestroyImage(blur_image);
1771   return(blur_image);
1772 }
1773 \f
1774 /*
1775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1776 %                                                                             %
1777 %                                                                             %
1778 %                                                                             %
1779 %     P r e v i e w I m a g e                                                 %
1780 %                                                                             %
1781 %                                                                             %
1782 %                                                                             %
1783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 %
1785 %  PreviewImage() tiles 9 thumbnails of the specified image with an image
1786 %  processing operation applied with varying parameters.  This may be helpful
1787 %  pin-pointing an appropriate parameter for a particular image processing
1788 %  operation.
1789 %
1790 %  The format of the PreviewImages method is:
1791 %
1792 %      Image *PreviewImages(const Image *image,const PreviewType preview,
1793 %        ExceptionInfo *exception)
1794 %
1795 %  A description of each parameter follows:
1796 %
1797 %    o image: the image.
1798 %
1799 %    o preview: the image processing operation.
1800 %
1801 %    o exception: return any errors or warnings in this structure.
1802 %
1803 */
1804 MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
1805   ExceptionInfo *exception)
1806 {
1807 #define NumberTiles  9
1808 #define PreviewImageTag  "Preview/Image"
1809 #define DefaultPreviewGeometry  "204x204+10+10"
1810
1811   char
1812     factor[MaxTextExtent],
1813     label[MaxTextExtent];
1814
1815   double
1816     degrees,
1817     gamma,
1818     percentage,
1819     radius,
1820     sigma,
1821     threshold;
1822
1823   extern const char
1824     DefaultTileFrame[];
1825
1826   Image
1827     *images,
1828     *montage_image,
1829     *preview_image,
1830     *thumbnail;
1831
1832   ImageInfo
1833     *preview_info;
1834
1835   MagickBooleanType
1836     proceed;
1837
1838   MontageInfo
1839     *montage_info;
1840
1841   QuantizeInfo
1842     quantize_info;
1843
1844   RectangleInfo
1845     geometry;
1846
1847   register ssize_t
1848     i,
1849     x;
1850
1851   size_t
1852     colors;
1853
1854   ssize_t
1855     y;
1856
1857   /*
1858     Open output image file.
1859   */
1860   assert(image != (Image *) NULL);
1861   assert(image->signature == MagickSignature);
1862   if (image->debug != MagickFalse)
1863     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1864   colors=2;
1865   degrees=0.0;
1866   gamma=(-0.2f);
1867   preview_info=AcquireImageInfo();
1868   SetGeometry(image,&geometry);
1869   (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
1870     &geometry.width,&geometry.height);
1871   images=NewImageList();
1872   percentage=12.5;
1873   GetQuantizeInfo(&quantize_info);
1874   radius=0.0;
1875   sigma=1.0;
1876   threshold=0.0;
1877   x=0;
1878   y=0;
1879   for (i=0; i < NumberTiles; i++)
1880   {
1881     thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
1882     if (thumbnail == (Image *) NULL)
1883       break;
1884     (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
1885       (void *) NULL);
1886     (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
1887     if (i == (NumberTiles/2))
1888       {
1889         (void) QueryColorCompliance("#dfdfdf",AllCompliance,
1890           &thumbnail->matte_color,exception);
1891         AppendImageToList(&images,thumbnail);
1892         continue;
1893       }
1894     switch (preview)
1895     {
1896       case RotatePreview:
1897       {
1898         degrees+=45.0;
1899         preview_image=RotateImage(thumbnail,degrees,exception);
1900         (void) FormatLocaleString(label,MaxTextExtent,"rotate %g",degrees);
1901         break;
1902       }
1903       case ShearPreview:
1904       {
1905         degrees+=5.0;
1906         preview_image=ShearImage(thumbnail,degrees,degrees,exception);
1907         (void) FormatLocaleString(label,MaxTextExtent,"shear %gx%g",degrees,
1908           2.0*degrees);
1909         break;
1910       }
1911       case RollPreview:
1912       {
1913         x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
1914         y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
1915         preview_image=RollImage(thumbnail,x,y,exception);
1916         (void) FormatLocaleString(label,MaxTextExtent,"roll %+.20gx%+.20g",
1917           (double) x,(double) y);
1918         break;
1919       }
1920       case HuePreview:
1921       {
1922         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1923         if (preview_image == (Image *) NULL)
1924           break;
1925         (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",2.0*
1926           percentage);
1927         (void) ModulateImage(preview_image,factor,exception);
1928         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
1929         break;
1930       }
1931       case SaturationPreview:
1932       {
1933         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1934         if (preview_image == (Image *) NULL)
1935           break;
1936         (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",2.0*percentage);
1937         (void) ModulateImage(preview_image,factor,exception);
1938         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
1939         break;
1940       }
1941       case BrightnessPreview:
1942       {
1943         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1944         if (preview_image == (Image *) NULL)
1945           break;
1946         (void) FormatLocaleString(factor,MaxTextExtent,"%g",2.0*percentage);
1947         (void) ModulateImage(preview_image,factor,exception);
1948         (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
1949         break;
1950       }
1951       case GammaPreview:
1952       default:
1953       {
1954         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1955         if (preview_image == (Image *) NULL)
1956           break;
1957         gamma+=0.4f;
1958         (void) GammaImage(preview_image,gamma,exception);
1959         (void) FormatLocaleString(label,MaxTextExtent,"gamma %g",gamma);
1960         break;
1961       }
1962       case SpiffPreview:
1963       {
1964         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1965         if (preview_image != (Image *) NULL)
1966           for (x=0; x < i; x++)
1967             (void) ContrastImage(preview_image,MagickTrue,exception);
1968         (void) FormatLocaleString(label,MaxTextExtent,"contrast (%.20g)",
1969           (double) i+1);
1970         break;
1971       }
1972       case DullPreview:
1973       {
1974         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1975         if (preview_image == (Image *) NULL)
1976           break;
1977         for (x=0; x < i; x++)
1978           (void) ContrastImage(preview_image,MagickFalse,exception);
1979         (void) FormatLocaleString(label,MaxTextExtent,"+contrast (%.20g)",
1980           (double) i+1);
1981         break;
1982       }
1983       case GrayscalePreview:
1984       {
1985         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1986         if (preview_image == (Image *) NULL)
1987           break;
1988         colors<<=1;
1989         quantize_info.number_colors=colors;
1990         quantize_info.colorspace=GRAYColorspace;
1991         (void) QuantizeImage(&quantize_info,preview_image,exception);
1992         (void) FormatLocaleString(label,MaxTextExtent,
1993           "-colorspace gray -colors %.20g",(double) colors);
1994         break;
1995       }
1996       case QuantizePreview:
1997       {
1998         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
1999         if (preview_image == (Image *) NULL)
2000           break;
2001         colors<<=1;
2002         quantize_info.number_colors=colors;
2003         (void) QuantizeImage(&quantize_info,preview_image,exception);
2004         (void) FormatLocaleString(label,MaxTextExtent,"colors %.20g",(double)
2005           colors);
2006         break;
2007       }
2008       case DespecklePreview:
2009       {
2010         for (x=0; x < (i-1); x++)
2011         {
2012           preview_image=DespeckleImage(thumbnail,exception);
2013           if (preview_image == (Image *) NULL)
2014             break;
2015           thumbnail=DestroyImage(thumbnail);
2016           thumbnail=preview_image;
2017         }
2018         preview_image=DespeckleImage(thumbnail,exception);
2019         if (preview_image == (Image *) NULL)
2020           break;
2021         (void) FormatLocaleString(label,MaxTextExtent,"despeckle (%.20g)",
2022           (double) i+1);
2023         break;
2024       }
2025       case ReduceNoisePreview:
2026       {
2027         preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) radius,
2028           (size_t) radius,exception);
2029         (void) FormatLocaleString(label,MaxTextExtent,"noise %g",radius);
2030         break;
2031       }
2032       case AddNoisePreview:
2033       {
2034         switch ((int) i)
2035         {
2036           case 0:
2037           {
2038             (void) CopyMagickString(factor,"uniform",MaxTextExtent);
2039             break;
2040           }
2041           case 1:
2042           {
2043             (void) CopyMagickString(factor,"gaussian",MaxTextExtent);
2044             break;
2045           }
2046           case 2:
2047           {
2048             (void) CopyMagickString(factor,"multiplicative",MaxTextExtent);
2049             break;
2050           }
2051           case 3:
2052           {
2053             (void) CopyMagickString(factor,"impulse",MaxTextExtent);
2054             break;
2055           }
2056           case 4:
2057           {
2058             (void) CopyMagickString(factor,"laplacian",MaxTextExtent);
2059             break;
2060           }
2061           case 5:
2062           {
2063             (void) CopyMagickString(factor,"Poisson",MaxTextExtent);
2064             break;
2065           }
2066           default:
2067           {
2068             (void) CopyMagickString(thumbnail->magick,"NULL",MaxTextExtent);
2069             break;
2070           }
2071         }
2072         preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
2073           (size_t) i,exception);
2074         (void) FormatLocaleString(label,MaxTextExtent,"+noise %s",factor);
2075         break;
2076       }
2077       case SharpenPreview:
2078       {
2079         preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2080         (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",radius,
2081           sigma);
2082         break;
2083       }
2084       case BlurPreview:
2085       {
2086         preview_image=BlurImage(thumbnail,radius,sigma,exception);
2087         (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius,
2088           sigma);
2089         break;
2090       }
2091       case ThresholdPreview:
2092       {
2093         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2094         if (preview_image == (Image *) NULL)
2095           break;
2096         (void) BilevelImage(thumbnail,(double) (percentage*((double)
2097           QuantumRange+1.0))/100.0,exception);
2098         (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",(double)
2099           (percentage*((double) QuantumRange+1.0))/100.0);
2100         break;
2101       }
2102       case EdgeDetectPreview:
2103       {
2104         preview_image=EdgeImage(thumbnail,radius,sigma,exception);
2105         (void) FormatLocaleString(label,MaxTextExtent,"edge %g",radius);
2106         break;
2107       }
2108       case SpreadPreview:
2109       {
2110         preview_image=SpreadImage(thumbnail,radius,thumbnail->interpolate,
2111           exception);
2112         (void) FormatLocaleString(label,MaxTextExtent,"spread %g",radius+0.5);
2113         break;
2114       }
2115       case SolarizePreview:
2116       {
2117         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2118         if (preview_image == (Image *) NULL)
2119           break;
2120         (void) SolarizeImage(preview_image,(double) QuantumRange*percentage/
2121           100.0,exception);
2122         (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
2123           (QuantumRange*percentage)/100.0);
2124         break;
2125       }
2126       case ShadePreview:
2127       {
2128         degrees+=10.0;
2129         preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2130           exception);
2131         (void) FormatLocaleString(label,MaxTextExtent,"shade %gx%g",degrees,
2132           degrees);
2133         break;
2134       }
2135       case RaisePreview:
2136       {
2137         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2138         if (preview_image == (Image *) NULL)
2139           break;
2140         geometry.width=(size_t) (2*i+2);
2141         geometry.height=(size_t) (2*i+2);
2142         geometry.x=i/2;
2143         geometry.y=i/2;
2144         (void) RaiseImage(preview_image,&geometry,MagickTrue,exception);
2145         (void) FormatLocaleString(label,MaxTextExtent,
2146           "raise %.20gx%.20g%+.20g%+.20g",(double) geometry.width,(double)
2147           geometry.height,(double) geometry.x,(double) geometry.y);
2148         break;
2149       }
2150       case SegmentPreview:
2151       {
2152         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2153         if (preview_image == (Image *) NULL)
2154           break;
2155         threshold+=0.4f;
2156         (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2157           threshold,exception);
2158         (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
2159           threshold,threshold);
2160         break;
2161       }
2162       case SwirlPreview:
2163       {
2164         preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2165           exception);
2166         (void) FormatLocaleString(label,MaxTextExtent,"swirl %g",degrees);
2167         degrees+=45.0;
2168         break;
2169       }
2170       case ImplodePreview:
2171       {
2172         degrees+=0.1f;
2173         preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2174           exception);
2175         (void) FormatLocaleString(label,MaxTextExtent,"implode %g",degrees);
2176         break;
2177       }
2178       case WavePreview:
2179       {
2180         degrees+=5.0f;
2181         preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2182           image->interpolate,exception);
2183         (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",0.5*degrees,
2184           2.0*degrees);
2185         break;
2186       }
2187       case OilPaintPreview:
2188       {
2189         preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
2190           exception);
2191         (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",radius,
2192           sigma);
2193         break;
2194       }
2195       case CharcoalDrawingPreview:
2196       {
2197         preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
2198           exception);
2199         (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",radius,
2200           sigma);
2201         break;
2202       }
2203       case JPEGPreview:
2204       {
2205         char
2206           filename[MaxTextExtent];
2207
2208         int
2209           file;
2210
2211         MagickBooleanType
2212           status;
2213
2214         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2215         if (preview_image == (Image *) NULL)
2216           break;
2217         preview_info->quality=(size_t) percentage;
2218         (void) FormatLocaleString(factor,MaxTextExtent,"%.20g",(double)
2219           preview_info->quality);
2220         file=AcquireUniqueFileResource(filename);
2221         if (file != -1)
2222           file=close(file)-1;
2223         (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
2224           "jpeg:%s",filename);
2225         status=WriteImage(preview_info,preview_image,exception);
2226         if (status != MagickFalse)
2227           {
2228             Image
2229               *quality_image;
2230
2231             (void) CopyMagickString(preview_info->filename,
2232               preview_image->filename,MaxTextExtent);
2233             quality_image=ReadImage(preview_info,exception);
2234             if (quality_image != (Image *) NULL)
2235               {
2236                 preview_image=DestroyImage(preview_image);
2237                 preview_image=quality_image;
2238               }
2239           }
2240         (void) RelinquishUniqueFileResource(preview_image->filename);
2241         if ((GetBlobSize(preview_image)/1024) >= 1024)
2242           (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%gmb ",
2243             factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
2244             1024.0/1024.0);
2245         else
2246           if (GetBlobSize(preview_image) >= 1024)
2247             (void) FormatLocaleString(label,MaxTextExtent,
2248               "quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
2249               GetBlobSize(preview_image))/1024.0);
2250           else
2251             (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%.20gb ",
2252               factor,(double) ((MagickOffsetType) GetBlobSize(thumbnail)));
2253         break;
2254       }
2255     }
2256     thumbnail=DestroyImage(thumbnail);
2257     percentage+=12.5;
2258     radius+=0.5;
2259     sigma+=0.25;
2260     if (preview_image == (Image *) NULL)
2261       break;
2262     (void) DeleteImageProperty(preview_image,"label");
2263     (void) SetImageProperty(preview_image,"label",label,exception);
2264     AppendImageToList(&images,preview_image);
2265     proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
2266       NumberTiles);
2267     if (proceed == MagickFalse)
2268       break;
2269   }
2270   if (images == (Image *) NULL)
2271     {
2272       preview_info=DestroyImageInfo(preview_info);
2273       return((Image *) NULL);
2274     }
2275   /*
2276     Create the montage.
2277   */
2278   montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
2279   (void) CopyMagickString(montage_info->filename,image->filename,MaxTextExtent);
2280   montage_info->shadow=MagickTrue;
2281   (void) CloneString(&montage_info->tile,"3x3");
2282   (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
2283   (void) CloneString(&montage_info->frame,DefaultTileFrame);
2284   montage_image=MontageImages(images,montage_info,exception);
2285   montage_info=DestroyMontageInfo(montage_info);
2286   images=DestroyImageList(images);
2287   if (montage_image == (Image *) NULL)
2288     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2289   if (montage_image->montage != (char *) NULL)
2290     {
2291       /*
2292         Free image directory.
2293       */
2294       montage_image->montage=(char *) RelinquishMagickMemory(
2295         montage_image->montage);
2296       if (image->directory != (char *) NULL)
2297         montage_image->directory=(char *) RelinquishMagickMemory(
2298           montage_image->directory);
2299     }
2300   preview_info=DestroyImageInfo(preview_info);
2301   return(montage_image);
2302 }
2303 \f
2304 /*
2305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306 %                                                                             %
2307 %                                                                             %
2308 %                                                                             %
2309 %     R a d i a l B l u r I m a g e                                           %
2310 %                                                                             %
2311 %                                                                             %
2312 %                                                                             %
2313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2314 %
2315 %  RadialBlurImage() applies a radial blur to the image.
2316 %
2317 %  Andrew Protano contributed this effect.
2318 %
2319 %  The format of the RadialBlurImage method is:
2320 %
2321 %    Image *RadialBlurImage(const Image *image,const double angle,
2322 %      ExceptionInfo *exception)
2323 %
2324 %  A description of each parameter follows:
2325 %
2326 %    o image: the image.
2327 %
2328 %    o angle: the angle of the radial blur.
2329 %
2330 %    o blur: the blur.
2331 %
2332 %    o exception: return any errors or warnings in this structure.
2333 %
2334 */
2335 MagickExport Image *RadialBlurImage(const Image *image,const double angle,
2336   ExceptionInfo *exception)
2337 {
2338   CacheView
2339     *blur_view,
2340     *image_view,
2341     *radial_view;
2342
2343   Image
2344     *blur_image;
2345
2346   MagickBooleanType
2347     status;
2348
2349   MagickOffsetType
2350     progress;
2351
2352   double
2353     blur_radius,
2354     *cos_theta,
2355     offset,
2356     *sin_theta,
2357     theta;
2358
2359   PointInfo
2360     blur_center;
2361
2362   register ssize_t
2363     i;
2364
2365   size_t
2366     n;
2367
2368   ssize_t
2369     y;
2370
2371   /*
2372     Allocate blur image.
2373   */
2374   assert(image != (Image *) NULL);
2375   assert(image->signature == MagickSignature);
2376   if (image->debug != MagickFalse)
2377     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2378   assert(exception != (ExceptionInfo *) NULL);
2379   assert(exception->signature == MagickSignature);
2380   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
2381   if (blur_image == (Image *) NULL)
2382     return((Image *) NULL);
2383   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2384     {
2385       blur_image=DestroyImage(blur_image);
2386       return((Image *) NULL);
2387     }
2388   blur_center.x=(double) image->columns/2.0;
2389   blur_center.y=(double) image->rows/2.0;
2390   blur_radius=hypot(blur_center.x,blur_center.y);
2391   n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
2392   theta=DegreesToRadians(angle)/(double) (n-1);
2393   cos_theta=(double *) AcquireQuantumMemory((size_t) n,
2394     sizeof(*cos_theta));
2395   sin_theta=(double *) AcquireQuantumMemory((size_t) n,
2396     sizeof(*sin_theta));
2397   if ((cos_theta == (double *) NULL) ||
2398       (sin_theta == (double *) NULL))
2399     {
2400       blur_image=DestroyImage(blur_image);
2401       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2402     }
2403   offset=theta*(double) (n-1)/2.0;
2404   for (i=0; i < (ssize_t) n; i++)
2405   {
2406     cos_theta[i]=cos((double) (theta*i-offset));
2407     sin_theta[i]=sin((double) (theta*i-offset));
2408   }
2409   /*
2410     Radial blur image.
2411   */
2412   status=MagickTrue;
2413   progress=0;
2414   image_view=AcquireVirtualCacheView(image,exception);
2415   radial_view=AcquireVirtualCacheView(image,exception);
2416   blur_view=AcquireAuthenticCacheView(blur_image,exception);
2417 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2418   #pragma omp parallel for schedule(static,4) shared(progress,status) \
2419     magick_threads(image,blur_image,image->rows,1)
2420 #endif
2421   for (y=0; y < (ssize_t) image->rows; y++)
2422   {
2423     register const Quantum
2424       *restrict p;
2425
2426     register Quantum
2427       *restrict q;
2428
2429     register ssize_t
2430       x;
2431
2432     if (status == MagickFalse)
2433       continue;
2434     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2435     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2436       exception);
2437     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2438       {
2439         status=MagickFalse;
2440         continue;
2441       }
2442     for (x=0; x < (ssize_t) image->columns; x++)
2443     {
2444       double
2445         radius;
2446
2447       PointInfo
2448         center;
2449
2450       register ssize_t
2451         i;
2452
2453       size_t
2454         step;
2455
2456       center.x=(double) x-blur_center.x;
2457       center.y=(double) y-blur_center.y;
2458       radius=hypot((double) center.x,center.y);
2459       if (radius == 0)
2460         step=1;
2461       else
2462         {
2463           step=(size_t) (blur_radius/radius);
2464           if (step == 0)
2465             step=1;
2466           else
2467             if (step >= n)
2468               step=n-1;
2469         }
2470       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2471       {
2472         double
2473           gamma,
2474           pixel;
2475
2476         PixelChannel
2477           channel;
2478
2479         PixelTrait
2480           blur_traits,
2481           traits;
2482
2483         register const Quantum
2484           *restrict r;
2485
2486         register ssize_t
2487           j;
2488
2489         channel=GetPixelChannelChannel(image,i);
2490         traits=GetPixelChannelTraits(image,channel);
2491         blur_traits=GetPixelChannelTraits(blur_image,channel);
2492         if ((traits == UndefinedPixelTrait) ||
2493             (blur_traits == UndefinedPixelTrait))
2494           continue;
2495         if (((blur_traits & CopyPixelTrait) != 0) ||
2496             (GetPixelMask(image,p) != 0))
2497           {
2498             SetPixelChannel(blur_image,channel,p[i],q);
2499             continue;
2500           }
2501         gamma=0.0;
2502         pixel=0.0;
2503         if ((blur_traits & BlendPixelTrait) == 0)
2504           {
2505             for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
2506             {
2507               r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
2508                 center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
2509                 (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
2510                 1,1,exception);
2511               if (r == (const Quantum *) NULL)
2512                 {
2513                   status=MagickFalse;
2514                   continue;
2515                 }
2516               pixel+=r[i];
2517               gamma++;
2518             }
2519             gamma=PerceptibleReciprocal(gamma);
2520             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2521             continue;
2522           }
2523         for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
2524         {
2525           r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
2526             center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
2527             (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
2528             1,1,exception);
2529           if (r == (const Quantum *) NULL)
2530             {
2531               status=MagickFalse;
2532               continue;
2533             }
2534           pixel+=GetPixelAlpha(image,r)*r[i];
2535           gamma+=GetPixelAlpha(image,r);
2536         }
2537         gamma=PerceptibleReciprocal(gamma);
2538         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2539       }
2540       p+=GetPixelChannels(image);
2541       q+=GetPixelChannels(blur_image);
2542     }
2543     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2544       status=MagickFalse;
2545     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2546       {
2547         MagickBooleanType
2548           proceed;
2549
2550 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2551         #pragma omp critical (MagickCore_RadialBlurImage)
2552 #endif
2553         proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
2554         if (proceed == MagickFalse)
2555           status=MagickFalse;
2556       }
2557   }
2558   blur_view=DestroyCacheView(blur_view);
2559   radial_view=DestroyCacheView(radial_view);
2560   image_view=DestroyCacheView(image_view);
2561   cos_theta=(double *) RelinquishMagickMemory(cos_theta);
2562   sin_theta=(double *) RelinquishMagickMemory(sin_theta);
2563   if (status == MagickFalse)
2564     blur_image=DestroyImage(blur_image);
2565   return(blur_image);
2566 }
2567 \f
2568 /*
2569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570 %                                                                             %
2571 %                                                                             %
2572 %                                                                             %
2573 %     S e l e c t i v e B l u r I m a g e                                     %
2574 %                                                                             %
2575 %                                                                             %
2576 %                                                                             %
2577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578 %
2579 %  SelectiveBlurImage() selectively blur pixels within a contrast threshold.
2580 %  It is similar to the unsharpen mask that sharpens everything with contrast
2581 %  above a certain threshold.
2582 %
2583 %  The format of the SelectiveBlurImage method is:
2584 %
2585 %      Image *SelectiveBlurImage(const Image *image,const double radius,
2586 %        const double sigma,const double threshold,ExceptionInfo *exception)
2587 %
2588 %  A description of each parameter follows:
2589 %
2590 %    o image: the image.
2591 %
2592 %    o radius: the radius of the Gaussian, in pixels, not counting the center
2593 %      pixel.
2594 %
2595 %    o sigma: the standard deviation of the Gaussian, in pixels.
2596 %
2597 %    o threshold: only pixels within this contrast threshold are included
2598 %      in the blur operation.
2599 %
2600 %    o exception: return any errors or warnings in this structure.
2601 %
2602 */
2603 MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
2604   const double sigma,const double threshold,ExceptionInfo *exception)
2605 {
2606 #define SelectiveBlurImageTag  "SelectiveBlur/Image"
2607
2608   CacheView
2609     *blur_view,
2610     *image_view,
2611     *luminance_view;
2612
2613   Image
2614     *blur_image,
2615     *luminance_image;
2616
2617   MagickBooleanType
2618     status;
2619
2620   MagickOffsetType
2621     progress;
2622
2623   MagickRealType
2624     *kernel;
2625
2626   register ssize_t
2627     i;
2628
2629   size_t
2630     width;
2631
2632   ssize_t
2633     center,
2634     j,
2635     u,
2636     v,
2637     y;
2638
2639   /*
2640     Initialize blur image attributes.
2641   */
2642   assert(image != (Image *) NULL);
2643   assert(image->signature == MagickSignature);
2644   if (image->debug != MagickFalse)
2645     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2646   assert(exception != (ExceptionInfo *) NULL);
2647   assert(exception->signature == MagickSignature);
2648   width=GetOptimalKernelWidth1D(radius,sigma);
2649   kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
2650     width,width*sizeof(*kernel)));
2651   if (kernel == (MagickRealType *) NULL)
2652     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2653   j=(ssize_t) width/2;
2654   i=0;
2655   for (v=(-j); v <= j; v++)
2656   {
2657     for (u=(-j); u <= j; u++)
2658       kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
2659         MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
2660   }
2661   if (image->debug != MagickFalse)
2662     {
2663       char
2664         format[MaxTextExtent],
2665         *message;
2666
2667       register const MagickRealType
2668         *k;
2669
2670       ssize_t
2671         u,
2672         v;
2673
2674       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
2675         "  SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
2676         width);
2677       message=AcquireString("");
2678       k=kernel;
2679       for (v=0; v < (ssize_t) width; v++)
2680       {
2681         *message='\0';
2682         (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
2683         (void) ConcatenateString(&message,format);
2684         for (u=0; u < (ssize_t) width; u++)
2685         {
2686           (void) FormatLocaleString(format,MaxTextExtent,"%+f ",(double) *k++);
2687           (void) ConcatenateString(&message,format);
2688         }
2689         (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
2690       }
2691       message=DestroyString(message);
2692     }
2693   blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
2694   if (blur_image == (Image *) NULL)
2695     return((Image *) NULL);
2696   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2697     {
2698       blur_image=DestroyImage(blur_image);
2699       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2700       return((Image *) NULL);
2701     }
2702   luminance_image=CloneImage(image,0,0,MagickTrue,exception);
2703   if (luminance_image == (Image *) NULL)
2704     {
2705       blur_image=DestroyImage(blur_image);
2706       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2707       return((Image *) NULL);
2708     }
2709   status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
2710   if (status == MagickFalse)
2711     {
2712       luminance_image=DestroyImage(luminance_image);
2713       blur_image=DestroyImage(blur_image);
2714       kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2715       return((Image *) NULL);
2716     }
2717   /*
2718     Threshold blur image.
2719   */
2720   status=MagickTrue;
2721   progress=0;
2722   center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*(width/2L)+
2723     GetPixelChannels(image)*(width/2L));
2724   image_view=AcquireVirtualCacheView(image,exception);
2725   luminance_view=AcquireVirtualCacheView(luminance_image,exception);
2726   blur_view=AcquireAuthenticCacheView(blur_image,exception);
2727 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2728   #pragma omp parallel for schedule(static,4) shared(progress,status) \
2729     magick_threads(image,blur_image,image->rows,1)
2730 #endif
2731   for (y=0; y < (ssize_t) image->rows; y++)
2732   {
2733     double
2734       contrast;
2735
2736     MagickBooleanType
2737       sync;
2738
2739     register const Quantum
2740       *restrict l,
2741       *restrict p;
2742
2743     register Quantum
2744       *restrict q;
2745
2746     register ssize_t
2747       x;
2748
2749     if (status == MagickFalse)
2750       continue;
2751     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
2752       (width/2L),image->columns+width,width,exception);
2753     l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) width/2L),y-(ssize_t)
2754       (width/2L),luminance_image->columns+width,width,exception);
2755     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2756       exception);
2757     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2758       {
2759         status=MagickFalse;
2760         continue;
2761       }
2762     for (x=0; x < (ssize_t) image->columns; x++)
2763     {
2764       double
2765         intensity;
2766
2767       register ssize_t
2768         i;
2769
2770       intensity=GetPixelIntensity(image,p+center);
2771       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2772       {
2773         double
2774           alpha,
2775           gamma,
2776           pixel;
2777
2778         PixelChannel
2779           channel;
2780
2781         PixelTrait
2782           blur_traits,
2783           traits;
2784
2785         register const MagickRealType
2786           *restrict k;
2787
2788         register const Quantum
2789           *restrict luminance_pixels,
2790           *restrict pixels;
2791
2792         register ssize_t
2793           u;
2794
2795         ssize_t
2796           v;
2797
2798         channel=GetPixelChannelChannel(image,i);
2799         traits=GetPixelChannelTraits(image,channel);
2800         blur_traits=GetPixelChannelTraits(blur_image,channel);
2801         if ((traits == UndefinedPixelTrait) ||
2802             (blur_traits == UndefinedPixelTrait))
2803           continue;
2804         if (((blur_traits & CopyPixelTrait) != 0) ||
2805             (GetPixelMask(image,p+center) != 0))
2806           {
2807             SetPixelChannel(blur_image,channel,p[center+i],q);
2808             continue;
2809           }
2810         k=kernel;
2811         pixel=0.0;
2812         pixels=p;
2813         luminance_pixels=l;
2814         gamma=0.0;
2815         if ((blur_traits & BlendPixelTrait) == 0)
2816           {
2817             for (v=0; v < (ssize_t) width; v++)
2818             {
2819               for (u=0; u < (ssize_t) width; u++)
2820               {
2821                 contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
2822                   intensity;
2823                 if (fabs(contrast) < threshold)
2824                   {
2825                     pixel+=(*k)*pixels[i];
2826                     gamma+=(*k);
2827                   }
2828                 k++;
2829                 pixels+=GetPixelChannels(image);
2830                 luminance_pixels+=GetPixelChannels(luminance_image);
2831               }
2832               pixels+=image->columns*GetPixelChannels(image);
2833               luminance_pixels+=luminance_image->columns*
2834                 GetPixelChannels(luminance_image);
2835             }
2836             if (fabs((double) gamma) < MagickEpsilon)
2837               {
2838                 SetPixelChannel(blur_image,channel,p[center+i],q);
2839                 continue;
2840               }
2841             gamma=PerceptibleReciprocal(gamma);
2842             SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2843             continue;
2844           }
2845         for (v=0; v < (ssize_t) width; v++)
2846         {
2847           for (u=0; u < (ssize_t) width; u++)
2848           {
2849             contrast=GetPixelIntensity(image,pixels)-intensity;
2850             if (fabs(contrast) < threshold)
2851               {
2852                 alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
2853                 pixel+=(*k)*alpha*pixels[i];
2854                 gamma+=(*k)*alpha;
2855               }
2856             k++;
2857             pixels+=GetPixelChannels(image);
2858             luminance_pixels+=GetPixelChannels(luminance_image);
2859           }
2860           pixels+=image->columns*GetPixelChannels(image);
2861           luminance_pixels+=luminance_image->columns*
2862             GetPixelChannels(luminance_image);
2863         }
2864         if (fabs((double) gamma) < MagickEpsilon)
2865           {
2866             SetPixelChannel(blur_image,channel,p[center+i],q);
2867             continue;
2868           }
2869         gamma=PerceptibleReciprocal(gamma);
2870         SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2871       }
2872       p+=GetPixelChannels(image);
2873       l+=GetPixelChannels(luminance_image);
2874       q+=GetPixelChannels(blur_image);
2875     }
2876     sync=SyncCacheViewAuthenticPixels(blur_view,exception);
2877     if (sync == MagickFalse)
2878       status=MagickFalse;
2879     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2880       {
2881         MagickBooleanType
2882           proceed;
2883
2884 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2885         #pragma omp critical (MagickCore_SelectiveBlurImage)
2886 #endif
2887         proceed=SetImageProgress(image,SelectiveBlurImageTag,progress++,
2888           image->rows);
2889         if (proceed == MagickFalse)
2890           status=MagickFalse;
2891       }
2892   }
2893   blur_image->type=image->type;
2894   blur_view=DestroyCacheView(blur_view);
2895   image_view=DestroyCacheView(image_view);
2896   luminance_image=DestroyImage(luminance_image);
2897   kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2898   if (status == MagickFalse)
2899     blur_image=DestroyImage(blur_image);
2900   return(blur_image);
2901 }
2902 \f
2903 /*
2904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2905 %                                                                             %
2906 %                                                                             %
2907 %                                                                             %
2908 %     S h a d e I m a g e                                                     %
2909 %                                                                             %
2910 %                                                                             %
2911 %                                                                             %
2912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913 %
2914 %  ShadeImage() shines a distant light on an image to create a
2915 %  three-dimensional effect. You control the positioning of the light with
2916 %  azimuth and elevation; azimuth is measured in degrees off the x axis
2917 %  and elevation is measured in pixels above the Z axis.
2918 %
2919 %  The format of the ShadeImage method is:
2920 %
2921 %      Image *ShadeImage(const Image *image,const MagickBooleanType gray,
2922 %        const double azimuth,const double elevation,ExceptionInfo *exception)
2923 %
2924 %  A description of each parameter follows:
2925 %
2926 %    o image: the image.
2927 %
2928 %    o gray: A value other than zero shades the intensity of each pixel.
2929 %
2930 %    o azimuth, elevation:  Define the light source direction.
2931 %
2932 %    o exception: return any errors or warnings in this structure.
2933 %
2934 */
2935 MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
2936   const double azimuth,const double elevation,ExceptionInfo *exception)
2937 {
2938 #define ShadeImageTag  "Shade/Image"
2939
2940   CacheView
2941     *image_view,
2942     *shade_view;
2943
2944   Image
2945     *linear_image,
2946     *shade_image;
2947
2948   MagickBooleanType
2949     status;
2950
2951   MagickOffsetType
2952     progress;
2953
2954   PrimaryInfo
2955     light;
2956
2957   ssize_t
2958     y;
2959
2960   /*
2961     Initialize shaded image attributes.
2962   */
2963   assert(image != (const Image *) NULL);
2964   assert(image->signature == MagickSignature);
2965   if (image->debug != MagickFalse)
2966     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2967   assert(exception != (ExceptionInfo *) NULL);
2968   assert(exception->signature == MagickSignature);
2969   linear_image=CloneImage(image,0,0,MagickTrue,exception);
2970   shade_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
2971   if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
2972     {
2973       if (linear_image != (Image *) NULL)
2974         linear_image=DestroyImage(linear_image);
2975       if (shade_image != (Image *) NULL)
2976         shade_image=DestroyImage(shade_image);
2977       return((Image *) NULL);
2978     }
2979   if (image->colorspace == sRGBColorspace)
2980     (void) TransformImageColorspace(linear_image,RGBColorspace,exception);
2981   if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
2982     {
2983       linear_image=DestroyImage(linear_image);
2984       shade_image=DestroyImage(shade_image);
2985       return((Image *) NULL);
2986     }
2987   /*
2988     Compute the light vector.
2989   */
2990   light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
2991     cos(DegreesToRadians(elevation));
2992   light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
2993     cos(DegreesToRadians(elevation));
2994   light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
2995   /*
2996     Shade image.
2997   */
2998   status=MagickTrue;
2999   progress=0;
3000   image_view=AcquireVirtualCacheView(linear_image,exception);
3001   shade_view=AcquireAuthenticCacheView(shade_image,exception);
3002 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3003   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3004     magick_threads(linear_image,shade_image,linear_image->rows,1)
3005 #endif
3006   for (y=0; y < (ssize_t) linear_image->rows; y++)
3007   {
3008     double
3009       distance,
3010       normal_distance,
3011       shade;
3012
3013     PrimaryInfo
3014       normal;
3015
3016     register const Quantum
3017       *restrict center,
3018       *restrict p,
3019       *restrict post,
3020       *restrict pre;
3021
3022     register Quantum
3023       *restrict q;
3024
3025     register ssize_t
3026       x;
3027
3028     if (status == MagickFalse)
3029       continue;
3030     p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3031       exception);
3032     q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3033       exception);
3034     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3035       {
3036         status=MagickFalse;
3037         continue;
3038       }
3039     /*
3040       Shade this row of pixels.
3041     */
3042     normal.z=2.0*(double) QuantumRange;  /* constant Z of surface normal */
3043     pre=p+GetPixelChannels(linear_image);
3044     center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3045     post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3046     for (x=0; x < (ssize_t) linear_image->columns; x++)
3047     {
3048       register ssize_t
3049         i;
3050
3051       /*
3052         Determine the surface normal and compute shading.
3053       */
3054       normal.x=(double) (
3055         GetPixelIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3056         GetPixelIntensity(linear_image,center-GetPixelChannels(linear_image))+
3057         GetPixelIntensity(linear_image,post-GetPixelChannels(linear_image))-
3058         GetPixelIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3059         GetPixelIntensity(linear_image,center+GetPixelChannels(linear_image))-
3060         GetPixelIntensity(linear_image,post+GetPixelChannels(linear_image)));
3061       normal.y=(double) (
3062         GetPixelIntensity(linear_image,post-GetPixelChannels(linear_image))+
3063         GetPixelIntensity(linear_image,post)+
3064         GetPixelIntensity(linear_image,post+GetPixelChannels(linear_image))-
3065         GetPixelIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3066         GetPixelIntensity(linear_image,pre)-
3067         GetPixelIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3068       if ((normal.x == 0.0) && (normal.y == 0.0))
3069         shade=light.z;
3070       else
3071         {
3072           shade=0.0;
3073           distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3074           if (distance > MagickEpsilon)
3075             {
3076               normal_distance=normal.x*normal.x+normal.y*normal.y+
3077                 normal.z*normal.z;
3078               if (normal_distance > (MagickEpsilon*MagickEpsilon))
3079                 shade=distance/sqrt((double) normal_distance);
3080             }
3081         }
3082       for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3083       {
3084         PixelChannel
3085           channel;
3086
3087         PixelTrait
3088           shade_traits,
3089           traits;
3090
3091         channel=GetPixelChannelChannel(linear_image,i);
3092         traits=GetPixelChannelTraits(linear_image,channel);
3093         shade_traits=GetPixelChannelTraits(shade_image,channel);
3094         if ((traits == UndefinedPixelTrait) ||
3095             (shade_traits == UndefinedPixelTrait))
3096           continue;
3097         if (((shade_traits & CopyPixelTrait) != 0) ||
3098             (GetPixelMask(linear_image,center) != 0))
3099           {
3100             SetPixelChannel(shade_image,channel,center[i],q);
3101             continue;
3102           }
3103         if (gray != MagickFalse)
3104           {
3105             SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3106             continue;
3107           }
3108         SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
3109           center[i]),q);
3110       }
3111       pre+=GetPixelChannels(linear_image);
3112       center+=GetPixelChannels(linear_image);
3113       post+=GetPixelChannels(linear_image);
3114       q+=GetPixelChannels(shade_image);
3115     }
3116     if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3117       status=MagickFalse;
3118     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3119       {
3120         MagickBooleanType
3121           proceed;
3122
3123 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3124         #pragma omp critical (MagickCore_ShadeImage)
3125 #endif
3126         proceed=SetImageProgress(image,ShadeImageTag,progress++,image->rows);
3127         if (proceed == MagickFalse)
3128           status=MagickFalse;
3129       }
3130   }
3131   shade_view=DestroyCacheView(shade_view);
3132   image_view=DestroyCacheView(image_view);
3133   linear_image=DestroyImage(linear_image);
3134   if (image->colorspace == sRGBColorspace)
3135     (void) TransformImageColorspace(shade_image,sRGBColorspace,exception);
3136   if (status == MagickFalse)
3137     shade_image=DestroyImage(shade_image);
3138   return(shade_image);
3139 }
3140 \f
3141 /*
3142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3143 %                                                                             %
3144 %                                                                             %
3145 %                                                                             %
3146 %     S h a r p e n I m a g e                                                 %
3147 %                                                                             %
3148 %                                                                             %
3149 %                                                                             %
3150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3151 %
3152 %  SharpenImage() sharpens the image.  We convolve the image with a Gaussian
3153 %  operator of the given radius and standard deviation (sigma).  For
3154 %  reasonable results, radius should be larger than sigma.  Use a radius of 0
3155 %  and SharpenImage() selects a suitable radius for you.
3156 %
3157 %  Using a separable kernel would be faster, but the negative weights cancel
3158 %  out on the corners of the kernel producing often undesirable ringing in the
3159 %  filtered result; this can be avoided by using a 2D gaussian shaped image
3160 %  sharpening kernel instead.
3161 %
3162 %  The format of the SharpenImage method is:
3163 %
3164 %    Image *SharpenImage(const Image *image,const double radius,
3165 %      const double sigma,ExceptionInfo *exception)
3166 %
3167 %  A description of each parameter follows:
3168 %
3169 %    o image: the image.
3170 %
3171 %    o radius: the radius of the Gaussian, in pixels, not counting the center
3172 %      pixel.
3173 %
3174 %    o sigma: the standard deviation of the Laplacian, in pixels.
3175 %
3176 %    o exception: return any errors or warnings in this structure.
3177 %
3178 */
3179 MagickExport Image *SharpenImage(const Image *image,const double radius,
3180   const double sigma,ExceptionInfo *exception)
3181 {
3182   double
3183     normalize;
3184
3185   Image
3186     *sharp_image;
3187
3188   KernelInfo
3189     *kernel_info;
3190
3191   register ssize_t
3192     i;
3193
3194   size_t
3195     width;
3196
3197   ssize_t
3198     j,
3199     u,
3200     v;
3201
3202   assert(image != (const Image *) NULL);
3203   assert(image->signature == MagickSignature);
3204   if (image->debug != MagickFalse)
3205     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3206   assert(exception != (ExceptionInfo *) NULL);
3207   assert(exception->signature == MagickSignature);
3208   width=GetOptimalKernelWidth2D(radius,sigma);
3209   kernel_info=AcquireKernelInfo((const char *) NULL);
3210   if (kernel_info == (KernelInfo *) NULL)
3211     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3212   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
3213   kernel_info->width=width;
3214   kernel_info->height=width;
3215   kernel_info->x=(ssize_t) width/2;
3216   kernel_info->y=(ssize_t) width/2;
3217   kernel_info->signature=MagickSignature;
3218   kernel_info->values=(MagickRealType *) MagickAssumeAligned(
3219     AcquireAlignedMemory(kernel_info->width,kernel_info->width*
3220     sizeof(*kernel_info->values)));
3221   if (kernel_info->values == (MagickRealType *) NULL)
3222     {
3223       kernel_info=DestroyKernelInfo(kernel_info);
3224       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3225     }
3226   normalize=0.0;
3227   j=(ssize_t) kernel_info->width/2;
3228   i=0;
3229   for (v=(-j); v <= j; v++)
3230   {
3231     for (u=(-j); u <= j; u++)
3232     {
3233       kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
3234         MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3235       normalize+=kernel_info->values[i];
3236       i++;
3237     }
3238   }
3239   kernel_info->values[i/2]=(double) ((-2.0)*normalize);
3240   sharp_image=ConvolveImage(image,kernel_info,exception);
3241   kernel_info=DestroyKernelInfo(kernel_info);
3242   return(sharp_image);
3243 }
3244 \f
3245 /*
3246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3247 %                                                                             %
3248 %                                                                             %
3249 %                                                                             %
3250 %     S p r e a d I m a g e                                                   %
3251 %                                                                             %
3252 %                                                                             %
3253 %                                                                             %
3254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3255 %
3256 %  SpreadImage() is a special effects method that randomly displaces each
3257 %  pixel in a block defined by the radius parameter.
3258 %
3259 %  The format of the SpreadImage method is:
3260 %
3261 %      Image *SpreadImage(const Image *image,const double radius,
3262 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
3263 %
3264 %  A description of each parameter follows:
3265 %
3266 %    o image: the image.
3267 %
3268 %    o radius:  choose a random pixel in a neighborhood of this extent.
3269 %
3270 %    o method:  the pixel interpolation method.
3271 %
3272 %    o exception: return any errors or warnings in this structure.
3273 %
3274 */
3275 MagickExport Image *SpreadImage(const Image *image,const double radius,
3276   const PixelInterpolateMethod method,ExceptionInfo *exception)
3277 {
3278 #define SpreadImageTag  "Spread/Image"
3279
3280   CacheView
3281     *image_view,
3282     *spread_view;
3283
3284   Image
3285     *spread_image;
3286
3287   MagickBooleanType
3288     status;
3289
3290   MagickOffsetType
3291     progress;
3292
3293   RandomInfo
3294     **restrict random_info;
3295
3296   size_t
3297     width;
3298
3299   ssize_t
3300     y;
3301
3302 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3303   unsigned long
3304     key;
3305 #endif
3306
3307   /*
3308     Initialize spread image attributes.
3309   */
3310   assert(image != (Image *) NULL);
3311   assert(image->signature == MagickSignature);
3312   if (image->debug != MagickFalse)
3313     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3314   assert(exception != (ExceptionInfo *) NULL);
3315   assert(exception->signature == MagickSignature);
3316   spread_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3317     exception);
3318   if (spread_image == (Image *) NULL)
3319     return((Image *) NULL);
3320   if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
3321     {
3322       spread_image=DestroyImage(spread_image);
3323       return((Image *) NULL);
3324     }
3325   /*
3326     Spread image.
3327   */
3328   status=MagickTrue;
3329   progress=0;
3330   width=GetOptimalKernelWidth1D(radius,0.5);
3331   random_info=AcquireRandomInfoThreadSet();
3332   image_view=AcquireVirtualCacheView(image,exception);
3333   spread_view=AcquireAuthenticCacheView(spread_image,exception);
3334 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3335   key=GetRandomSecretKey(random_info[0]);
3336   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3337     magick_threads(image,spread_image,image->rows,key == ~0UL)
3338 #endif
3339   for (y=0; y < (ssize_t) image->rows; y++)
3340   {
3341     const int
3342       id = GetOpenMPThreadId();
3343
3344     register const Quantum
3345       *restrict p;
3346
3347     register Quantum
3348       *restrict q;
3349
3350     register ssize_t
3351       x;
3352
3353     if (status == MagickFalse)
3354       continue;
3355     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3356     q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
3357       exception);
3358     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3359       {
3360         status=MagickFalse;
3361         continue;
3362       }
3363     for (x=0; x < (ssize_t) image->columns; x++)
3364     {
3365       PointInfo
3366         point;
3367
3368       point.x=GetPseudoRandomValue(random_info[id]);
3369       point.y=GetPseudoRandomValue(random_info[id]);
3370       status=InterpolatePixelChannels(image,image_view,spread_image,method,
3371         (double) x+width*point.x-0.5,(double) y+width*point.y-0.5,q,exception);
3372       q+=GetPixelChannels(spread_image);
3373     }
3374     if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
3375       status=MagickFalse;
3376     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3377       {
3378         MagickBooleanType
3379           proceed;
3380
3381 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3382         #pragma omp critical (MagickCore_SpreadImage)
3383 #endif
3384         proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
3385         if (proceed == MagickFalse)
3386           status=MagickFalse;
3387       }
3388   }
3389   spread_view=DestroyCacheView(spread_view);
3390   image_view=DestroyCacheView(image_view);
3391   random_info=DestroyRandomInfoThreadSet(random_info);
3392   if (status == MagickFalse)
3393     spread_image=DestroyImage(spread_image);
3394   return(spread_image);
3395 }
3396 \f
3397 /*
3398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3399 %                                                                             %
3400 %                                                                             %
3401 %                                                                             %
3402 %     U n s h a r p M a s k I m a g e                                         %
3403 %                                                                             %
3404 %                                                                             %
3405 %                                                                             %
3406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3407 %
3408 %  UnsharpMaskImage() sharpens one or more image channels.  We convolve the
3409 %  image with a Gaussian operator of the given radius and standard deviation
3410 %  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
3411 %  radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
3412 %
3413 %  The format of the UnsharpMaskImage method is:
3414 %
3415 %    Image *UnsharpMaskImage(const Image *image,const double radius,
3416 %      const double sigma,const double amount,const double threshold,
3417 %      ExceptionInfo *exception)
3418 %
3419 %  A description of each parameter follows:
3420 %
3421 %    o image: the image.
3422 %
3423 %    o radius: the radius of the Gaussian, in pixels, not counting the center
3424 %      pixel.
3425 %
3426 %    o sigma: the standard deviation of the Gaussian, in pixels.
3427 %
3428 %    o amount: the percentage of the difference between the original and the
3429 %      blur image that is added back into the original.
3430 %
3431 %    o threshold: the threshold in pixels needed to apply the diffence amount.
3432 %
3433 %    o exception: return any errors or warnings in this structure.
3434 %
3435 */
3436 MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
3437   const double sigma,const double amount,const double threshold,
3438   ExceptionInfo *exception)
3439 {
3440 #define SharpenImageTag  "Sharpen/Image"
3441
3442   CacheView
3443     *image_view,
3444     *unsharp_view;
3445
3446   Image
3447     *unsharp_image;
3448
3449   MagickBooleanType
3450     status;
3451
3452   MagickOffsetType
3453     progress;
3454
3455   double
3456     quantum_threshold;
3457
3458   ssize_t
3459     y;
3460
3461   assert(image != (const Image *) NULL);
3462   assert(image->signature == MagickSignature);
3463   if (image->debug != MagickFalse)
3464     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3465   assert(exception != (ExceptionInfo *) NULL);
3466   unsharp_image=BlurImage(image,radius,sigma,exception);
3467   if (unsharp_image == (Image *) NULL)
3468     return((Image *) NULL);
3469   quantum_threshold=(double) QuantumRange*threshold;
3470   /*
3471     Unsharp-mask image.
3472   */
3473   status=MagickTrue;
3474   progress=0;
3475   image_view=AcquireVirtualCacheView(image,exception);
3476   unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
3477 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3478   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3479     magick_threads(image,unsharp_image,image->rows,1)
3480 #endif
3481   for (y=0; y < (ssize_t) image->rows; y++)
3482   {
3483     register const Quantum
3484       *restrict p;
3485
3486     register Quantum
3487       *restrict q;
3488
3489     register ssize_t
3490       x;
3491
3492     if (status == MagickFalse)
3493       continue;
3494     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3495     q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
3496       exception);
3497     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3498       {
3499         status=MagickFalse;
3500         continue;
3501       }
3502     for (x=0; x < (ssize_t) image->columns; x++)
3503     {
3504       register ssize_t
3505         i;
3506
3507       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3508       {
3509         double
3510           pixel;
3511
3512         PixelChannel
3513           channel;
3514
3515         PixelTrait
3516           traits,
3517           unsharp_traits;
3518
3519         channel=GetPixelChannelChannel(image,i);
3520         traits=GetPixelChannelTraits(image,channel);
3521         unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
3522         if ((traits == UndefinedPixelTrait) ||
3523             (unsharp_traits == UndefinedPixelTrait))
3524           continue;
3525         if (((unsharp_traits & CopyPixelTrait) != 0) ||
3526             (GetPixelMask(image,p) != 0))
3527           {
3528             SetPixelChannel(unsharp_image,channel,p[i],q);
3529             continue;
3530           }
3531         pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
3532         if (fabs(2.0*pixel) < quantum_threshold)
3533           pixel=(double) p[i];
3534         else
3535           pixel=(double) p[i]+amount*pixel;
3536         SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
3537       }
3538       p+=GetPixelChannels(image);
3539       q+=GetPixelChannels(unsharp_image);
3540     }
3541     if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
3542       status=MagickFalse;
3543     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3544       {
3545         MagickBooleanType
3546           proceed;
3547
3548 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3549         #pragma omp critical (MagickCore_UnsharpMaskImage)
3550 #endif
3551         proceed=SetImageProgress(image,SharpenImageTag,progress++,image->rows);
3552         if (proceed == MagickFalse)
3553           status=MagickFalse;
3554       }
3555   }
3556   unsharp_image->type=image->type;
3557   unsharp_view=DestroyCacheView(unsharp_view);
3558   image_view=DestroyCacheView(image_view);
3559   if (status == MagickFalse)
3560     unsharp_image=DestroyImage(unsharp_image);
3561   return(unsharp_image);
3562 }