MagickCore  7.1.0
effect.c
Go to the documentation of this file.
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 % Cristy %
17 % October 1996 %
18 % %
19 % %
20 % Copyright 1999-2021 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 % https://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 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.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"
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"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/matrix.h"
66 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
70 #include "MagickCore/montage.h"
71 #include "MagickCore/morphology.h"
73 #include "MagickCore/paint.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantize.h"
78 #include "MagickCore/quantum.h"
80 #include "MagickCore/random_.h"
82 #include "MagickCore/resample.h"
84 #include "MagickCore/resize.h"
85 #include "MagickCore/resource_.h"
86 #include "MagickCore/segment.h"
87 #include "MagickCore/shear.h"
89 #include "MagickCore/statistic.h"
90 #include "MagickCore/string_.h"
92 #include "MagickCore/transform.h"
93 #include "MagickCore/threshold.h"
94 
95 /*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 % %
98 % %
99 % %
100 % A d a p t i v e B l u r I m a g e %
101 % %
102 % %
103 % %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 % AdaptiveBlurImage() adaptively blurs the image by blurring less
107 % intensely near image edges and more intensely far from edges. We blur the
108 % image with a Gaussian operator of the given radius and standard deviation
109 % (sigma). For reasonable results, radius should be larger than sigma. Use a
110 % radius of 0 and AdaptiveBlurImage() selects a suitable radius for you.
111 %
112 % The format of the AdaptiveBlurImage method is:
113 %
114 % Image *AdaptiveBlurImage(const Image *image,const double radius,
115 % const double sigma,ExceptionInfo *exception)
116 %
117 % A description of each parameter follows:
118 %
119 % o image: the image.
120 %
121 % o radius: the radius of the Gaussian, in pixels, not counting the center
122 % pixel.
123 %
124 % o sigma: the standard deviation of the Laplacian, in pixels.
125 %
126 % o exception: return any errors or warnings in this structure.
127 %
128 */
129 MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
130  const double sigma,ExceptionInfo *exception)
131 {
132 #define AdaptiveBlurImageTag "Convolve/Image"
133 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
134 
135  CacheView
136  *blur_view,
137  *edge_view,
138  *image_view;
139 
140  double
141  normalize,
142  **kernel;
143 
144  Image
145  *blur_image,
146  *edge_image,
147  *gaussian_image;
148 
150  status;
151 
153  progress;
154 
155  size_t
156  width;
157 
158  ssize_t
159  w,
160  y;
161 
162  assert(image != (const Image *) NULL);
163  assert(image->signature == MagickCoreSignature);
164  if (image->debug != MagickFalse)
165  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
166  assert(exception != (ExceptionInfo *) NULL);
167  assert(exception->signature == MagickCoreSignature);
168  blur_image=CloneImage(image,0,0,MagickTrue,exception);
169  if (blur_image == (Image *) NULL)
170  return((Image *) NULL);
171  if (fabs(sigma) < MagickEpsilon)
172  return(blur_image);
173  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
174  {
175  blur_image=DestroyImage(blur_image);
176  return((Image *) NULL);
177  }
178  /*
179  Edge detect the image brightness channel, level, blur, and level again.
180  */
181  edge_image=EdgeImage(image,radius,exception);
182  if (edge_image == (Image *) NULL)
183  {
184  blur_image=DestroyImage(blur_image);
185  return((Image *) NULL);
186  }
187  (void) AutoLevelImage(edge_image,exception);
188  gaussian_image=BlurImage(edge_image,radius,sigma,exception);
189  if (gaussian_image != (Image *) NULL)
190  {
191  edge_image=DestroyImage(edge_image);
192  edge_image=gaussian_image;
193  }
194  (void) AutoLevelImage(edge_image,exception);
195  /*
196  Create a set of kernels from maximum (radius,sigma) to minimum.
197  */
198  width=GetOptimalKernelWidth2D(radius,sigma);
199  kernel=(double **) MagickAssumeAligned(AcquireAlignedMemory((size_t) width,
200  sizeof(*kernel)));
201  if (kernel == (double **) NULL)
202  {
203  edge_image=DestroyImage(edge_image);
204  blur_image=DestroyImage(blur_image);
205  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
206  }
207  (void) memset(kernel,0,(size_t) width*sizeof(*kernel));
208  for (w=0; w < (ssize_t) width; w+=2)
209  {
210  ssize_t
211  j,
212  k,
213  u,
214  v;
215 
216  kernel[w]=(double *) MagickAssumeAligned(AcquireAlignedMemory(
217  (size_t) (width-w),(width-w)*sizeof(**kernel)));
218  if (kernel[w] == (double *) NULL)
219  break;
220  normalize=0.0;
221  j=(ssize_t) (width-w-1)/2;
222  k=0;
223  for (v=(-j); v <= j; v++)
224  {
225  for (u=(-j); u <= j; u++)
226  {
227  kernel[w][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
229  normalize+=kernel[w][k];
230  k++;
231  }
232  }
233  kernel[w][(k-1)/2]+=(double) (1.0-normalize);
234  if (sigma < MagickEpsilon)
235  kernel[w][(k-1)/2]=1.0;
236  }
237  if (w < (ssize_t) width)
238  {
239  for (w-=2; w >= 0; w-=2)
240  kernel[w]=(double *) RelinquishAlignedMemory(kernel[w]);
241  kernel=(double **) RelinquishAlignedMemory(kernel);
242  edge_image=DestroyImage(edge_image);
243  blur_image=DestroyImage(blur_image);
244  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
245  }
246  /*
247  Adaptively blur image.
248  */
249  status=MagickTrue;
250  progress=0;
251  image_view=AcquireVirtualCacheView(image,exception);
252  edge_view=AcquireVirtualCacheView(edge_image,exception);
253  blur_view=AcquireAuthenticCacheView(blur_image,exception);
254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
255  #pragma omp parallel for schedule(static) shared(progress,status) \
256  magick_number_threads(image,blur_image,blur_image->rows,1)
257 #endif
258  for (y=0; y < (ssize_t) blur_image->rows; y++)
259  {
260  const Quantum
261  *magick_restrict r;
262 
263  Quantum
264  *magick_restrict q;
265 
266  ssize_t
267  x;
268 
269  if (status == MagickFalse)
270  continue;
271  r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
272  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
273  exception);
274  if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
275  {
276  status=MagickFalse;
277  continue;
278  }
279  for (x=0; x < (ssize_t) blur_image->columns; x++)
280  {
281  const Quantum
282  *magick_restrict p;
283 
284  ssize_t
285  i;
286 
287  ssize_t
288  center,
289  j;
290 
291  j=CastDoubleToLong(ceil((double) width*(1.0-QuantumScale*
292  GetPixelIntensity(edge_image,r))-0.5));
293  if (j < 0)
294  j=0;
295  else
296  if (j > (ssize_t) width)
297  j=(ssize_t) width;
298  if ((j & 0x01) != 0)
299  j--;
300  p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
301  (ssize_t) ((width-j)/2L),width-j,width-j,exception);
302  if (p == (const Quantum *) NULL)
303  break;
304  center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
305  GetPixelChannels(image)*((width-j)/2);
306  for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
307  {
308  double
309  alpha,
310  gamma,
311  pixel;
312 
314  channel;
315 
316  PixelTrait
317  blur_traits,
318  traits;
319 
320  const double
321  *magick_restrict k;
322 
323  const Quantum
324  *magick_restrict pixels;
325 
326  ssize_t
327  u;
328 
329  ssize_t
330  v;
331 
332  channel=GetPixelChannelChannel(image,i);
333  traits=GetPixelChannelTraits(image,channel);
334  blur_traits=GetPixelChannelTraits(blur_image,channel);
335  if ((traits == UndefinedPixelTrait) ||
336  (blur_traits == UndefinedPixelTrait))
337  continue;
338  if ((blur_traits & CopyPixelTrait) != 0)
339  {
340  SetPixelChannel(blur_image,channel,p[center+i],q);
341  continue;
342  }
343  k=kernel[j];
344  pixels=p;
345  pixel=0.0;
346  gamma=0.0;
347  if ((blur_traits & BlendPixelTrait) == 0)
348  {
349  /*
350  No alpha blending.
351  */
352  for (v=0; v < (ssize_t) (width-j); v++)
353  {
354  for (u=0; u < (ssize_t) (width-j); u++)
355  {
356  pixel+=(*k)*pixels[i];
357  gamma+=(*k);
358  k++;
359  pixels+=GetPixelChannels(image);
360  }
361  }
362  gamma=PerceptibleReciprocal(gamma);
363  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
364  continue;
365  }
366  /*
367  Alpha blending.
368  */
369  for (v=0; v < (ssize_t) (width-j); v++)
370  {
371  for (u=0; u < (ssize_t) (width-j); u++)
372  {
373  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
374  pixel+=(*k)*alpha*pixels[i];
375  gamma+=(*k)*alpha;
376  k++;
377  pixels+=GetPixelChannels(image);
378  }
379  }
380  gamma=PerceptibleReciprocal(gamma);
381  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
382  }
383  q+=GetPixelChannels(blur_image);
384  r+=GetPixelChannels(edge_image);
385  }
386  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
387  status=MagickFalse;
388  if (image->progress_monitor != (MagickProgressMonitor) NULL)
389  {
391  proceed;
392 
393 #if defined(MAGICKCORE_OPENMP_SUPPORT)
394  #pragma omp atomic
395 #endif
396  progress++;
397  proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
398  image->rows);
399  if (proceed == MagickFalse)
400  status=MagickFalse;
401  }
402  }
403  blur_image->type=image->type;
404  blur_view=DestroyCacheView(blur_view);
405  edge_view=DestroyCacheView(edge_view);
406  image_view=DestroyCacheView(image_view);
407  edge_image=DestroyImage(edge_image);
408  for (w=0; w < (ssize_t) width; w+=2)
409  kernel[w]=(double *) RelinquishAlignedMemory(kernel[w]);
410  kernel=(double **) RelinquishAlignedMemory(kernel);
411  if (status == MagickFalse)
412  blur_image=DestroyImage(blur_image);
413  return(blur_image);
414 }
415 
416 /*
417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 % %
419 % %
420 % %
421 % A d a p t i v e S h a r p e n I m a g e %
422 % %
423 % %
424 % %
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 %
427 % AdaptiveSharpenImage() adaptively sharpens the image by sharpening more
428 % intensely near image edges and less intensely far from edges. We sharpen the
429 % image with a Gaussian operator of the given radius and standard deviation
430 % (sigma). For reasonable results, radius should be larger than sigma. Use a
431 % radius of 0 and AdaptiveSharpenImage() selects a suitable radius for you.
432 %
433 % The format of the AdaptiveSharpenImage method is:
434 %
435 % Image *AdaptiveSharpenImage(const Image *image,const double radius,
436 % const double sigma,ExceptionInfo *exception)
437 %
438 % A description of each parameter follows:
439 %
440 % o image: the image.
441 %
442 % o radius: the radius of the Gaussian, in pixels, not counting the center
443 % pixel.
444 %
445 % o sigma: the standard deviation of the Laplacian, in pixels.
446 %
447 % o exception: return any errors or warnings in this structure.
448 %
449 */
450 MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
451  const double sigma,ExceptionInfo *exception)
452 {
453 #define AdaptiveSharpenImageTag "Convolve/Image"
454 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
455 
456  CacheView
457  *sharp_view,
458  *edge_view,
459  *image_view;
460 
461  double
462  normalize,
463  **kernel;
464 
465  Image
466  *sharp_image,
467  *edge_image,
468  *gaussian_image;
469 
471  status;
472 
474  progress;
475 
476  size_t
477  width;
478 
479  ssize_t
480  w,
481  y;
482 
483  assert(image != (const Image *) NULL);
484  assert(image->signature == MagickCoreSignature);
485  if (image->debug != MagickFalse)
486  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
487  assert(exception != (ExceptionInfo *) NULL);
488  assert(exception->signature == MagickCoreSignature);
489  sharp_image=CloneImage(image,0,0,MagickTrue,exception);
490  if (sharp_image == (Image *) NULL)
491  return((Image *) NULL);
492  if (fabs(sigma) < MagickEpsilon)
493  return(sharp_image);
494  if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
495  {
496  sharp_image=DestroyImage(sharp_image);
497  return((Image *) NULL);
498  }
499  /*
500  Edge detect the image brightness channel, level, sharp, and level again.
501  */
502  edge_image=EdgeImage(image,radius,exception);
503  if (edge_image == (Image *) NULL)
504  {
505  sharp_image=DestroyImage(sharp_image);
506  return((Image *) NULL);
507  }
508  (void) AutoLevelImage(edge_image,exception);
509  gaussian_image=BlurImage(edge_image,radius,sigma,exception);
510  if (gaussian_image != (Image *) NULL)
511  {
512  edge_image=DestroyImage(edge_image);
513  edge_image=gaussian_image;
514  }
515  (void) AutoLevelImage(edge_image,exception);
516  /*
517  Create a set of kernels from maximum (radius,sigma) to minimum.
518  */
519  width=GetOptimalKernelWidth2D(radius,sigma);
520  kernel=(double **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
521  width,sizeof(*kernel)));
522  if (kernel == (double **) NULL)
523  {
524  edge_image=DestroyImage(edge_image);
525  sharp_image=DestroyImage(sharp_image);
526  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
527  }
528  (void) memset(kernel,0,(size_t) width*sizeof(*kernel));
529  for (w=0; w < (ssize_t) width; w+=2)
530  {
531  ssize_t
532  j,
533  k,
534  u,
535  v;
536 
537  kernel[w]=(double *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
538  (width-w),(width-w)*sizeof(**kernel)));
539  if (kernel[w] == (double *) NULL)
540  break;
541  normalize=0.0;
542  j=(ssize_t) (width-w-1)/2;
543  k=0;
544  for (v=(-j); v <= j; v++)
545  {
546  for (u=(-j); u <= j; u++)
547  {
548  kernel[w][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
550  normalize+=kernel[w][k];
551  k++;
552  }
553  }
554  kernel[w][(k-1)/2]=(double) ((-2.0)*normalize);
555  if (sigma < MagickEpsilon)
556  kernel[w][(k-1)/2]=1.0;
557  }
558  if (w < (ssize_t) width)
559  {
560  for (w-=2; w >= 0; w-=2)
561  kernel[w]=(double *) RelinquishAlignedMemory(kernel[w]);
562  kernel=(double **) RelinquishAlignedMemory(kernel);
563  edge_image=DestroyImage(edge_image);
564  sharp_image=DestroyImage(sharp_image);
565  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
566  }
567  /*
568  Adaptively sharpen image.
569  */
570  status=MagickTrue;
571  progress=0;
572  image_view=AcquireVirtualCacheView(image,exception);
573  edge_view=AcquireVirtualCacheView(edge_image,exception);
574  sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
575 #if defined(MAGICKCORE_OPENMP_SUPPORT)
576  #pragma omp parallel for schedule(static) shared(progress,status) \
577  magick_number_threads(image,sharp_image,sharp_image->rows,1)
578 #endif
579  for (y=0; y < (ssize_t) sharp_image->rows; y++)
580  {
581  const Quantum
582  *magick_restrict r;
583 
584  Quantum
585  *magick_restrict q;
586 
587  ssize_t
588  x;
589 
590  if (status == MagickFalse)
591  continue;
592  r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
593  q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
594  exception);
595  if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
596  {
597  status=MagickFalse;
598  continue;
599  }
600  for (x=0; x < (ssize_t) sharp_image->columns; x++)
601  {
602  const Quantum
603  *magick_restrict p;
604 
605  ssize_t
606  i;
607 
608  ssize_t
609  center,
610  j;
611 
612  j=CastDoubleToLong(ceil((double) width*(1.0-QuantumScale*
613  GetPixelIntensity(edge_image,r))-0.5));
614  if (j < 0)
615  j=0;
616  else
617  if (j > (ssize_t) width)
618  j=(ssize_t) width;
619  if ((j & 0x01) != 0)
620  j--;
621  p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
622  (ssize_t) ((width-j)/2L),width-j,width-j,exception);
623  if (p == (const Quantum *) NULL)
624  break;
625  center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
626  GetPixelChannels(image)*((width-j)/2);
627  for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
628  {
629  double
630  alpha,
631  gamma,
632  pixel;
633 
635  channel;
636 
637  PixelTrait
638  sharp_traits,
639  traits;
640 
641  const double
642  *magick_restrict k;
643 
644  const Quantum
645  *magick_restrict pixels;
646 
647  ssize_t
648  u;
649 
650  ssize_t
651  v;
652 
653  channel=GetPixelChannelChannel(image,i);
654  traits=GetPixelChannelTraits(image,channel);
655  sharp_traits=GetPixelChannelTraits(sharp_image,channel);
656  if ((traits == UndefinedPixelTrait) ||
657  (sharp_traits == UndefinedPixelTrait))
658  continue;
659  if ((sharp_traits & CopyPixelTrait) != 0)
660  {
661  SetPixelChannel(sharp_image,channel,p[center+i],q);
662  continue;
663  }
664  k=kernel[j];
665  pixels=p;
666  pixel=0.0;
667  gamma=0.0;
668  if ((sharp_traits & BlendPixelTrait) == 0)
669  {
670  /*
671  No alpha blending.
672  */
673  for (v=0; v < (ssize_t) (width-j); v++)
674  {
675  for (u=0; u < (ssize_t) (width-j); u++)
676  {
677  pixel+=(*k)*pixels[i];
678  gamma+=(*k);
679  k++;
680  pixels+=GetPixelChannels(image);
681  }
682  }
683  gamma=PerceptibleReciprocal(gamma);
684  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
685  continue;
686  }
687  /*
688  Alpha blending.
689  */
690  for (v=0; v < (ssize_t) (width-j); v++)
691  {
692  for (u=0; u < (ssize_t) (width-j); u++)
693  {
694  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
695  pixel+=(*k)*alpha*pixels[i];
696  gamma+=(*k)*alpha;
697  k++;
698  pixels+=GetPixelChannels(image);
699  }
700  }
701  gamma=PerceptibleReciprocal(gamma);
702  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
703  }
704  q+=GetPixelChannels(sharp_image);
705  r+=GetPixelChannels(edge_image);
706  }
707  if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
708  status=MagickFalse;
709  if (image->progress_monitor != (MagickProgressMonitor) NULL)
710  {
712  proceed;
713 
714 #if defined(MAGICKCORE_OPENMP_SUPPORT)
715  #pragma omp atomic
716 #endif
717  progress++;
718  proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
719  image->rows);
720  if (proceed == MagickFalse)
721  status=MagickFalse;
722  }
723  }
724  sharp_image->type=image->type;
725  sharp_view=DestroyCacheView(sharp_view);
726  edge_view=DestroyCacheView(edge_view);
727  image_view=DestroyCacheView(image_view);
728  edge_image=DestroyImage(edge_image);
729  for (w=0; w < (ssize_t) width; w+=2)
730  kernel[w]=(double *) RelinquishAlignedMemory(kernel[w]);
731  kernel=(double **) RelinquishAlignedMemory(kernel);
732  if (status == MagickFalse)
733  sharp_image=DestroyImage(sharp_image);
734  return(sharp_image);
735 }
736 
737 /*
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739 % %
740 % %
741 % %
742 % B l u r I m a g e %
743 % %
744 % %
745 % %
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 %
748 % BlurImage() blurs an image. We convolve the image with a Gaussian operator
749 % of the given radius and standard deviation (sigma). For reasonable results,
750 % the radius should be larger than sigma. Use a radius of 0 and BlurImage()
751 % selects a suitable radius for you.
752 %
753 % The format of the BlurImage method is:
754 %
755 % Image *BlurImage(const Image *image,const double radius,
756 % const double sigma,ExceptionInfo *exception)
757 %
758 % A description of each parameter follows:
759 %
760 % o image: the image.
761 %
762 % o radius: the radius of the Gaussian, in pixels, not counting the center
763 % pixel.
764 %
765 % o sigma: the standard deviation of the Gaussian, in pixels.
766 %
767 % o exception: return any errors or warnings in this structure.
768 %
769 */
770 MagickExport Image *BlurImage(const Image *image,const double radius,
771  const double sigma,ExceptionInfo *exception)
772 {
773  char
774  geometry[MagickPathExtent];
775 
776  KernelInfo
777  *kernel_info;
778 
779  Image
780  *blur_image;
781 
782  assert(image != (const Image *) NULL);
783  assert(image->signature == MagickCoreSignature);
784  if (image->debug != MagickFalse)
785  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
786  assert(exception != (ExceptionInfo *) NULL);
787  assert(exception->signature == MagickCoreSignature);
788 #if defined(MAGICKCORE_OPENCL_SUPPORT)
789  blur_image=AccelerateBlurImage(image,radius,sigma,exception);
790  if (blur_image != (Image *) NULL)
791  return(blur_image);
792 #endif
793  (void) FormatLocaleString(geometry,MagickPathExtent,
794  "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
795  kernel_info=AcquireKernelInfo(geometry,exception);
796  if (kernel_info == (KernelInfo *) NULL)
797  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
798  blur_image=ConvolveImage(image,kernel_info,exception);
799  kernel_info=DestroyKernelInfo(kernel_info);
800  return(blur_image);
801 }
802 
803 /*
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 % %
806 % %
807 % %
808 % B i l a t e r a l B l u r I m a g e %
809 % %
810 % %
811 % %
812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 %
814 % BilateralBlurImage() is a non-linear, edge-preserving, and noise-reducing
815 % smoothing filter for images. It replaces the intensity of each pixel with
816 % a weighted average of intensity values from nearby pixels. This weight is
817 % based on a Gaussian distribution. The weights depend not only on Euclidean
818 % distance of pixels, but also on the radiometric differences (e.g., range
819 % differences, such as color intensity, depth distance, etc.). This preserves
820 % sharp edges.
821 %
822 % The format of the BilateralBlurImage method is:
823 %
824 % Image *BilateralBlurImage(const Image *image,const size_t width,
825 % const size_t height,const double intensity_sigma,
826 % const double spatial_sigma,ExceptionInfo *exception)
827 %
828 % A description of each parameter follows:
829 %
830 % o image: the image.
831 %
832 % o width: the width of the neighborhood in pixels.
833 %
834 % o height: the height of the neighborhood in pixels.
835 %
836 % o intensity_sigma: sigma in the intensity space. A larger value means
837 % that farther colors within the pixel neighborhood (see spatial_sigma)
838 % will be mixed together, resulting in larger areas of semi-equal color.
839 %
840 % o spatial_sigma: sigma in the coordinate space. A larger value means that
841 % farther pixels influence each other as long as their colors are close
842 % enough (see intensity_sigma ). When the neigborhood diameter is greater
843 % than zero, it specifies the neighborhood size regardless of
844 % spatial_sigma. Otherwise, the neigborhood diameter is proportional to
845 % spatial_sigma.
846 %
847 % o exception: return any errors or warnings in this structure.
848 %
849 */
850 
851 static inline double BlurDistance(const ssize_t x,const ssize_t y,
852  const ssize_t u,const ssize_t v)
853 {
854  return(sqrt(((double) x-u)*((double) x-u)+((double) y-v)*((double) y-v)));
855 }
856 
857 static inline double BlurGaussian(const double x,const double sigma)
858 {
859  return(exp(-((double) x*x)*PerceptibleReciprocal(2.0*sigma*sigma))*
860  PerceptibleReciprocal(Magick2PI*sigma*sigma));
861 }
862 
863 static double **DestroyBilateralThreadSet(const ssize_t number_threads,
864  double **weights)
865 {
866  ssize_t
867  i;
868 
869  assert(weights != (double **) NULL);
870  for (i=0; i <= (ssize_t) number_threads; i++)
871  if (weights[i] != (double *) NULL)
872  weights[i]=(double *) RelinquishMagickMemory(weights[i]);
873  weights=(double **) RelinquishMagickMemory(weights);
874  return(weights);
875 }
876 
877 static double **AcquireBilateralThreadSet(const size_t number_threads,
878  const size_t width,const size_t height)
879 {
880  double
881  **weights;
882 
883  ssize_t
884  i;
885 
886  weights=(double **) AcquireQuantumMemory(number_threads+1,sizeof(*weights));
887  if (weights == (double **) NULL)
888  return((double **) NULL);
889  (void) memset(weights,0,number_threads*sizeof(*weights));
890  for (i=0; i <= (ssize_t) number_threads; i++)
891  {
892  weights[i]=(double *) AcquireQuantumMemory(width,height*sizeof(**weights));
893  if (weights[i] == (double *) NULL)
894  return(DestroyBilateralThreadSet(number_threads,weights));
895  }
896  return(weights);
897 }
898 
899 MagickExport Image *BilateralBlurImage(const Image *image,const size_t width,
900  const size_t height,const double intensity_sigma,const double spatial_sigma,
901  ExceptionInfo *exception)
902 {
903 #define MaxIntensity (255)
904 #define BilateralBlurImageTag "Blur/Image"
905 
906  CacheView
907  *blur_view,
908  *image_view;
909 
910  double
911  intensity_gaussian[2*(MaxIntensity+1)],
912  *spatial_gaussian,
913  **weights;
914 
915  Image
916  *blur_image;
917 
919  status;
920 
922  progress;
923 
924  OffsetInfo
925  mid;
926 
927  ssize_t
928  number_threads,
929  w,
930  y;
931 
932  assert(image != (const Image *) NULL);
933  assert(image->signature == MagickCoreSignature);
934  if (image->debug != MagickFalse)
935  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
936  assert(exception != (ExceptionInfo *) NULL);
937  assert(exception->signature == MagickCoreSignature);
938  blur_image=CloneImage(image,0,0,MagickTrue,exception);
939  if (blur_image == (Image *) NULL)
940  return((Image *) NULL);
941  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
942  {
943  blur_image=DestroyImage(blur_image);
944  return((Image *) NULL);
945  }
946  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
947  weights=AcquireBilateralThreadSet(number_threads,width,height);
948  if (weights == (double **) NULL)
949  {
950  blur_image=DestroyImage(blur_image);
951  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
952  }
953  for (w=(-MaxIntensity); w < MaxIntensity; w++)
954  intensity_gaussian[w+MaxIntensity]=BlurGaussian((double) w,intensity_sigma);
955  spatial_gaussian=weights[number_threads];
956  {
957  ssize_t
958  n,
959  v;
960 
961  n=0;
962  mid.x=(ssize_t) (width/2L);
963  mid.y=(ssize_t) (height/2L);
964  for (v=0; v < (ssize_t) height; v++)
965  {
966  ssize_t
967  u;
968 
969  for (u=0; u < (ssize_t) width; u++)
970  spatial_gaussian[n++]=BlurGaussian(BlurDistance(0,0,u-mid.x,v-mid.y),
971  spatial_sigma);
972  }
973  }
974  /*
975  Bilateral blur image.
976  */
977  status=MagickTrue;
978  progress=0;
979  image_view=AcquireVirtualCacheView(image,exception);
980  blur_view=AcquireAuthenticCacheView(blur_image,exception);
981 #if defined(MAGICKCORE_OPENMP_SUPPORT)
982  #pragma omp parallel for schedule(static) shared(progress,status) \
983  magick_number_threads(image,blur_image,blur_image->rows,1)
984 #endif
985  for (y=0; y < (ssize_t) blur_image->rows; y++)
986  {
987  const int
988  id = GetOpenMPThreadId();
989 
990  Quantum
991  *magick_restrict q;
992 
993  ssize_t
994  x;
995 
996  if (status == MagickFalse)
997  continue;
998  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
999  exception);
1000  if (q == (Quantum *) NULL)
1001  {
1002  status=MagickFalse;
1003  continue;
1004  }
1005  for (x=0; x < (ssize_t) blur_image->columns; x++)
1006  {
1007  double
1008  gamma,
1009  pixel;
1010 
1011  const Quantum
1012  *magick_restrict p,
1013  *magick_restrict r;
1014 
1015  ssize_t
1016  i,
1017  u;
1018 
1019  ssize_t
1020  n,
1021  v;
1022 
1023  /*
1024  Tonal weighting preserves edges while smoothing in the flat regions.
1025  */
1026  p=GetCacheViewVirtualPixels(image_view,x-mid.x,y-mid.y,width,height,
1027  exception);
1028  if (p == (const Quantum *) NULL)
1029  break;
1030  p+=(ssize_t) GetPixelChannels(image)*width*mid.y+GetPixelChannels(image)*
1031  mid.x;
1032  n=0;
1033  for (v=0; v < (ssize_t) height; v++)
1034  {
1035  for (u=0; u < (ssize_t) width; u++)
1036  {
1037  double
1038  intensity;
1039 
1040  r=p+(ssize_t) GetPixelChannels(image)*(ssize_t) width*(mid.y-v)+
1041  GetPixelChannels(image)*(mid.x-u);
1042  intensity=ScaleQuantumToChar(GetPixelIntensity(image,r))-
1043  (double) ScaleQuantumToChar(GetPixelIntensity(image,p));
1044  if ((intensity >= -MaxIntensity) && (intensity <= MaxIntensity))
1045  weights[id][n]=intensity_gaussian[(ssize_t) intensity+MaxIntensity]*
1046  spatial_gaussian[n];
1047  else
1048  weights[id][n]=BlurGaussian(intensity,intensity_sigma)*
1049  BlurGaussian(BlurDistance(x,y,x+u-mid.x,y+v-mid.y),spatial_sigma);
1050  n++;
1051  }
1052  }
1053  for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
1054  {
1055  PixelChannel
1056  channel;
1057 
1058  PixelTrait
1059  blur_traits,
1060  traits;
1061 
1062  channel=GetPixelChannelChannel(image,i);
1063  traits=GetPixelChannelTraits(image,channel);
1064  blur_traits=GetPixelChannelTraits(blur_image,channel);
1065  if ((traits == UndefinedPixelTrait) ||
1066  (blur_traits == UndefinedPixelTrait))
1067  continue;
1068  if ((blur_traits & CopyPixelTrait) != 0)
1069  {
1070  SetPixelChannel(blur_image,channel,p[i],q);
1071  continue;
1072  }
1073  pixel=0.0;
1074  gamma=0.0;
1075  n=0;
1076  if ((blur_traits & BlendPixelTrait) == 0)
1077  {
1078  /*
1079  No alpha blending.
1080  */
1081  for (v=0; v < (ssize_t) height; v++)
1082  {
1083  for (u=0; u < (ssize_t) width; u++)
1084  {
1085  r=p+(ssize_t) GetPixelChannels(image)*width*(mid.y-v)+
1086  GetPixelChannels(image)*(mid.x-u);
1087  pixel+=weights[id][n]*r[i];
1088  gamma+=weights[id][n];
1089  n++;
1090  }
1091  }
1092  SetPixelChannel(blur_image,channel,ClampToQuantum(
1093  PerceptibleReciprocal(gamma)*pixel),q);
1094  continue;
1095  }
1096  /*
1097  Alpha blending.
1098  */
1099  for (v=0; v < (ssize_t) height; v++)
1100  {
1101  for (u=0; u < (ssize_t) width; u++)
1102  {
1103  double
1104  alpha,
1105  beta;
1106 
1107  r=p+(ssize_t) GetPixelChannels(image)*width*(mid.y-v)+
1108  GetPixelChannels(image)*(mid.x-u);
1109  alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
1110  beta=(double) (QuantumScale*GetPixelAlpha(image,r));
1111  pixel+=weights[id][n]*r[i];
1112  gamma+=weights[id][n]*alpha*beta;
1113  n++;
1114  }
1115  }
1116  SetPixelChannel(blur_image,channel,ClampToQuantum(
1117  PerceptibleReciprocal(gamma)*pixel),q);
1118  }
1119  q+=GetPixelChannels(blur_image);
1120  }
1121  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1122  status=MagickFalse;
1123  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1124  {
1126  proceed;
1127 
1128 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1129  #pragma omp atomic
1130 #endif
1131  progress++;
1132  proceed=SetImageProgress(image,BilateralBlurImageTag,progress,
1133  image->rows);
1134  if (proceed == MagickFalse)
1135  status=MagickFalse;
1136  }
1137  }
1138  blur_image->type=image->type;
1139  blur_view=DestroyCacheView(blur_view);
1140  image_view=DestroyCacheView(image_view);
1141  weights=DestroyBilateralThreadSet(number_threads,weights);
1142  if (status == MagickFalse)
1143  blur_image=DestroyImage(blur_image);
1144  return(blur_image);
1145 }
1146 
1147 /*
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % %
1150 % %
1151 % %
1152 % C o n v o l v e I m a g e %
1153 % %
1154 % %
1155 % %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157 %
1158 % ConvolveImage() applies a custom convolution kernel to the image.
1159 %
1160 % The format of the ConvolveImage method is:
1161 %
1162 % Image *ConvolveImage(const Image *image,const KernelInfo *kernel,
1163 % ExceptionInfo *exception)
1164 %
1165 % A description of each parameter follows:
1166 %
1167 % o image: the image.
1168 %
1169 % o kernel: the filtering kernel.
1170 %
1171 % o exception: return any errors or warnings in this structure.
1172 %
1173 */
1175  const KernelInfo *kernel_info,ExceptionInfo *exception)
1176 {
1177  Image
1178  *convolve_image;
1179 
1180 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1181  convolve_image=AccelerateConvolveImage(image,kernel_info,exception);
1182  if (convolve_image != (Image *) NULL)
1183  return(convolve_image);
1184 #endif
1185 
1186  convolve_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
1187  exception);
1188  return(convolve_image);
1189 }
1190 
1191 /*
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193 % %
1194 % %
1195 % %
1196 % D e s p e c k l e I m a g e %
1197 % %
1198 % %
1199 % %
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201 %
1202 % DespeckleImage() reduces the speckle noise in an image while perserving the
1203 % edges of the original image. A speckle removing filter uses a complementary
1204 % hulling technique (raising pixels that are darker than their surrounding
1205 % neighbors, then complementarily lowering pixels that are brighter than their
1206 % surrounding neighbors) to reduce the speckle index of that image (reference
1207 % Crimmins speckle removal).
1208 %
1209 % The format of the DespeckleImage method is:
1210 %
1211 % Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
1212 %
1213 % A description of each parameter follows:
1214 %
1215 % o image: the image.
1216 %
1217 % o exception: return any errors or warnings in this structure.
1218 %
1219 */
1220 
1221 static void Hull(const Image *image,const ssize_t x_offset,
1222  const ssize_t y_offset,const size_t columns,const size_t rows,
1223  const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
1224 {
1225  Quantum
1226  *p,
1227  *q,
1228  *r,
1229  *s;
1230 
1231  ssize_t
1232  y;
1233 
1234  assert(image != (const Image *) NULL);
1235  assert(image->signature == MagickCoreSignature);
1236  if (image->debug != MagickFalse)
1237  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1238  assert(f != (Quantum *) NULL);
1239  assert(g != (Quantum *) NULL);
1240  p=f+(columns+2);
1241  q=g+(columns+2);
1242  r=p+(y_offset*((ssize_t) columns+2)+x_offset);
1243 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1244  #pragma omp parallel for schedule(static) \
1245  magick_number_threads(image,image,rows,1)
1246 #endif
1247  for (y=0; y < (ssize_t) rows; y++)
1248  {
1250  v;
1251 
1252  ssize_t
1253  i,
1254  x;
1255 
1256  i=(2*y+1)+y*columns;
1257  if (polarity > 0)
1258  for (x=0; x < (ssize_t) columns; x++)
1259  {
1260  v=(MagickRealType) p[i];
1261  if ((MagickRealType) r[i] >= (v+ScaleCharToQuantum(2)))
1262  v+=ScaleCharToQuantum(1);
1263  q[i]=(Quantum) v;
1264  i++;
1265  }
1266  else
1267  for (x=0; x < (ssize_t) columns; x++)
1268  {
1269  v=(MagickRealType) p[i];
1270  if ((MagickRealType) r[i] <= (v-ScaleCharToQuantum(2)))
1271  v-=ScaleCharToQuantum(1);
1272  q[i]=(Quantum) v;
1273  i++;
1274  }
1275  }
1276  p=f+(columns+2);
1277  q=g+(columns+2);
1278  r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1279  s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1280 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1281  #pragma omp parallel for schedule(static) \
1282  magick_number_threads(image,image,rows,1)
1283 #endif
1284  for (y=0; y < (ssize_t) rows; y++)
1285  {
1286  ssize_t
1287  i,
1288  x;
1289 
1291  v;
1292 
1293  i=(2*y+1)+y*columns;
1294  if (polarity > 0)
1295  for (x=0; x < (ssize_t) columns; x++)
1296  {
1297  v=(MagickRealType) q[i];
1298  if (((MagickRealType) s[i] >= (v+ScaleCharToQuantum(2))) &&
1299  ((MagickRealType) r[i] > v))
1300  v+=ScaleCharToQuantum(1);
1301  p[i]=(Quantum) v;
1302  i++;
1303  }
1304  else
1305  for (x=0; x < (ssize_t) columns; x++)
1306  {
1307  v=(MagickRealType) q[i];
1308  if (((MagickRealType) s[i] <= (v-ScaleCharToQuantum(2))) &&
1309  ((MagickRealType) r[i] < v))
1310  v-=ScaleCharToQuantum(1);
1311  p[i]=(Quantum) v;
1312  i++;
1313  }
1314  }
1315 }
1316 
1318 {
1319 #define DespeckleImageTag "Despeckle/Image"
1320 
1321  CacheView
1322  *despeckle_view,
1323  *image_view;
1324 
1325  Image
1326  *despeckle_image;
1327 
1329  status;
1330 
1331  MemoryInfo
1332  *buffer_info,
1333  *pixel_info;
1334 
1335  Quantum
1336  *magick_restrict buffer,
1337  *magick_restrict pixels;
1338 
1339  ssize_t
1340  i;
1341 
1342  size_t
1343  length;
1344 
1345  static const ssize_t
1346  X[4] = {0, 1, 1,-1},
1347  Y[4] = {1, 0, 1, 1};
1348 
1349  /*
1350  Allocate despeckled image.
1351  */
1352  assert(image != (const Image *) NULL);
1353  assert(image->signature == MagickCoreSignature);
1354  if (image->debug != MagickFalse)
1355  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1356  assert(exception != (ExceptionInfo *) NULL);
1357  assert(exception->signature == MagickCoreSignature);
1358 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1359  despeckle_image=AccelerateDespeckleImage(image,exception);
1360  if (despeckle_image != (Image *) NULL)
1361  return(despeckle_image);
1362 #endif
1363  despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1364  if (despeckle_image == (Image *) NULL)
1365  return((Image *) NULL);
1366  status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1367  if (status == MagickFalse)
1368  {
1369  despeckle_image=DestroyImage(despeckle_image);
1370  return((Image *) NULL);
1371  }
1372  /*
1373  Allocate image buffer.
1374  */
1375  length=(size_t) ((image->columns+2)*(image->rows+2));
1376  pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1377  buffer_info=AcquireVirtualMemory(length,sizeof(*buffer));
1378  if ((pixel_info == (MemoryInfo *) NULL) ||
1379  (buffer_info == (MemoryInfo *) NULL))
1380  {
1381  if (buffer_info != (MemoryInfo *) NULL)
1382  buffer_info=RelinquishVirtualMemory(buffer_info);
1383  if (pixel_info != (MemoryInfo *) NULL)
1384  pixel_info=RelinquishVirtualMemory(pixel_info);
1385  despeckle_image=DestroyImage(despeckle_image);
1386  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1387  }
1388  pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1389  buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1390  /*
1391  Reduce speckle in the image.
1392  */
1393  status=MagickTrue;
1394  image_view=AcquireVirtualCacheView(image,exception);
1395  despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1396  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1397  {
1398  PixelChannel
1399  channel;
1400 
1401  PixelTrait
1402  despeckle_traits,
1403  traits;
1404 
1405  ssize_t
1406  k,
1407  x;
1408 
1409  ssize_t
1410  j,
1411  y;
1412 
1413  if (status == MagickFalse)
1414  continue;
1415  channel=GetPixelChannelChannel(image,i);
1416  traits=GetPixelChannelTraits(image,channel);
1417  despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1418  if ((traits == UndefinedPixelTrait) ||
1419  (despeckle_traits == UndefinedPixelTrait))
1420  continue;
1421  if ((despeckle_traits & CopyPixelTrait) != 0)
1422  continue;
1423  (void) memset(pixels,0,length*sizeof(*pixels));
1424  j=(ssize_t) image->columns+2;
1425  for (y=0; y < (ssize_t) image->rows; y++)
1426  {
1427  const Quantum
1428  *magick_restrict p;
1429 
1430  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1431  if (p == (const Quantum *) NULL)
1432  {
1433  status=MagickFalse;
1434  continue;
1435  }
1436  j++;
1437  for (x=0; x < (ssize_t) image->columns; x++)
1438  {
1439  pixels[j++]=p[i];
1440  p+=GetPixelChannels(image);
1441  }
1442  j++;
1443  }
1444  (void) memset(buffer,0,length*sizeof(*buffer));
1445  for (k=0; k < 4; k++)
1446  {
1447  Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1448  Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1449  Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1450  Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1451  }
1452  j=(ssize_t) image->columns+2;
1453  for (y=0; y < (ssize_t) image->rows; y++)
1454  {
1456  sync;
1457 
1458  Quantum
1459  *magick_restrict q;
1460 
1461  q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1462  1,exception);
1463  if (q == (Quantum *) NULL)
1464  {
1465  status=MagickFalse;
1466  continue;
1467  }
1468  j++;
1469  for (x=0; x < (ssize_t) image->columns; x++)
1470  {
1471  SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1472  q+=GetPixelChannels(despeckle_image);
1473  }
1474  sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1475  if (sync == MagickFalse)
1476  status=MagickFalse;
1477  j++;
1478  }
1479  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1480  {
1482  proceed;
1483 
1485  GetPixelChannels(image));
1486  if (proceed == MagickFalse)
1487  status=MagickFalse;
1488  }
1489  }
1490  despeckle_view=DestroyCacheView(despeckle_view);
1491  image_view=DestroyCacheView(image_view);
1492  buffer_info=RelinquishVirtualMemory(buffer_info);
1493  pixel_info=RelinquishVirtualMemory(pixel_info);
1494  despeckle_image->type=image->type;
1495  if (status == MagickFalse)
1496  despeckle_image=DestroyImage(despeckle_image);
1497  return(despeckle_image);
1498 }
1499 
1500 /*
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502 % %
1503 % %
1504 % %
1505 % E d g e I m a g e %
1506 % %
1507 % %
1508 % %
1509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1510 %
1511 % EdgeImage() finds edges in an image. Radius defines the radius of the
1512 % convolution filter. Use a radius of 0 and EdgeImage() selects a suitable
1513 % radius for you.
1514 %
1515 % The format of the EdgeImage method is:
1516 %
1517 % Image *EdgeImage(const Image *image,const double radius,
1518 % ExceptionInfo *exception)
1519 %
1520 % A description of each parameter follows:
1521 %
1522 % o image: the image.
1523 %
1524 % o radius: the radius of the pixel neighborhood.
1525 %
1526 % o exception: return any errors or warnings in this structure.
1527 %
1528 */
1529 MagickExport Image *EdgeImage(const Image *image,const double radius,
1530  ExceptionInfo *exception)
1531 {
1532  Image
1533  *edge_image;
1534 
1535  KernelInfo
1536  *kernel_info;
1537 
1538  ssize_t
1539  i;
1540 
1541  size_t
1542  width;
1543 
1544  assert(image != (const Image *) NULL);
1545  assert(image->signature == MagickCoreSignature);
1546  if (image->debug != MagickFalse)
1547  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1548  assert(exception != (ExceptionInfo *) NULL);
1549  assert(exception->signature == MagickCoreSignature);
1550  width=GetOptimalKernelWidth1D(radius,0.5);
1551  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
1552  if (kernel_info == (KernelInfo *) NULL)
1553  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1554  (void) memset(kernel_info,0,sizeof(*kernel_info));
1555  kernel_info->width=width;
1556  kernel_info->height=width;
1557  kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1558  kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1559  kernel_info->signature=MagickCoreSignature;
1560  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1561  AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1562  sizeof(*kernel_info->values)));
1563  if (kernel_info->values == (MagickRealType *) NULL)
1564  {
1565  kernel_info=DestroyKernelInfo(kernel_info);
1566  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1567  }
1568  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1569  kernel_info->values[i]=(-1.0);
1570  kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1571  edge_image=ConvolveImage(image,kernel_info,exception);
1572  kernel_info=DestroyKernelInfo(kernel_info);
1573  return(edge_image);
1574 }
1575 
1576 /*
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578 % %
1579 % %
1580 % %
1581 % E m b o s s I m a g e %
1582 % %
1583 % %
1584 % %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 %
1587 % EmbossImage() returns a grayscale image with a three-dimensional effect.
1588 % We convolve the image with a Gaussian operator of the given radius and
1589 % standard deviation (sigma). For reasonable results, radius should be
1590 % larger than sigma. Use a radius of 0 and Emboss() selects a suitable
1591 % radius for you.
1592 %
1593 % The format of the EmbossImage method is:
1594 %
1595 % Image *EmbossImage(const Image *image,const double radius,
1596 % const double sigma,ExceptionInfo *exception)
1597 %
1598 % A description of each parameter follows:
1599 %
1600 % o image: the image.
1601 %
1602 % o radius: the radius of the pixel neighborhood.
1603 %
1604 % o sigma: the standard deviation of the Gaussian, in pixels.
1605 %
1606 % o exception: return any errors or warnings in this structure.
1607 %
1608 */
1609 MagickExport Image *EmbossImage(const Image *image,const double radius,
1610  const double sigma,ExceptionInfo *exception)
1611 {
1612  double
1613  gamma,
1614  normalize;
1615 
1616  Image
1617  *emboss_image;
1618 
1619  KernelInfo
1620  *kernel_info;
1621 
1622  ssize_t
1623  i;
1624 
1625  size_t
1626  width;
1627 
1628  ssize_t
1629  j,
1630  k,
1631  u,
1632  v;
1633 
1634  assert(image != (const Image *) NULL);
1635  assert(image->signature == MagickCoreSignature);
1636  if (image->debug != MagickFalse)
1637  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1638  assert(exception != (ExceptionInfo *) NULL);
1639  assert(exception->signature == MagickCoreSignature);
1640  width=GetOptimalKernelWidth1D(radius,sigma);
1641  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
1642  if (kernel_info == (KernelInfo *) NULL)
1643  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1644  kernel_info->width=width;
1645  kernel_info->height=width;
1646  kernel_info->x=(ssize_t) (width-1)/2;
1647  kernel_info->y=(ssize_t) (width-1)/2;
1648  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1649  AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1650  sizeof(*kernel_info->values)));
1651  if (kernel_info->values == (MagickRealType *) NULL)
1652  {
1653  kernel_info=DestroyKernelInfo(kernel_info);
1654  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1655  }
1656  j=(ssize_t) (kernel_info->width-1)/2;
1657  k=j;
1658  i=0;
1659  for (v=(-j); v <= j; v++)
1660  {
1661  for (u=(-j); u <= j; u++)
1662  {
1663  kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1664  8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1666  if (u != k)
1667  kernel_info->values[i]=0.0;
1668  i++;
1669  }
1670  k--;
1671  }
1672  normalize=0.0;
1673  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1674  normalize+=kernel_info->values[i];
1675  gamma=PerceptibleReciprocal(normalize);
1676  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1677  kernel_info->values[i]*=gamma;
1678  emboss_image=ConvolveImage(image,kernel_info,exception);
1679  kernel_info=DestroyKernelInfo(kernel_info);
1680  if (emboss_image != (Image *) NULL)
1681  (void) EqualizeImage(emboss_image,exception);
1682  return(emboss_image);
1683 }
1684 
1685 /*
1686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 % %
1688 % %
1689 % %
1690 % G a u s s i a n B l u r I m a g e %
1691 % %
1692 % %
1693 % %
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695 %
1696 % GaussianBlurImage() blurs an image. We convolve the image with a
1697 % Gaussian operator of the given radius and standard deviation (sigma).
1698 % For reasonable results, the radius should be larger than sigma. Use a
1699 % radius of 0 and GaussianBlurImage() selects a suitable radius for you.
1700 %
1701 % The format of the GaussianBlurImage method is:
1702 %
1703 % Image *GaussianBlurImage(const Image *image,onst double radius,
1704 % const double sigma,ExceptionInfo *exception)
1705 %
1706 % A description of each parameter follows:
1707 %
1708 % o image: the image.
1709 %
1710 % o radius: the radius of the Gaussian, in pixels, not counting the center
1711 % pixel.
1712 %
1713 % o sigma: the standard deviation of the Gaussian, in pixels.
1714 %
1715 % o exception: return any errors or warnings in this structure.
1716 %
1717 */
1718 MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
1719  const double sigma,ExceptionInfo *exception)
1720 {
1721  char
1722  geometry[MagickPathExtent];
1723 
1724  KernelInfo
1725  *kernel_info;
1726 
1727  Image
1728  *blur_image;
1729 
1730  assert(image != (const Image *) NULL);
1731  assert(image->signature == MagickCoreSignature);
1732  if (image->debug != MagickFalse)
1733  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1734  assert(exception != (ExceptionInfo *) NULL);
1735  assert(exception->signature == MagickCoreSignature);
1736  (void) FormatLocaleString(geometry,MagickPathExtent,"gaussian:%.20gx%.20g",
1737  radius,sigma);
1738  kernel_info=AcquireKernelInfo(geometry,exception);
1739  if (kernel_info == (KernelInfo *) NULL)
1740  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1741  blur_image=ConvolveImage(image,kernel_info,exception);
1742  kernel_info=DestroyKernelInfo(kernel_info);
1743  return(blur_image);
1744 }
1745 
1746 /*
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 % %
1749 % %
1750 % %
1751 % K u w a h a r a I m a g e %
1752 % %
1753 % %
1754 % %
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756 %
1757 % KuwaharaImage() is an edge preserving noise reduction filter.
1758 %
1759 % The format of the KuwaharaImage method is:
1760 %
1761 % Image *KuwaharaImage(const Image *image,const double radius,
1762 % const double sigma,ExceptionInfo *exception)
1763 %
1764 % A description of each parameter follows:
1765 %
1766 % o image: the image.
1767 %
1768 % o radius: the square window radius.
1769 %
1770 % o sigma: the standard deviation of the Gaussian, in pixels.
1771 %
1772 % o exception: return any errors or warnings in this structure.
1773 %
1774 */
1775 
1777  const double *magick_restrict pixel)
1778 {
1779  return(0.212656f*pixel[image->channel_map[RedPixelChannel].offset]+
1780  0.715158f*pixel[image->channel_map[GreenPixelChannel].offset]+
1781  0.072186f*pixel[image->channel_map[BluePixelChannel].offset]); /* Rec709 */
1782 }
1783 
1784 MagickExport Image *KuwaharaImage(const Image *image,const double radius,
1785  const double sigma,ExceptionInfo *exception)
1786 {
1787 #define KuwaharaImageTag "Kuwahara/Image"
1788 
1789  CacheView
1790  *image_view,
1791  *kuwahara_view;
1792 
1793  Image
1794  *gaussian_image,
1795  *kuwahara_image;
1796 
1798  status;
1799 
1801  progress;
1802 
1803  size_t
1804  width;
1805 
1806  ssize_t
1807  y;
1808 
1809  /*
1810  Initialize Kuwahara image attributes.
1811  */
1812  assert(image != (Image *) NULL);
1813  assert(image->signature == MagickCoreSignature);
1814  if (image->debug != MagickFalse)
1815  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1816  assert(exception != (ExceptionInfo *) NULL);
1817  assert(exception->signature == MagickCoreSignature);
1818  width=(size_t) radius+1;
1819  gaussian_image=BlurImage(image,radius,sigma,exception);
1820  if (gaussian_image == (Image *) NULL)
1821  return((Image *) NULL);
1822  kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1823  if (kuwahara_image == (Image *) NULL)
1824  {
1825  gaussian_image=DestroyImage(gaussian_image);
1826  return((Image *) NULL);
1827  }
1828  if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1829  {
1830  gaussian_image=DestroyImage(gaussian_image);
1831  kuwahara_image=DestroyImage(kuwahara_image);
1832  return((Image *) NULL);
1833  }
1834  /*
1835  Edge preserving noise reduction filter.
1836  */
1837  status=MagickTrue;
1838  progress=0;
1839  image_view=AcquireVirtualCacheView(gaussian_image,exception);
1840  kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1841 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1842  #pragma omp parallel for schedule(static) shared(progress,status) \
1843  magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1844 #endif
1845  for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1846  {
1847  Quantum
1848  *magick_restrict q;
1849 
1850  ssize_t
1851  x;
1852 
1853  if (status == MagickFalse)
1854  continue;
1855  q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1856  exception);
1857  if (q == (Quantum *) NULL)
1858  {
1859  status=MagickFalse;
1860  continue;
1861  }
1862  for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1863  {
1864  const Quantum
1865  *magick_restrict p;
1866 
1867  double
1868  min_variance;
1869 
1871  quadrant,
1872  target;
1873 
1874  size_t
1875  i;
1876 
1877  min_variance=MagickMaximumValue;
1878  SetGeometry(gaussian_image,&target);
1879  quadrant.width=width;
1880  quadrant.height=width;
1881  for (i=0; i < 4; i++)
1882  {
1883  const Quantum
1884  *magick_restrict k;
1885 
1886  double
1887  mean[MaxPixelChannels],
1888  variance;
1889 
1890  ssize_t
1891  n;
1892 
1893  ssize_t
1894  j;
1895 
1896  quadrant.x=x;
1897  quadrant.y=y;
1898  switch (i)
1899  {
1900  case 0:
1901  {
1902  quadrant.x=x-(ssize_t) (width-1);
1903  quadrant.y=y-(ssize_t) (width-1);
1904  break;
1905  }
1906  case 1:
1907  {
1908  quadrant.y=y-(ssize_t) (width-1);
1909  break;
1910  }
1911  case 2:
1912  {
1913  quadrant.x=x-(ssize_t) (width-1);
1914  break;
1915  }
1916  case 3:
1917  default:
1918  break;
1919  }
1920  p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1921  quadrant.width,quadrant.height,exception);
1922  if (p == (const Quantum *) NULL)
1923  break;
1924  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1925  mean[j]=0.0;
1926  k=p;
1927  for (n=0; n < (ssize_t) (width*width); n++)
1928  {
1929  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1930  mean[j]+=(double) k[j];
1931  k+=GetPixelChannels(gaussian_image);
1932  }
1933  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1934  mean[j]/=(double) (width*width);
1935  k=p;
1936  variance=0.0;
1937  for (n=0; n < (ssize_t) (width*width); n++)
1938  {
1939  double
1940  luma;
1941 
1942  luma=GetPixelLuma(gaussian_image,k);
1943  variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1944  (luma-GetMeanLuma(gaussian_image,mean));
1945  k+=GetPixelChannels(gaussian_image);
1946  }
1947  if (variance < min_variance)
1948  {
1949  min_variance=variance;
1950  target=quadrant;
1951  }
1952  }
1953  if (i < 4)
1954  {
1955  status=MagickFalse;
1956  break;
1957  }
1958  status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1959  UndefinedInterpolatePixel,(double) target.x+target.width/2.0,(double)
1960  target.y+target.height/2.0,q,exception);
1961  if (status == MagickFalse)
1962  break;
1963  q+=GetPixelChannels(kuwahara_image);
1964  }
1965  if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1966  status=MagickFalse;
1967  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1968  {
1970  proceed;
1971 
1972 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1973  #pragma omp atomic
1974 #endif
1975  progress++;
1976  proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1977  if (proceed == MagickFalse)
1978  status=MagickFalse;
1979  }
1980  }
1981  kuwahara_view=DestroyCacheView(kuwahara_view);
1982  image_view=DestroyCacheView(image_view);
1983  gaussian_image=DestroyImage(gaussian_image);
1984  if (status == MagickFalse)
1985  kuwahara_image=DestroyImage(kuwahara_image);
1986  return(kuwahara_image);
1987 }
1988 
1989 /*
1990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991 % %
1992 % %
1993 % %
1994 % L o c a l C o n t r a s t I m a g e %
1995 % %
1996 % %
1997 % %
1998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 %
2000 % LocalContrastImage() attempts to increase the appearance of large-scale
2001 % light-dark transitions. Local contrast enhancement works similarly to
2002 % sharpening with an unsharp mask, however the mask is instead created using
2003 % an image with a greater blur distance.
2004 %
2005 % The format of the LocalContrastImage method is:
2006 %
2007 % Image *LocalContrastImage(const Image *image, const double radius,
2008 % const double strength,ExceptionInfo *exception)
2009 %
2010 % A description of each parameter follows:
2011 %
2012 % o image: the image.
2013 %
2014 % o radius: the radius of the Gaussian blur, in percentage with 100%
2015 % resulting in a blur radius of 20% of largest dimension.
2016 %
2017 % o strength: the strength of the blur mask in percentage.
2018 %
2019 % o exception: return any errors or warnings in this structure.
2020 %
2021 */
2022 MagickExport Image *LocalContrastImage(const Image *image,const double radius,
2023  const double strength,ExceptionInfo *exception)
2024 {
2025 #define LocalContrastImageTag "LocalContrast/Image"
2026 
2027  CacheView
2028  *image_view,
2029  *contrast_view;
2030 
2031  float
2032  *interImage,
2033  *scanline,
2034  totalWeight;
2035 
2036  Image
2037  *contrast_image;
2038 
2040  status;
2041 
2042  MemoryInfo
2043  *scanline_info,
2044  *interImage_info;
2045 
2046  ssize_t
2047  scanLineSize,
2048  width;
2049 
2050  /*
2051  Initialize contrast image attributes.
2052  */
2053  assert(image != (const Image *) NULL);
2054  assert(image->signature == MagickCoreSignature);
2055  if (image->debug != MagickFalse)
2056  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2057  assert(exception != (ExceptionInfo *) NULL);
2058  assert(exception->signature == MagickCoreSignature);
2059 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2060  contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2061  if (contrast_image != (Image *) NULL)
2062  return(contrast_image);
2063 #endif
2064  contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2065  if (contrast_image == (Image *) NULL)
2066  return((Image *) NULL);
2067  if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2068  {
2069  contrast_image=DestroyImage(contrast_image);
2070  return((Image *) NULL);
2071  }
2072  image_view=AcquireVirtualCacheView(image,exception);
2073  contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2074  scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2075  width=(ssize_t) scanLineSize*0.002f*fabs(radius);
2076  scanLineSize+=(2*width);
2077  scanline_info=AcquireVirtualMemory((size_t) GetOpenMPMaximumThreads()*
2078  scanLineSize,sizeof(*scanline));
2079  if (scanline_info == (MemoryInfo *) NULL)
2080  {
2081  contrast_view=DestroyCacheView(contrast_view);
2082  image_view=DestroyCacheView(image_view);
2083  contrast_image=DestroyImage(contrast_image);
2084  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2085  }
2086  scanline=(float *) GetVirtualMemoryBlob(scanline_info);
2087  /*
2088  Create intermediate buffer.
2089  */
2090  interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(2*width)),
2091  sizeof(*interImage));
2092  if (interImage_info == (MemoryInfo *) NULL)
2093  {
2094  scanline_info=RelinquishVirtualMemory(scanline_info);
2095  contrast_view=DestroyCacheView(contrast_view);
2096  image_view=DestroyCacheView(image_view);
2097  contrast_image=DestroyImage(contrast_image);
2098  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2099  }
2100  interImage=(float *) GetVirtualMemoryBlob(interImage_info);
2101  totalWeight=(float) ((width+1)*(width+1));
2102  /*
2103  Vertical pass.
2104  */
2105  status=MagickTrue;
2106  {
2107  ssize_t
2108  x;
2109 
2110 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2111 #pragma omp parallel for schedule(static) \
2112  magick_number_threads(image,image,image->columns,1)
2113 #endif
2114  for (x=0; x < (ssize_t) image->columns; x++)
2115  {
2116  const int
2117  id = GetOpenMPThreadId();
2118 
2119  const Quantum
2120  *magick_restrict p;
2121 
2122  float
2123  *out,
2124  *pix,
2125  *pixels;
2126 
2127  ssize_t
2128  y;
2129 
2130  ssize_t
2131  i;
2132 
2133  if (status == MagickFalse)
2134  continue;
2135  pixels=scanline;
2136  pixels+=id*scanLineSize;
2137  pix=pixels;
2138  p=GetCacheViewVirtualPixels(image_view,x,-width,1,image->rows+(2*width),
2139  exception);
2140  if (p == (const Quantum *) NULL)
2141  {
2142  status=MagickFalse;
2143  continue;
2144  }
2145  for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2146  {
2147  *pix++=(float)GetPixelLuma(image,p);
2148  p+=image->number_channels;
2149  }
2150  out=interImage+x+width;
2151  for (y=0; y < (ssize_t) image->rows; y++)
2152  {
2153  float
2154  sum,
2155  weight;
2156 
2157  weight=1.0f;
2158  sum=0;
2159  pix=pixels+y;
2160  for (i=0; i < width; i++)
2161  {
2162  sum+=weight*(*pix++);
2163  weight+=1.0f;
2164  }
2165  for (i=width+1; i < (2*width); i++)
2166  {
2167  sum+=weight*(*pix++);
2168  weight-=1.0f;
2169  }
2170  /* write to output */
2171  *out=sum/totalWeight;
2172  /* mirror into padding */
2173  if (x <= width && x != 0)
2174  *(out-(x*2))=*out;
2175  if ((x > (ssize_t) image->columns-width-2) &&
2176  (x != (ssize_t) image->columns-1))
2177  *(out+((image->columns-x-1)*2))=*out;
2178  out+=image->columns+(width*2);
2179  }
2180  }
2181  }
2182  /*
2183  Horizontal pass.
2184  */
2185  {
2186  ssize_t
2187  y;
2188 
2189 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2190 #pragma omp parallel for schedule(static) \
2191  magick_number_threads(image,image,image->rows,1)
2192 #endif
2193  for (y=0; y < (ssize_t) image->rows; y++)
2194  {
2195  const int
2196  id = GetOpenMPThreadId();
2197 
2198  const Quantum
2199  *magick_restrict p;
2200 
2201  float
2202  *pix,
2203  *pixels;
2204 
2205  Quantum
2206  *magick_restrict q;
2207 
2208  ssize_t
2209  x;
2210 
2211  ssize_t
2212  i;
2213 
2214  if (status == MagickFalse)
2215  continue;
2216  pixels=scanline;
2217  pixels+=id*scanLineSize;
2218  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2219  q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2220  exception);
2221  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2222  {
2223  status=MagickFalse;
2224  continue;
2225  }
2226  memcpy(pixels,interImage+(y*(image->columns+(2*width))),(image->columns+
2227  (2*width))*sizeof(float));
2228  for (x=0; x < (ssize_t) image->columns; x++)
2229  {
2230  float
2231  mult,
2232  srcVal,
2233  sum,
2234  weight;
2235 
2236  PixelTrait
2237  traits;
2238 
2239  weight=1.0f;
2240  sum=0;
2241  pix=pixels+x;
2242  for (i=0; i < width; i++)
2243  {
2244  sum+=weight*(*pix++);
2245  weight+=1.0f;
2246  }
2247  for (i=width+1; i < (2*width); i++)
2248  {
2249  sum+=weight*(*pix++);
2250  weight-=1.0f;
2251  }
2252  /* Apply and write */
2253  srcVal=(float) GetPixelLuma(image,p);
2254  mult=(srcVal-(sum/totalWeight))*(strength/100.0f);
2255  mult=(srcVal+mult)/srcVal;
2256  traits=GetPixelChannelTraits(image,RedPixelChannel);
2257  if ((traits & UpdatePixelTrait) != 0)
2258  SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2259  GetPixelRed(image,p)*mult),q);
2261  if ((traits & UpdatePixelTrait) != 0)
2263  GetPixelGreen(image,p)*mult),q);
2265  if ((traits & UpdatePixelTrait) != 0)
2266  SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2267  GetPixelBlue(image,p)*mult),q);
2268  p+=image->number_channels;
2269  q+=contrast_image->number_channels;
2270  }
2271  if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2272  status=MagickFalse;
2273  }
2274  }
2275  scanline_info=RelinquishVirtualMemory(scanline_info);
2276  interImage_info=RelinquishVirtualMemory(interImage_info);
2277  contrast_view=DestroyCacheView(contrast_view);
2278  image_view=DestroyCacheView(image_view);
2279  if (status == MagickFalse)
2280  contrast_image=DestroyImage(contrast_image);
2281  return(contrast_image);
2282 }
2283 
2284 /*
2285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286 % %
2287 % %
2288 % %
2289 % M o t i o n B l u r I m a g e %
2290 % %
2291 % %
2292 % %
2293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2294 %
2295 % MotionBlurImage() simulates motion blur. We convolve the image with a
2296 % Gaussian operator of the given radius and standard deviation (sigma).
2297 % For reasonable results, radius should be larger than sigma. Use a
2298 % radius of 0 and MotionBlurImage() selects a suitable radius for you.
2299 % Angle gives the angle of the blurring motion.
2300 %
2301 % Andrew Protano contributed this effect.
2302 %
2303 % The format of the MotionBlurImage method is:
2304 %
2305 % Image *MotionBlurImage(const Image *image,const double radius,
2306 % const double sigma,const double angle,ExceptionInfo *exception)
2307 %
2308 % A description of each parameter follows:
2309 %
2310 % o image: the image.
2311 %
2312 % o radius: the radius of the Gaussian, in pixels, not counting
2313 % the center pixel.
2314 %
2315 % o sigma: the standard deviation of the Gaussian, in pixels.
2316 %
2317 % o angle: Apply the effect along this angle.
2318 %
2319 % o exception: return any errors or warnings in this structure.
2320 %
2321 */
2322 
2323 static MagickRealType *GetMotionBlurKernel(const size_t width,
2324  const double sigma)
2325 {
2327  *kernel,
2328  normalize;
2329 
2330  ssize_t
2331  i;
2332 
2333  /*
2334  Generate a 1-D convolution kernel.
2335  */
2336  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2338  width,sizeof(*kernel)));
2339  if (kernel == (MagickRealType *) NULL)
2340  return(kernel);
2341  normalize=0.0;
2342  for (i=0; i < (ssize_t) width; i++)
2343  {
2344  kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
2346  normalize+=kernel[i];
2347  }
2348  for (i=0; i < (ssize_t) width; i++)
2349  kernel[i]/=normalize;
2350  return(kernel);
2351 }
2352 
2353 MagickExport Image *MotionBlurImage(const Image *image,const double radius,
2354  const double sigma,const double angle,ExceptionInfo *exception)
2355 {
2356 #define BlurImageTag "Blur/Image"
2357 
2358  CacheView
2359  *blur_view,
2360  *image_view,
2361  *motion_view;
2362 
2363  Image
2364  *blur_image;
2365 
2367  status;
2368 
2370  progress;
2371 
2373  *kernel;
2374 
2375  OffsetInfo
2376  *offset;
2377 
2378  PointInfo
2379  point;
2380 
2381  size_t
2382  width;
2383 
2384  ssize_t
2385  w,
2386  y;
2387 
2388  assert(image != (Image *) NULL);
2389  assert(image->signature == MagickCoreSignature);
2390  if (image->debug != MagickFalse)
2391  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2392  assert(exception != (ExceptionInfo *) NULL);
2393  width=GetOptimalKernelWidth1D(radius,sigma);
2394  kernel=GetMotionBlurKernel(width,sigma);
2395  if (kernel == (MagickRealType *) NULL)
2396  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2397  offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
2398  if (offset == (OffsetInfo *) NULL)
2399  {
2400  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2401  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2402  }
2403  point.x=(double) width*sin(DegreesToRadians(angle));
2404  point.y=(double) width*cos(DegreesToRadians(angle));
2405  for (w=0; w < (ssize_t) width; w++)
2406  {
2407  offset[w].x=CastDoubleToLong(ceil((double) (w*point.y)/
2408  hypot(point.x,point.y)-0.5));
2409  offset[w].y=CastDoubleToLong(ceil((double) (w*point.x)/
2410  hypot(point.x,point.y)-0.5));
2411  }
2412  /*
2413  Motion blur image.
2414  */
2415 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2416  blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2417  if (blur_image != (Image *) NULL)
2418  {
2419  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2420  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2421  return(blur_image);
2422  }
2423 #endif
2424  blur_image=CloneImage(image,0,0,MagickTrue,exception);
2425  if (blur_image == (Image *) NULL)
2426  {
2427  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2428  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2429  return((Image *) NULL);
2430  }
2431  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2432  {
2433  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2434  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2435  blur_image=DestroyImage(blur_image);
2436  return((Image *) NULL);
2437  }
2438  status=MagickTrue;
2439  progress=0;
2440  image_view=AcquireVirtualCacheView(image,exception);
2441  motion_view=AcquireVirtualCacheView(image,exception);
2442  blur_view=AcquireAuthenticCacheView(blur_image,exception);
2443 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2444  #pragma omp parallel for schedule(static) shared(progress,status) \
2445  magick_number_threads(image,blur_image,image->rows,1)
2446 #endif
2447  for (y=0; y < (ssize_t) image->rows; y++)
2448  {
2449  const Quantum
2450  *magick_restrict p;
2451 
2452  Quantum
2453  *magick_restrict q;
2454 
2455  ssize_t
2456  x;
2457 
2458  if (status == MagickFalse)
2459  continue;
2460  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2461  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2462  exception);
2463  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2464  {
2465  status=MagickFalse;
2466  continue;
2467  }
2468  for (x=0; x < (ssize_t) image->columns; x++)
2469  {
2470  ssize_t
2471  i;
2472 
2473  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2474  {
2475  double
2476  alpha,
2477  gamma,
2478  pixel;
2479 
2480  PixelChannel
2481  channel;
2482 
2483  PixelTrait
2484  blur_traits,
2485  traits;
2486 
2487  const Quantum
2488  *magick_restrict r;
2489 
2491  *magick_restrict k;
2492 
2493  ssize_t
2494  j;
2495 
2496  channel=GetPixelChannelChannel(image,i);
2497  traits=GetPixelChannelTraits(image,channel);
2498  blur_traits=GetPixelChannelTraits(blur_image,channel);
2499  if ((traits == UndefinedPixelTrait) ||
2500  (blur_traits == UndefinedPixelTrait))
2501  continue;
2502  if ((blur_traits & CopyPixelTrait) != 0)
2503  {
2504  SetPixelChannel(blur_image,channel,p[i],q);
2505  continue;
2506  }
2507  k=kernel;
2508  pixel=0.0;
2509  if ((blur_traits & BlendPixelTrait) == 0)
2510  {
2511  for (j=0; j < (ssize_t) width; j++)
2512  {
2513  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2514  offset[j].y,1,1,exception);
2515  if (r == (const Quantum *) NULL)
2516  {
2517  status=MagickFalse;
2518  continue;
2519  }
2520  pixel+=(*k)*r[i];
2521  k++;
2522  }
2523  SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2524  continue;
2525  }
2526  alpha=0.0;
2527  gamma=0.0;
2528  for (j=0; j < (ssize_t) width; j++)
2529  {
2530  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2531  1,exception);
2532  if (r == (const Quantum *) NULL)
2533  {
2534  status=MagickFalse;
2535  continue;
2536  }
2537  alpha=(double) (QuantumScale*GetPixelAlpha(image,r));
2538  pixel+=(*k)*alpha*r[i];
2539  gamma+=(*k)*alpha;
2540  k++;
2541  }
2542  gamma=PerceptibleReciprocal(gamma);
2543  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2544  }
2545  p+=GetPixelChannels(image);
2546  q+=GetPixelChannels(blur_image);
2547  }
2548  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2549  status=MagickFalse;
2550  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2551  {
2553  proceed;
2554 
2555 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2556  #pragma omp atomic
2557 #endif
2558  progress++;
2559  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2560  if (proceed == MagickFalse)
2561  status=MagickFalse;
2562  }
2563  }
2564  blur_view=DestroyCacheView(blur_view);
2565  motion_view=DestroyCacheView(motion_view);
2566  image_view=DestroyCacheView(image_view);
2567  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2568  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2569  if (status == MagickFalse)
2570  blur_image=DestroyImage(blur_image);
2571  return(blur_image);
2572 }
2573 
2574 /*
2575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2576 % %
2577 % %
2578 % %
2579 % P r e v i e w I m a g e %
2580 % %
2581 % %
2582 % %
2583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584 %
2585 % PreviewImage() tiles 9 thumbnails of the specified image with an image
2586 % processing operation applied with varying parameters. This may be helpful
2587 % pin-pointing an appropriate parameter for a particular image processing
2588 % operation.
2589 %
2590 % The format of the PreviewImages method is:
2591 %
2592 % Image *PreviewImages(const Image *image,const PreviewType preview,
2593 % ExceptionInfo *exception)
2594 %
2595 % A description of each parameter follows:
2596 %
2597 % o image: the image.
2598 %
2599 % o preview: the image processing operation.
2600 %
2601 % o exception: return any errors or warnings in this structure.
2602 %
2603 */
2604 MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
2605  ExceptionInfo *exception)
2606 {
2607 #define NumberTiles 9
2608 #define PreviewImageTag "Preview/Image"
2609 #define DefaultPreviewGeometry "204x204+10+10"
2610 
2611  char
2612  factor[MagickPathExtent],
2613  label[MagickPathExtent];
2614 
2615  double
2616  degrees,
2617  gamma,
2618  percentage,
2619  radius,
2620  sigma,
2621  threshold;
2622 
2623  Image
2624  *images,
2625  *montage_image,
2626  *preview_image,
2627  *thumbnail;
2628 
2629  ImageInfo
2630  *preview_info;
2631 
2633  proceed;
2634 
2635  MontageInfo
2636  *montage_info;
2637 
2638  QuantizeInfo
2639  quantize_info;
2640 
2642  geometry;
2643 
2644  ssize_t
2645  i,
2646  x;
2647 
2648  size_t
2649  colors;
2650 
2651  ssize_t
2652  y;
2653 
2654  /*
2655  Open output image file.
2656  */
2657  assert(image != (Image *) NULL);
2658  assert(image->signature == MagickCoreSignature);
2659  if (image->debug != MagickFalse)
2660  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2661  colors=2;
2662  degrees=0.0;
2663  gamma=(-0.2f);
2664  preview_info=AcquireImageInfo();
2665  SetGeometry(image,&geometry);
2666  (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2667  &geometry.width,&geometry.height);
2668  images=NewImageList();
2669  percentage=12.5;
2670  GetQuantizeInfo(&quantize_info);
2671  radius=0.0;
2672  sigma=1.0;
2673  threshold=0.0;
2674  x=0;
2675  y=0;
2676  for (i=0; i < NumberTiles; i++)
2677  {
2678  thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2679  if (thumbnail == (Image *) NULL)
2680  break;
2681  (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2682  (void *) NULL);
2683  (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
2684  if (i == (NumberTiles/2))
2685  {
2686  (void) QueryColorCompliance("#dfdfdf",AllCompliance,
2687  &thumbnail->matte_color,exception);
2688  AppendImageToList(&images,thumbnail);
2689  continue;
2690  }
2691  switch (preview)
2692  {
2693  case RotatePreview:
2694  {
2695  degrees+=45.0;
2696  preview_image=RotateImage(thumbnail,degrees,exception);
2697  (void) FormatLocaleString(label,MagickPathExtent,"rotate %g",degrees);
2698  break;
2699  }
2700  case ShearPreview:
2701  {
2702  degrees+=5.0;
2703  preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2704  (void) FormatLocaleString(label,MagickPathExtent,"shear %gx%g",degrees,
2705  2.0*degrees);
2706  break;
2707  }
2708  case RollPreview:
2709  {
2710  x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
2711  y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
2712  preview_image=RollImage(thumbnail,x,y,exception);
2713  (void) FormatLocaleString(label,MagickPathExtent,"roll %+.20gx%+.20g",
2714  (double) x,(double) y);
2715  break;
2716  }
2717  case HuePreview:
2718  {
2719  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2720  if (preview_image == (Image *) NULL)
2721  break;
2722  (void) FormatLocaleString(factor,MagickPathExtent,"100,100,%g",2.0*
2723  percentage);
2724  (void) ModulateImage(preview_image,factor,exception);
2725  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2726  break;
2727  }
2728  case SaturationPreview:
2729  {
2730  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2731  if (preview_image == (Image *) NULL)
2732  break;
2733  (void) FormatLocaleString(factor,MagickPathExtent,"100,%g",2.0*
2734  percentage);
2735  (void) ModulateImage(preview_image,factor,exception);
2736  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2737  break;
2738  }
2739  case BrightnessPreview:
2740  {
2741  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2742  if (preview_image == (Image *) NULL)
2743  break;
2744  (void) FormatLocaleString(factor,MagickPathExtent,"%g",2.0*percentage);
2745  (void) ModulateImage(preview_image,factor,exception);
2746  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2747  break;
2748  }
2749  case GammaPreview:
2750  default:
2751  {
2752  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2753  if (preview_image == (Image *) NULL)
2754  break;
2755  gamma+=0.4f;
2756  (void) GammaImage(preview_image,gamma,exception);
2757  (void) FormatLocaleString(label,MagickPathExtent,"gamma %g",gamma);
2758  break;
2759  }
2760  case SpiffPreview:
2761  {
2762  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2763  if (preview_image != (Image *) NULL)
2764  for (x=0; x < i; x++)
2765  (void) ContrastImage(preview_image,MagickTrue,exception);
2766  (void) FormatLocaleString(label,MagickPathExtent,"contrast (%.20g)",
2767  (double) i+1);
2768  break;
2769  }
2770  case DullPreview:
2771  {
2772  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2773  if (preview_image == (Image *) NULL)
2774  break;
2775  for (x=0; x < i; x++)
2776  (void) ContrastImage(preview_image,MagickFalse,exception);
2777  (void) FormatLocaleString(label,MagickPathExtent,"+contrast (%.20g)",
2778  (double) i+1);
2779  break;
2780  }
2781  case GrayscalePreview:
2782  {
2783  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2784  if (preview_image == (Image *) NULL)
2785  break;
2786  colors<<=1;
2787  quantize_info.number_colors=colors;
2788  quantize_info.colorspace=GRAYColorspace;
2789  (void) QuantizeImage(&quantize_info,preview_image,exception);
2790  (void) FormatLocaleString(label,MagickPathExtent,
2791  "-colorspace gray -colors %.20g",(double) colors);
2792  break;
2793  }
2794  case QuantizePreview:
2795  {
2796  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2797  if (preview_image == (Image *) NULL)
2798  break;
2799  colors<<=1;
2800  quantize_info.number_colors=colors;
2801  (void) QuantizeImage(&quantize_info,preview_image,exception);
2802  (void) FormatLocaleString(label,MagickPathExtent,"colors %.20g",
2803  (double) colors);
2804  break;
2805  }
2806  case DespecklePreview:
2807  {
2808  for (x=0; x < (i-1); x++)
2809  {
2810  preview_image=DespeckleImage(thumbnail,exception);
2811  if (preview_image == (Image *) NULL)
2812  break;
2813  thumbnail=DestroyImage(thumbnail);
2814  thumbnail=preview_image;
2815  }
2816  preview_image=DespeckleImage(thumbnail,exception);
2817  if (preview_image == (Image *) NULL)
2818  break;
2819  (void) FormatLocaleString(label,MagickPathExtent,"despeckle (%.20g)",
2820  (double) i+1);
2821  break;
2822  }
2823  case ReduceNoisePreview:
2824  {
2825  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t)
2826  radius,(size_t) radius,exception);
2827  (void) FormatLocaleString(label,MagickPathExtent,"noise %g",radius);
2828  break;
2829  }
2830  case AddNoisePreview:
2831  {
2832  switch ((int) i)
2833  {
2834  case 0:
2835  {
2836  (void) CopyMagickString(factor,"uniform",MagickPathExtent);
2837  break;
2838  }
2839  case 1:
2840  {
2841  (void) CopyMagickString(factor,"gaussian",MagickPathExtent);
2842  break;
2843  }
2844  case 2:
2845  {
2846  (void) CopyMagickString(factor,"multiplicative",MagickPathExtent);
2847  break;
2848  }
2849  case 3:
2850  {
2851  (void) CopyMagickString(factor,"impulse",MagickPathExtent);
2852  break;
2853  }
2854  case 5:
2855  {
2856  (void) CopyMagickString(factor,"laplacian",MagickPathExtent);
2857  break;
2858  }
2859  case 6:
2860  {
2861  (void) CopyMagickString(factor,"Poisson",MagickPathExtent);
2862  break;
2863  }
2864  default:
2865  {
2866  (void) CopyMagickString(thumbnail->magick,"NULL",MagickPathExtent);
2867  break;
2868  }
2869  }
2870  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
2871  (size_t) i,exception);
2872  (void) FormatLocaleString(label,MagickPathExtent,"+noise %s",factor);
2873  break;
2874  }
2875  case SharpenPreview:
2876  {
2877  preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2878  (void) FormatLocaleString(label,MagickPathExtent,"sharpen %gx%g",
2879  radius,sigma);
2880  break;
2881  }
2882  case BlurPreview:
2883  {
2884  preview_image=BlurImage(thumbnail,radius,sigma,exception);
2885  (void) FormatLocaleString(label,MagickPathExtent,"blur %gx%g",radius,
2886  sigma);
2887  break;
2888  }
2889  case ThresholdPreview:
2890  {
2891  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2892  if (preview_image == (Image *) NULL)
2893  break;
2894  (void) BilevelImage(thumbnail,(double) (percentage*((double)
2895  QuantumRange+1.0))/100.0,exception);
2896  (void) FormatLocaleString(label,MagickPathExtent,"threshold %g",
2897  (double) (percentage*((double) QuantumRange+1.0))/100.0);
2898  break;
2899  }
2900  case EdgeDetectPreview:
2901  {
2902  preview_image=EdgeImage(thumbnail,radius,exception);
2903  (void) FormatLocaleString(label,MagickPathExtent,"edge %g",radius);
2904  break;
2905  }
2906  case SpreadPreview:
2907  {
2908  preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2909  exception);
2910  (void) FormatLocaleString(label,MagickPathExtent,"spread %g",
2911  radius+0.5);
2912  break;
2913  }
2914  case SolarizePreview:
2915  {
2916  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2917  if (preview_image == (Image *) NULL)
2918  break;
2919  (void) SolarizeImage(preview_image,(double) QuantumRange*percentage/
2920  100.0,exception);
2921  (void) FormatLocaleString(label,MagickPathExtent,"solarize %g",
2922  (QuantumRange*percentage)/100.0);
2923  break;
2924  }
2925  case ShadePreview:
2926  {
2927  degrees+=10.0;
2928  preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2929  exception);
2930  (void) FormatLocaleString(label,MagickPathExtent,"shade %gx%g",degrees,
2931  degrees);
2932  break;
2933  }
2934  case RaisePreview:
2935  {
2937  raise;
2938 
2939  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2940  if (preview_image == (Image *) NULL)
2941  break;
2942  raise.width=(size_t) (2*i+2);
2943  raise.height=(size_t) (2*i+2);
2944  raise.x=(i-1)/2;
2945  raise.y=(i-1)/2;
2946  (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2947  (void) FormatLocaleString(label,MagickPathExtent,
2948  "raise %.20gx%.20g%+.20g%+.20g",(double) raise.width,(double)
2949  raise.height,(double) raise.x,(double) raise.y);
2950  break;
2951  }
2952  case SegmentPreview:
2953  {
2954  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2955  if (preview_image == (Image *) NULL)
2956  break;
2957  threshold+=0.4f;
2958  (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2959  threshold,exception);
2960  (void) FormatLocaleString(label,MagickPathExtent,"segment %gx%g",
2961  threshold,threshold);
2962  break;
2963  }
2964  case SwirlPreview:
2965  {
2966  preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2967  exception);
2968  (void) FormatLocaleString(label,MagickPathExtent,"swirl %g",degrees);
2969  degrees+=45.0;
2970  break;
2971  }
2972  case ImplodePreview:
2973  {
2974  degrees+=0.1f;
2975  preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2976  exception);
2977  (void) FormatLocaleString(label,MagickPathExtent,"implode %g",degrees);
2978  break;
2979  }
2980  case WavePreview:
2981  {
2982  degrees+=5.0f;
2983  preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2984  image->interpolate,exception);
2985  (void) FormatLocaleString(label,MagickPathExtent,"wave %gx%g",0.5*
2986  degrees,2.0*degrees);
2987  break;
2988  }
2989  case OilPaintPreview:
2990  {
2991  preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
2992  exception);
2993  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
2994  radius,sigma);
2995  break;
2996  }
2998  {
2999  preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
3000  exception);
3001  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
3002  radius,sigma);
3003  break;
3004  }
3005  case JPEGPreview:
3006  {
3007  char
3008  filename[MagickPathExtent];
3009 
3010  int
3011  file;
3012 
3014  status;
3015 
3016  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3017  if (preview_image == (Image *) NULL)
3018  break;
3019  preview_info->quality=(size_t) percentage;
3020  (void) FormatLocaleString(factor,MagickPathExtent,"%.20g",(double)
3021  preview_info->quality);
3022  file=AcquireUniqueFileResource(filename);
3023  if (file != -1)
3024  file=close(file)-1;
3025  (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3026  "jpeg:%s",filename);
3027  status=WriteImage(preview_info,preview_image,exception);
3028  if (status != MagickFalse)
3029  {
3030  Image
3031  *quality_image;
3032 
3033  (void) CopyMagickString(preview_info->filename,
3034  preview_image->filename,MagickPathExtent);
3035  quality_image=ReadImage(preview_info,exception);
3036  if (quality_image != (Image *) NULL)
3037  {
3038  preview_image=DestroyImage(preview_image);
3039  preview_image=quality_image;
3040  }
3041  }
3042  (void) RelinquishUniqueFileResource(preview_image->filename);
3043  if ((GetBlobSize(preview_image)/1024) >= 1024)
3044  (void) FormatLocaleString(label,MagickPathExtent,"quality %s\n%gmb ",
3045  factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
3046  1024.0/1024.0);
3047  else
3048  if (GetBlobSize(preview_image) >= 1024)
3049  (void) FormatLocaleString(label,MagickPathExtent,
3050  "quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
3051  GetBlobSize(preview_image))/1024.0);
3052  else
3053  (void) FormatLocaleString(label,MagickPathExtent,
3054  "quality %s\n%.20gb ",factor,(double) ((MagickOffsetType)
3055  GetBlobSize(thumbnail)));
3056  break;
3057  }
3058  }
3059  thumbnail=DestroyImage(thumbnail);
3060  percentage+=12.5;
3061  radius+=0.5;
3062  sigma+=0.25;
3063  if (preview_image == (Image *) NULL)
3064  break;
3065  preview_image->alpha_trait=UndefinedPixelTrait;
3066  (void) DeleteImageProperty(preview_image,"label");
3067  (void) SetImageProperty(preview_image,"label",label,exception);
3068  AppendImageToList(&images,preview_image);
3070  NumberTiles);
3071  if (proceed == MagickFalse)
3072  break;
3073  }
3074  if (images == (Image *) NULL)
3075  {
3076  preview_info=DestroyImageInfo(preview_info);
3077  return((Image *) NULL);
3078  }
3079  /*
3080  Create the montage.
3081  */
3082  montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
3083  (void) CopyMagickString(montage_info->filename,image->filename,
3085  montage_info->shadow=MagickTrue;
3086  (void) CloneString(&montage_info->tile,"3x3");
3087  (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3088  (void) CloneString(&montage_info->frame,DefaultTileFrame);
3089  montage_image=MontageImages(images,montage_info,exception);
3090  montage_info=DestroyMontageInfo(montage_info);
3091  images=DestroyImageList(images);
3092  if (montage_image == (Image *) NULL)
3093  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3094  if (montage_image->montage != (char *) NULL)
3095  {
3096  /*
3097  Free image directory.
3098  */
3099  montage_image->montage=(char *) RelinquishMagickMemory(
3100  montage_image->montage);
3101  if (image->directory != (char *) NULL)
3102  montage_image->directory=(char *) RelinquishMagickMemory(
3103  montage_image->directory);
3104  }
3105  preview_info=DestroyImageInfo(preview_info);
3106  return(montage_image);
3107 }
3108 
3109 /*
3110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3111 % %
3112 % %
3113 % %
3114 % R o t a t i o n a l B l u r I m a g e %
3115 % %
3116 % %
3117 % %
3118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119 %
3120 % RotationalBlurImage() applies a radial blur to the image.
3121 %
3122 % Andrew Protano contributed this effect.
3123 %
3124 % The format of the RotationalBlurImage method is:
3125 %
3126 % Image *RotationalBlurImage(const Image *image,const double angle,
3127 % ExceptionInfo *exception)
3128 %
3129 % A description of each parameter follows:
3130 %
3131 % o image: the image.
3132 %
3133 % o angle: the angle of the radial blur.
3134 %
3135 % o blur: the blur.
3136 %
3137 % o exception: return any errors or warnings in this structure.
3138 %
3139 */
3140 MagickExport Image *RotationalBlurImage(const Image *image,const double angle,
3141  ExceptionInfo *exception)
3142 {
3143  CacheView
3144  *blur_view,
3145  *image_view,
3146  *radial_view;
3147 
3148  double
3149  blur_radius,
3150  *cos_theta,
3151  offset,
3152  *sin_theta,
3153  theta;
3154 
3155  Image
3156  *blur_image;
3157 
3159  status;
3160 
3162  progress;
3163 
3164  PointInfo
3165  blur_center;
3166 
3167  size_t
3168  n;
3169 
3170  ssize_t
3171  w,
3172  y;
3173 
3174  /*
3175  Allocate blur image.
3176  */
3177  assert(image != (Image *) NULL);
3178  assert(image->signature == MagickCoreSignature);
3179  if (image->debug != MagickFalse)
3180  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3181  assert(exception != (ExceptionInfo *) NULL);
3182  assert(exception->signature == MagickCoreSignature);
3183 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3184  blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3185  if (blur_image != (Image *) NULL)
3186  return(blur_image);
3187 #endif
3188  blur_image=CloneImage(image,0,0,MagickTrue,exception);
3189  if (blur_image == (Image *) NULL)
3190  return((Image *) NULL);
3191  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3192  {
3193  blur_image=DestroyImage(blur_image);
3194  return((Image *) NULL);
3195  }
3196  blur_center.x=(double) (image->columns-1)/2.0;
3197  blur_center.y=(double) (image->rows-1)/2.0;
3198  blur_radius=hypot(blur_center.x,blur_center.y);
3199  n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
3200  theta=DegreesToRadians(angle)/(double) (n-1);
3201  cos_theta=(double *) AcquireQuantumMemory((size_t) n,sizeof(*cos_theta));
3202  sin_theta=(double *) AcquireQuantumMemory((size_t) n,sizeof(*sin_theta));
3203  if ((cos_theta == (double *) NULL) || (sin_theta == (double *) NULL))
3204  {
3205  if (cos_theta != (double *) NULL)
3206  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
3207  if (sin_theta != (double *) NULL)
3208  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
3209  blur_image=DestroyImage(blur_image);
3210  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3211  }
3212  offset=theta*(double) (n-1)/2.0;
3213  for (w=0; w < (ssize_t) n; w++)
3214  {
3215  cos_theta[w]=cos((double) (theta*w-offset));
3216  sin_theta[w]=sin((double) (theta*w-offset));
3217  }
3218  /*
3219  Radial blur image.
3220  */
3221  status=MagickTrue;
3222  progress=0;
3223  image_view=AcquireVirtualCacheView(image,exception);
3224  radial_view=AcquireVirtualCacheView(image,exception);
3225  blur_view=AcquireAuthenticCacheView(blur_image,exception);
3226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3227  #pragma omp parallel for schedule(static) shared(progress,status) \
3228  magick_number_threads(image,blur_image,image->rows,1)
3229 #endif
3230  for (y=0; y < (ssize_t) image->rows; y++)
3231  {
3232  const Quantum
3233  *magick_restrict p;
3234 
3235  Quantum
3236  *magick_restrict q;
3237 
3238  ssize_t
3239  x;
3240 
3241  if (status == MagickFalse)
3242  continue;
3243  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3244  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3245  exception);
3246  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3247  {
3248  status=MagickFalse;
3249  continue;
3250  }
3251  for (x=0; x < (ssize_t) image->columns; x++)
3252  {
3253  double
3254  radius;
3255 
3256  PointInfo
3257  center;
3258 
3259  ssize_t
3260  i;
3261 
3262  size_t
3263  step;
3264 
3265  center.x=(double) x-blur_center.x;
3266  center.y=(double) y-blur_center.y;
3267  radius=hypot((double) center.x,center.y);
3268  if (radius == 0)
3269  step=1;
3270  else
3271  {
3272  step=(size_t) (blur_radius/radius);
3273  if (step == 0)
3274  step=1;
3275  else
3276  if (step >= n)
3277  step=n-1;
3278  }
3279  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3280  {
3281  double
3282  gamma,
3283  pixel;
3284 
3285  PixelChannel
3286  channel;
3287 
3288  PixelTrait
3289  blur_traits,
3290  traits;
3291 
3292  const Quantum
3293  *magick_restrict r;
3294 
3295  ssize_t
3296  j;
3297 
3298  channel=GetPixelChannelChannel(image,i);
3299  traits=GetPixelChannelTraits(image,channel);
3300  blur_traits=GetPixelChannelTraits(blur_image,channel);
3301  if ((traits == UndefinedPixelTrait) ||
3302  (blur_traits == UndefinedPixelTrait))
3303  continue;
3304  if ((blur_traits & CopyPixelTrait) != 0)
3305  {
3306  SetPixelChannel(blur_image,channel,p[i],q);
3307  continue;
3308  }
3309  gamma=0.0;
3310  pixel=0.0;
3312  (channel == AlphaPixelChannel))
3313  {
3314  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3315  {
3316  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3317  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3318  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3319  1,1,exception);
3320  if (r == (const Quantum *) NULL)
3321  {
3322  status=MagickFalse;
3323  continue;
3324  }
3325  pixel+=r[i];
3326  gamma++;
3327  }
3328  gamma=PerceptibleReciprocal(gamma);
3329  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3330  continue;
3331  }
3332  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3333  {
3334  double
3335  alpha;
3336 
3337  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3338  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3339  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3340  1,1,exception);
3341  if (r == (const Quantum *) NULL)
3342  {
3343  status=MagickFalse;
3344  continue;
3345  }
3346  alpha=(double) QuantumScale*GetPixelAlpha(image,r);
3347  pixel+=alpha*r[i];
3348  gamma+=alpha;
3349  }
3350  gamma=PerceptibleReciprocal(gamma);
3351  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3352  }
3353  p+=GetPixelChannels(image);
3354  q+=GetPixelChannels(blur_image);
3355  }
3356  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3357  status=MagickFalse;
3358  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3359  {
3361  proceed;
3362 
3363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3364  #pragma omp atomic
3365 #endif
3366  progress++;
3367  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3368  if (proceed == MagickFalse)
3369  status=MagickFalse;
3370  }
3371  }
3372  blur_view=DestroyCacheView(blur_view);
3373  radial_view=DestroyCacheView(radial_view);
3374  image_view=DestroyCacheView(image_view);
3375  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
3376  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
3377  if (status == MagickFalse)
3378  blur_image=DestroyImage(blur_image);
3379  return(blur_image);
3380 }
3381 
3382 /*
3383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 % %
3385 % %
3386 % %
3387 % S e l e c t i v e B l u r I m a g e %
3388 % %
3389 % %
3390 % %
3391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392 %
3393 % SelectiveBlurImage() selectively blur pixels within a contrast threshold.
3394 % It is similar to the unsharpen mask that sharpens everything with contrast
3395 % above a certain threshold.
3396 %
3397 % The format of the SelectiveBlurImage method is:
3398 %
3399 % Image *SelectiveBlurImage(const Image *image,const double radius,
3400 % const double sigma,const double threshold,ExceptionInfo *exception)
3401 %
3402 % A description of each parameter follows:
3403 %
3404 % o image: the image.
3405 %
3406 % o radius: the radius of the Gaussian, in pixels, not counting the center
3407 % pixel.
3408 %
3409 % o sigma: the standard deviation of the Gaussian, in pixels.
3410 %
3411 % o threshold: only pixels within this contrast threshold are included
3412 % in the blur operation.
3413 %
3414 % o exception: return any errors or warnings in this structure.
3415 %
3416 */
3417 MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
3418  const double sigma,const double threshold,ExceptionInfo *exception)
3419 {
3420 #define SelectiveBlurImageTag "SelectiveBlur/Image"
3421 
3422  CacheView
3423  *blur_view,
3424  *image_view,
3425  *luminance_view;
3426 
3427  Image
3428  *blur_image,
3429  *luminance_image;
3430 
3432  status;
3433 
3435  progress;
3436 
3438  *kernel;
3439 
3440  size_t
3441  width;
3442 
3443  ssize_t
3444  center,
3445  y;
3446 
3447  /*
3448  Initialize blur image attributes.
3449  */
3450  assert(image != (Image *) NULL);
3451  assert(image->signature == MagickCoreSignature);
3452  if (image->debug != MagickFalse)
3453  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3454  assert(exception != (ExceptionInfo *) NULL);
3455  assert(exception->signature == MagickCoreSignature);
3456  width=GetOptimalKernelWidth1D(radius,sigma);
3458  width,width*sizeof(*kernel)));
3459  if (kernel == (MagickRealType *) NULL)
3460  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3461  {
3462  ssize_t
3463  i,
3464  j,
3465  v;
3466 
3467  j=(ssize_t) (width-1)/2;
3468  i=0;
3469  for (v=(-j); v <= j; v++)
3470  {
3471  ssize_t
3472  u;
3473 
3474  for (u=(-j); u <= j; u++)
3475  kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
3477  }
3478  }
3479  if (image->debug != MagickFalse)
3480  {
3481  char
3482  format[MagickPathExtent],
3483  *message;
3484 
3485  const MagickRealType
3486  *k;
3487 
3488  ssize_t
3489  u,
3490  v;
3491 
3493  " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
3494  width);
3495  message=AcquireString("");
3496  k=kernel;
3497  for (v=0; v < (ssize_t) width; v++)
3498  {
3499  *message='\0';
3500  (void) FormatLocaleString(format,MagickPathExtent,"%.20g: ",(double) v);
3501  (void) ConcatenateString(&message,format);
3502  for (u=0; u < (ssize_t) width; u++)
3503  {
3504  (void) FormatLocaleString(format,MagickPathExtent,"%+f ",(double)
3505  *k++);
3506  (void) ConcatenateString(&message,format);
3507  }
3508  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
3509  }
3510  message=DestroyString(message);
3511  }
3512  blur_image=CloneImage(image,0,0,MagickTrue,exception);
3513  if (blur_image == (Image *) NULL)
3514  return((Image *) NULL);
3515  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3516  {
3517  blur_image=DestroyImage(blur_image);
3518  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3519  return((Image *) NULL);
3520  }
3521  luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3522  if (luminance_image == (Image *) NULL)
3523  {
3524  blur_image=DestroyImage(blur_image);
3525  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3526  return((Image *) NULL);
3527  }
3528  status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3529  if (status == MagickFalse)
3530  {
3531  luminance_image=DestroyImage(luminance_image);
3532  blur_image=DestroyImage(blur_image);
3533  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3534  return((Image *) NULL);
3535  }
3536  /*
3537  Threshold blur image.
3538  */
3539  status=MagickTrue;
3540  progress=0;
3541  center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3542  ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3543  image_view=AcquireVirtualCacheView(image,exception);
3544  luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3545  blur_view=AcquireAuthenticCacheView(blur_image,exception);
3546 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3547  #pragma omp parallel for schedule(static) shared(progress,status) \
3548  magick_number_threads(image,blur_image,image->rows,1)
3549 #endif
3550  for (y=0; y < (ssize_t) image->rows; y++)
3551  {
3552  double
3553  contrast;
3554 
3556  sync;
3557 
3558  const Quantum
3559  *magick_restrict l,
3560  *magick_restrict p;
3561 
3562  Quantum
3563  *magick_restrict q;
3564 
3565  ssize_t
3566  x;
3567 
3568  if (status == MagickFalse)
3569  continue;
3570  p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3571  ((width-1)/2L),image->columns+width,width,exception);
3572  l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3573  (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3574  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3575  exception);
3576  if ((p == (const Quantum *) NULL) || (l == (const Quantum *) NULL) ||
3577  (q == (Quantum *) NULL))
3578  {
3579  status=MagickFalse;
3580  continue;
3581  }
3582  for (x=0; x < (ssize_t) image->columns; x++)
3583  {
3584  double
3585  intensity;
3586 
3587  ssize_t
3588  i;
3589 
3590  intensity=GetPixelIntensity(image,p+center);
3591  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3592  {
3593  double
3594  alpha,
3595  gamma,
3596  pixel;
3597 
3598  PixelChannel
3599  channel;
3600 
3601  PixelTrait
3602  blur_traits,
3603  traits;
3604 
3605  const MagickRealType
3606  *magick_restrict k;
3607 
3608  const Quantum
3609  *magick_restrict luminance_pixels,
3610  *magick_restrict pixels;
3611 
3612  ssize_t
3613  u;
3614 
3615  ssize_t
3616  v;
3617 
3618  channel=GetPixelChannelChannel(image,i);
3619  traits=GetPixelChannelTraits(image,channel);
3620  blur_traits=GetPixelChannelTraits(blur_image,channel);
3621  if ((traits == UndefinedPixelTrait) ||
3622  (blur_traits == UndefinedPixelTrait))
3623  continue;
3624  if ((blur_traits & CopyPixelTrait) != 0)
3625  {
3626  SetPixelChannel(blur_image,channel,p[center+i],q);
3627  continue;
3628  }
3629  k=kernel;
3630  pixel=0.0;
3631  pixels=p;
3632  luminance_pixels=l;
3633  gamma=0.0;
3634  if ((blur_traits & BlendPixelTrait) == 0)
3635  {
3636  for (v=0; v < (ssize_t) width; v++)
3637  {
3638  for (u=0; u < (ssize_t) width; u++)
3639  {
3640  contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3641  intensity;
3642  if (fabs(contrast) < threshold)
3643  {
3644  pixel+=(*k)*pixels[i];
3645  gamma+=(*k);
3646  }
3647  k++;
3648  pixels+=GetPixelChannels(image);
3649  luminance_pixels+=GetPixelChannels(luminance_image);
3650  }
3651  pixels+=GetPixelChannels(image)*image->columns;
3652  luminance_pixels+=GetPixelChannels(luminance_image)*
3653  luminance_image->columns;
3654  }
3655  if (fabs((double) gamma) < MagickEpsilon)
3656  {
3657  SetPixelChannel(blur_image,channel,p[center+i],q);
3658  continue;
3659  }
3660  gamma=PerceptibleReciprocal(gamma);
3661  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3662  continue;
3663  }
3664  for (v=0; v < (ssize_t) width; v++)
3665  {
3666  for (u=0; u < (ssize_t) width; u++)
3667  {
3668  contrast=GetPixelIntensity(image,pixels)-intensity;
3669  if (fabs(contrast) < threshold)
3670  {
3671  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
3672  pixel+=(*k)*alpha*pixels[i];
3673  gamma+=(*k)*alpha;
3674  }
3675  k++;
3676  pixels+=GetPixelChannels(image);
3677  luminance_pixels+=GetPixelChannels(luminance_image);
3678  }
3679  pixels+=GetPixelChannels(image)*image->columns;
3680  luminance_pixels+=GetPixelChannels(luminance_image)*
3681  luminance_image->columns;
3682  }
3683  if (fabs((double) gamma) < MagickEpsilon)
3684  {
3685  SetPixelChannel(blur_image,channel,p[center+i],q);
3686  continue;
3687  }
3688  gamma=PerceptibleReciprocal(gamma);
3689  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3690  }
3691  p+=GetPixelChannels(image);
3692  l+=GetPixelChannels(luminance_image);
3693  q+=GetPixelChannels(blur_image);
3694  }
3695  sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3696  if (sync == MagickFalse)
3697  status=MagickFalse;
3698  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3699  {
3701  proceed;
3702 
3703 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3704  #pragma omp atomic
3705 #endif
3706  progress++;
3707  proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3708  image->rows);
3709  if (proceed == MagickFalse)
3710  status=MagickFalse;
3711  }
3712  }
3713  blur_image->type=image->type;
3714  blur_view=DestroyCacheView(blur_view);
3715  luminance_view=DestroyCacheView(luminance_view);
3716  image_view=DestroyCacheView(image_view);
3717  luminance_image=DestroyImage(luminance_image);
3718  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3719  if (status == MagickFalse)
3720  blur_image=DestroyImage(blur_image);
3721  return(blur_image);
3722 }
3723 
3724 /*
3725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726 % %
3727 % %
3728 % %
3729 % S h a d e I m a g e %
3730 % %
3731 % %
3732 % %
3733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3734 %
3735 % ShadeImage() shines a distant light on an image to create a
3736 % three-dimensional effect. You control the positioning of the light with
3737 % azimuth and elevation; azimuth is measured in degrees off the x axis
3738 % and elevation is measured in pixels above the Z axis.
3739 %
3740 % The format of the ShadeImage method is:
3741 %
3742 % Image *ShadeImage(const Image *image,const MagickBooleanType gray,
3743 % const double azimuth,const double elevation,ExceptionInfo *exception)
3744 %
3745 % A description of each parameter follows:
3746 %
3747 % o image: the image.
3748 %
3749 % o gray: A value other than zero shades the intensity of each pixel.
3750 %
3751 % o azimuth, elevation: Define the light source direction.
3752 %
3753 % o exception: return any errors or warnings in this structure.
3754 %
3755 */
3757  const double azimuth,const double elevation,ExceptionInfo *exception)
3758 {
3759 #define GetShadeIntensity(image,pixel) \
3760  ClampPixel(GetPixelIntensity((image),(pixel)))
3761 #define ShadeImageTag "Shade/Image"
3762 
3763  CacheView
3764  *image_view,
3765  *shade_view;
3766 
3767  Image
3768  *linear_image,
3769  *shade_image;
3770 
3772  status;
3773 
3775  progress;
3776 
3777  PrimaryInfo
3778  light;
3779 
3780  ssize_t
3781  y;
3782 
3783  /*
3784  Initialize shaded image attributes.
3785  */
3786  assert(image != (const Image *) NULL);
3787  assert(image->signature == MagickCoreSignature);
3788  if (image->debug != MagickFalse)
3789  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3790  assert(exception != (ExceptionInfo *) NULL);
3791  assert(exception->signature == MagickCoreSignature);
3792  linear_image=CloneImage(image,0,0,MagickTrue,exception);
3793  shade_image=CloneImage(image,0,0,MagickTrue,exception);
3794  if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
3795  {
3796  if (linear_image != (Image *) NULL)
3797  linear_image=DestroyImage(linear_image);
3798  if (shade_image != (Image *) NULL)
3799  shade_image=DestroyImage(shade_image);
3800  return((Image *) NULL);
3801  }
3802  if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3803  {
3804  linear_image=DestroyImage(linear_image);
3805  shade_image=DestroyImage(shade_image);
3806  return((Image *) NULL);
3807  }
3808  /*
3809  Compute the light vector.
3810  */
3811  light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3812  cos(DegreesToRadians(elevation));
3813  light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3814  cos(DegreesToRadians(elevation));
3815  light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3816  /*
3817  Shade image.
3818  */
3819  status=MagickTrue;
3820  progress=0;
3821  image_view=AcquireVirtualCacheView(linear_image,exception);
3822  shade_view=AcquireAuthenticCacheView(shade_image,exception);
3823 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3824  #pragma omp parallel for schedule(static) shared(progress,status) \
3825  magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3826 #endif
3827  for (y=0; y < (ssize_t) linear_image->rows; y++)
3828  {
3829  double
3830  distance,
3831  normal_distance,
3832  shade;
3833 
3834  PrimaryInfo
3835  normal;
3836 
3837  const Quantum
3838  *magick_restrict center,
3839  *magick_restrict p,
3840  *magick_restrict post,
3841  *magick_restrict pre;
3842 
3843  Quantum
3844  *magick_restrict q;
3845 
3846  ssize_t
3847  x;
3848 
3849  if (status == MagickFalse)
3850  continue;
3851  p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3852  exception);
3853  q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3854  exception);
3855  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3856  {
3857  status=MagickFalse;
3858  continue;
3859  }
3860  /*
3861  Shade this row of pixels.
3862  */
3863  normal.z=2.0*(double) QuantumRange; /* constant Z of surface normal */
3864  for (x=0; x < (ssize_t) linear_image->columns; x++)
3865  {
3866  ssize_t
3867  i;
3868 
3869  /*
3870  Determine the surface normal and compute shading.
3871  */
3872  pre=p+GetPixelChannels(linear_image);
3873  center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3874  post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3875  normal.x=(double) (
3876  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3877  GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3878  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3879  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3880  GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3881  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3882  normal.y=(double) (
3883  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3884  GetShadeIntensity(linear_image,post)+
3885  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3886  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3887  GetShadeIntensity(linear_image,pre)-
3888  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3889  if ((fabs(normal.x) <= MagickEpsilon) &&
3890  (fabs(normal.y) <= MagickEpsilon))
3891  shade=light.z;
3892  else
3893  {
3894  shade=0.0;
3895  distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3896  if (distance > MagickEpsilon)
3897  {
3898  normal_distance=normal.x*normal.x+normal.y*normal.y+
3899  normal.z*normal.z;
3900  if (normal_distance > (MagickEpsilon*MagickEpsilon))
3901  shade=distance/sqrt((double) normal_distance);
3902  }
3903  }
3904  for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3905  {
3906  PixelChannel
3907  channel;
3908 
3909  PixelTrait
3910  shade_traits,
3911  traits;
3912 
3913  channel=GetPixelChannelChannel(linear_image,i);
3914  traits=GetPixelChannelTraits(linear_image,channel);
3915  shade_traits=GetPixelChannelTraits(shade_image,channel);
3916  if ((traits == UndefinedPixelTrait) ||
3917  (shade_traits == UndefinedPixelTrait))
3918  continue;
3919  if ((shade_traits & CopyPixelTrait) != 0)
3920  {
3921  SetPixelChannel(shade_image,channel,center[i],q);
3922  continue;
3923  }
3924  if ((traits & UpdatePixelTrait) == 0)
3925  {
3926  SetPixelChannel(shade_image,channel,center[i],q);
3927  continue;
3928  }
3929  if (gray != MagickFalse)
3930  {
3931  SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3932  continue;
3933  }
3934  SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
3935  center[i]),q);
3936  }
3937  p+=GetPixelChannels(linear_image);
3938  q+=GetPixelChannels(shade_image);
3939  }
3940  if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3941  status=MagickFalse;
3942  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3943  {
3945  proceed;
3946 
3947 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3948  #pragma omp atomic
3949 #endif
3950  progress++;
3951  proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3952  if (proceed == MagickFalse)
3953  status=MagickFalse;
3954  }
3955  }
3956  shade_view=DestroyCacheView(shade_view);
3957  image_view=DestroyCacheView(image_view);
3958  linear_image=DestroyImage(linear_image);
3959  if (status == MagickFalse)
3960  shade_image=DestroyImage(shade_image);
3961  return(shade_image);
3962 }
3963 
3964 /*
3965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3966 % %
3967 % %
3968 % %
3969 % S h a r p e n I m a g e %
3970 % %
3971 % %
3972 % %
3973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3974 %
3975 % SharpenImage() sharpens the image. We convolve the image with a Gaussian
3976 % operator of the given radius and standard deviation (sigma). For
3977 % reasonable results, radius should be larger than sigma. Use a radius of 0
3978 % and SharpenImage() selects a suitable radius for you.
3979 %
3980 % Using a separable kernel would be faster, but the negative weights cancel
3981 % out on the corners of the kernel producing often undesirable ringing in the
3982 % filtered result; this can be avoided by using a 2D gaussian shaped image
3983 % sharpening kernel instead.
3984 %
3985 % The format of the SharpenImage method is:
3986 %
3987 % Image *SharpenImage(const Image *image,const double radius,
3988 % const double sigma,ExceptionInfo *exception)
3989 %
3990 % A description of each parameter follows:
3991 %
3992 % o image: the image.
3993 %
3994 % o radius: the radius of the Gaussian, in pixels, not counting the center
3995 % pixel.
3996 %
3997 % o sigma: the standard deviation of the Laplacian, in pixels.
3998 %
3999 % o exception: return any errors or warnings in this structure.
4000 %
4001 */
4002 MagickExport Image *SharpenImage(const Image *image,const double radius,
4003  const double sigma,ExceptionInfo *exception)
4004 {
4005  double
4006  gamma,
4007  normalize;
4008 
4009  Image
4010  *sharp_image;
4011 
4012  KernelInfo
4013  *kernel_info;
4014 
4015  ssize_t
4016  i;
4017 
4018  size_t
4019  width;
4020 
4021  ssize_t
4022  j,
4023  u,
4024  v;
4025 
4026  assert(image != (const Image *) NULL);
4027  assert(image->signature == MagickCoreSignature);
4028  if (image->debug != MagickFalse)
4029  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4030  assert(exception != (ExceptionInfo *) NULL);
4031  assert(exception->signature == MagickCoreSignature);
4032  width=GetOptimalKernelWidth2D(radius,sigma);
4033  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
4034  if (kernel_info == (KernelInfo *) NULL)
4035  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
4036  (void) memset(kernel_info,0,sizeof(*kernel_info));
4037  kernel_info->width=width;
4038  kernel_info->height=width;
4039  kernel_info->x=(ssize_t) (width-1)/2;
4040  kernel_info->y=(ssize_t) (width-1)/2;
4041  kernel_info->signature=MagickCoreSignature;
4042  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4043  AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4044  sizeof(*kernel_info->values)));
4045  if (kernel_info->values == (MagickRealType *) NULL)
4046  {
4047  kernel_info=DestroyKernelInfo(kernel_info);
4048  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
4049  }
4050  normalize=0.0;
4051  j=(ssize_t) (kernel_info->width-1)/2;
4052  i=0;
4053  for (v=(-j); v <= j; v++)
4054  {
4055  for (u=(-j); u <= j; u++)
4056  {
4057  kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
4059  normalize+=kernel_info->values[i];
4060  i++;
4061  }
4062  }
4063  kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4064  normalize=0.0;
4065  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4066  normalize+=kernel_info->values[i];
4067  gamma=PerceptibleReciprocal(normalize);
4068  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4069  kernel_info->values[i]*=gamma;
4070  sharp_image=ConvolveImage(image,kernel_info,exception);
4071  kernel_info=DestroyKernelInfo(kernel_info);
4072  return(sharp_image);
4073 }
4074 
4075 /*
4076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077 % %
4078 % %
4079 % %
4080 % S p r e a d I m a g e %
4081 % %
4082 % %
4083 % %
4084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4085 %
4086 % SpreadImage() is a special effects method that randomly displaces each
4087 % pixel in a square area defined by the radius parameter.
4088 %
4089 % The format of the SpreadImage method is:
4090 %
4091 % Image *SpreadImage(const Image *image,
4092 % const PixelInterpolateMethod method,const double radius,
4093 % ExceptionInfo *exception)
4094 %
4095 % A description of each parameter follows:
4096 %
4097 % o image: the image.
4098 %
4099 % o method: intepolation method.
4100 %
4101 % o radius: choose a random pixel in a neighborhood of this extent.
4102 %
4103 % o exception: return any errors or warnings in this structure.
4104 %
4105 */
4107  const PixelInterpolateMethod method,const double radius,
4108  ExceptionInfo *exception)
4109 {
4110 #define SpreadImageTag "Spread/Image"
4111 
4112  CacheView
4113  *image_view,
4114  *spread_view;
4115 
4116  Image
4117  *spread_image;
4118 
4120  status;
4121 
4123  progress;
4124 
4125  RandomInfo
4127 
4128  size_t
4129  width;
4130 
4131  ssize_t
4132  y;
4133 
4134 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4135  unsigned long
4136  key;
4137 #endif
4138 
4139  /*
4140  Initialize spread image attributes.
4141  */
4142  assert(image != (Image *) NULL);
4143  assert(image->signature == MagickCoreSignature);
4144  if (image->debug != MagickFalse)
4145  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4146  assert(exception != (ExceptionInfo *) NULL);
4147  assert(exception->signature == MagickCoreSignature);
4148  spread_image=CloneImage(image,0,0,MagickTrue,exception);
4149  if (spread_image == (Image *) NULL)
4150  return((Image *) NULL);
4151  if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4152  {
4153  spread_image=DestroyImage(spread_image);
4154  return((Image *) NULL);
4155  }
4156  /*
4157  Spread image.
4158  */
4159  status=MagickTrue;
4160  progress=0;
4161  width=GetOptimalKernelWidth1D(radius,0.5);
4163  image_view=AcquireVirtualCacheView(image,exception);
4164  spread_view=AcquireAuthenticCacheView(spread_image,exception);
4165 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4167  #pragma omp parallel for schedule(static) shared(progress,status) \
4168  magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4169 #endif
4170  for (y=0; y < (ssize_t) image->rows; y++)
4171  {
4172  const int
4173  id = GetOpenMPThreadId();
4174 
4175  Quantum
4176  *magick_restrict q;
4177 
4178  ssize_t
4179  x;
4180 
4181  if (status == MagickFalse)
4182  continue;
4183  q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4184  exception);
4185  if (q == (Quantum *) NULL)
4186  {
4187  status=MagickFalse;
4188  continue;
4189  }
4190  for (x=0; x < (ssize_t) image->columns; x++)
4191  {
4192  PointInfo
4193  point;
4194 
4195  point.x=GetPseudoRandomValue(random_info[id]);
4196  point.y=GetPseudoRandomValue(random_info[id]);
4197  status=InterpolatePixelChannels(image,image_view,spread_image,method,
4198  (double) x+width*(point.x-0.5),(double) y+width*(point.y-0.5),q,
4199  exception);
4200  if (status == MagickFalse)
4201  break;
4202  q+=GetPixelChannels(spread_image);
4203  }
4204  if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4205  status=MagickFalse;
4206  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4207  {
4209  proceed;
4210 
4211 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4212  #pragma omp atomic
4213 #endif
4214  progress++;
4215  proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4216  if (proceed == MagickFalse)
4217  status=MagickFalse;
4218  }
4219  }
4220  spread_view=DestroyCacheView(spread_view);
4221  image_view=DestroyCacheView(image_view);
4223  if (status == MagickFalse)
4224  spread_image=DestroyImage(spread_image);
4225  return(spread_image);
4226 }
4227 
4228 /*
4229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4230 % %
4231 % %
4232 % %
4233 % U n s h a r p M a s k I m a g e %
4234 % %
4235 % %
4236 % %
4237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238 %
4239 % UnsharpMaskImage() sharpens one or more image channels. We convolve the
4240 % image with a Gaussian operator of the given radius and standard deviation
4241 % (sigma). For reasonable results, radius should be larger than sigma. Use a
4242 % radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
4243 %
4244 % The format of the UnsharpMaskImage method is:
4245 %
4246 % Image *UnsharpMaskImage(const Image *image,const double radius,
4247 % const double sigma,const double amount,const double threshold,
4248 % ExceptionInfo *exception)
4249 %
4250 % A description of each parameter follows:
4251 %
4252 % o image: the image.
4253 %
4254 % o radius: the radius of the Gaussian, in pixels, not counting the center
4255 % pixel.
4256 %
4257 % o sigma: the standard deviation of the Gaussian, in pixels.
4258 %
4259 % o gain: the percentage of the difference between the original and the
4260 % blur image that is added back into the original.
4261 %
4262 % o threshold: the threshold in pixels needed to apply the diffence gain.
4263 %
4264 % o exception: return any errors or warnings in this structure.
4265 %
4266 */
4267 MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
4268  const double sigma,const double gain,const double threshold,
4269  ExceptionInfo *exception)
4270 {
4271 #define SharpenImageTag "Sharpen/Image"
4272 
4273  CacheView
4274  *image_view,
4275  *unsharp_view;
4276 
4277  Image
4278  *unsharp_image;
4279 
4281  status;
4282 
4284  progress;
4285 
4286  double
4287  quantum_threshold;
4288 
4289  ssize_t
4290  y;
4291 
4292  assert(image != (const Image *) NULL);
4293  assert(image->signature == MagickCoreSignature);
4294  if (image->debug != MagickFalse)
4295  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4296  assert(exception != (ExceptionInfo *) NULL);
4297 /* This kernel appears to be broken.
4298 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4299  unsharp_image=AccelerateUnsharpMaskImage(image,radius,sigma,gain,threshold,
4300  exception);
4301  if (unsharp_image != (Image *) NULL)
4302  return(unsharp_image);
4303 #endif
4304 */
4305  unsharp_image=BlurImage(image,radius,sigma,exception);
4306  if (unsharp_image == (Image *) NULL)
4307  return((Image *) NULL);
4308  quantum_threshold=(double) QuantumRange*threshold;
4309  /*
4310  Unsharp-mask image.
4311  */
4312  status=MagickTrue;
4313  progress=0;
4314  image_view=AcquireVirtualCacheView(image,exception);
4315  unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4316 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4317  #pragma omp parallel for schedule(static) shared(progress,status) \
4318  magick_number_threads(image,unsharp_image,image->rows,1)
4319 #endif
4320  for (y=0; y < (ssize_t) image->rows; y++)
4321  {
4322  const Quantum
4323  *magick_restrict p;
4324 
4325  Quantum
4326  *magick_restrict q;
4327 
4328  ssize_t
4329  x;
4330 
4331  if (status == MagickFalse)
4332  continue;
4333  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4334  q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4335  exception);
4336  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4337  {
4338  status=MagickFalse;
4339  continue;
4340  }
4341  for (x=0; x < (ssize_t) image->columns; x++)
4342  {
4343  ssize_t
4344  i;
4345 
4346  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4347  {
4348  double
4349  pixel;
4350 
4351  PixelChannel
4352  channel;
4353 
4354  PixelTrait
4355  traits,
4356  unsharp_traits;
4357 
4358  channel=GetPixelChannelChannel(image,i);
4359  traits=GetPixelChannelTraits(image,channel);
4360  unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4361  if ((traits == UndefinedPixelTrait) ||
4362  (unsharp_traits == UndefinedPixelTrait))
4363  continue;
4364  if ((unsharp_traits & CopyPixelTrait) != 0)
4365  {
4366  SetPixelChannel(unsharp_image,channel,p[i],q);
4367  continue;
4368  }
4369  pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
4370  if (fabs(2.0*pixel) < quantum_threshold)
4371  pixel=(double) p[i];
4372  else
4373  pixel=(double) p[i]+gain*pixel;
4374  SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4375  }
4376  p+=GetPixelChannels(image);
4377  q+=GetPixelChannels(unsharp_image);
4378  }
4379  if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4380  status=MagickFalse;
4381  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4382  {
4384  proceed;
4385 
4386 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4387  #pragma omp atomic
4388 #endif
4389  progress++;
4390  proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4391  if (proceed == MagickFalse)
4392  status=MagickFalse;
4393  }
4394  }
4395  unsharp_image->type=image->type;
4396  unsharp_view=DestroyCacheView(unsharp_view);
4397  image_view=DestroyCacheView(image_view);
4398  if (status == MagickFalse)
4399  unsharp_image=DestroyImage(unsharp_image);
4400  return(unsharp_image);
4401 }
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport Image * SelectiveBlurImage(const Image *image, const double radius, const double sigma, const double threshold, ExceptionInfo *exception)
Definition: effect.c:3417
MagickExport Image * BlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:770
PixelInfo matte_color
Definition: image.h:357
MagickDoubleType MagickRealType
Definition: magick-type.h:124
#define DefaultTileLabel
Definition: image-private.h:30
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
MagickExport Image * MotionBlurImage(const Image *image, const double radius, const double sigma, const double angle, ExceptionInfo *exception)
Definition: effect.c:2353
#define BlurImageTag
MagickExport MemoryInfo * RelinquishVirtualMemory(MemoryInfo *memory_info)
Definition: memory.c:1229
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:327
#define PreviewImageTag
MagickExport Image * MontageImages(const Image *images, const MontageInfo *montage_info, ExceptionInfo *exception)
Definition: montage.c:306
MagickProgressMonitor progress_monitor
Definition: image.h:303
ImageType type
Definition: image.h:264
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType TransformImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1609
#define MagickAssumeAligned(address)
ssize_t y
Definition: geometry.h:117
static MagickRealType GetMeanLuma(const Image *magick_restrict image, const double *magick_restrict pixel)
Definition: effect.c:1776
char * geometry
Definition: montage.h:36
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
char * tile
Definition: montage.h:36
ColorspaceType colorspace
Definition: quantize.h:44
MagickExport Image * ShadeImage(const Image *image, const MagickBooleanType gray, const double azimuth, const double elevation, ExceptionInfo *exception)
Definition: effect.c:3756
MagickExport Image * UnsharpMaskImage(const Image *image, const double radius, const double sigma, const double gain, const double threshold, ExceptionInfo *exception)
Definition: effect.c:4267
MagickExport Image * BilateralBlurImage(const Image *image, const size_t width, const size_t height, const double intensity_sigma, const double spatial_sigma, ExceptionInfo *exception)
Definition: effect.c:899
size_t height
Definition: morphology.h:108
MagickExport MagickBooleanType RaiseImage(Image *image, const RectangleInfo *raise_info, const MagickBooleanType raise, ExceptionInfo *exception)
Definition: decorate.c:617
PixelInterpolateMethod
Definition: pixel.h:113
MagickExport KernelInfo * DestroyKernelInfo(KernelInfo *kernel)
Definition: morphology.c:2269
PixelInterpolateMethod interpolate
Definition: image.h:255
double x
Definition: image.h:99
MagickExport MemoryInfo * AcquireVirtualMemory(const size_t count, const size_t quantum)
Definition: memory.c:705
MagickExport Image * AdaptiveSharpenImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:450
size_t signature
Definition: exception.h:123
static size_t GetOpenMPMaximumThreads(void)
MagickExport Image * MorphologyImage(const Image *image, const MorphologyMethod method, const ssize_t iterations, const KernelInfo *kernel, ExceptionInfo *exception)
Definition: morphology.c:4138
MagickExport Image * PreviewImage(const Image *image, const PreviewType preview, ExceptionInfo *exception)
Definition: effect.c:2604
static Quantum GetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum *magick_restrict pixel)
static double ** AcquireBilateralThreadSet(const size_t number_threads, const size_t width, const size_t height)
Definition: effect.c:877
MagickExport MagickStatusType ParseMetaGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:1379
#define AdaptiveSharpenImageTag
MagickExport MagickBooleanType InterpolatePixelChannels(const Image *magick_restrict source, const CacheView_ *source_view, const Image *magick_restrict destination, const PixelInterpolateMethod method, const double x, const double y, Quantum *pixel, ExceptionInfo *exception)
Definition: pixel.c:4908
PreviewType
Definition: effect.h:27
double z
Definition: image.h:99
static RandomInfo ** DestroyRandomInfoThreadSet(RandomInfo **random_info)
ssize_t x
Definition: morphology.h:112
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
#define MagickPI
Definition: image-private.h:40
MagickExport MagickBooleanType EqualizeImage(Image *image, ExceptionInfo *exception)
Definition: enhance.c:2033
MagickExport Image * RotationalBlurImage(const Image *image, const double angle, ExceptionInfo *exception)
Definition: effect.c:3140
#define GetShadeIntensity(image, pixel)
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:463
MagickPrivate size_t GetOptimalKernelWidth1D(const double, const double)
MagickExport size_t CopyMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:731
char magick[MagickPathExtent]
Definition: image.h:319
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
static RandomInfo ** AcquireRandomInfoThreadSet(void)
size_t signature
Definition: morphology.h:129
#define SharpenImageTag
static MagickRealType GetPixelLuma(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
char * montage
Definition: image.h:201
#define MagickEpsilon
Definition: magick-type.h:114
size_t width
Definition: geometry.h:131
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:133
MagickExport Image * ThumbnailImage(const Image *image, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: resize.c:4523
MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info)
Definition: random.c:715
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
Definition: image.h:151
MagickExport Image * ImplodeImage(const Image *image, const double amount, const PixelInterpolateMethod method, ExceptionInfo *exception)
#define DespeckleImageTag
MagickExport MagickBooleanType ContrastImage(Image *image, const MagickBooleanType sharpen, ExceptionInfo *exception)
Definition: enhance.c:1399
char * frame
Definition: montage.h:36
double x
Definition: geometry.h:124
MagickExport KernelInfo * AcquireKernelInfo(const char *kernel_string, ExceptionInfo *exception)
Definition: morphology.c:486
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
#define SpreadImageTag
MagickBooleanType
Definition: magick-type.h:165
MagickExport Image * NewImageList(void)
Definition: list.c:953
MagickExport char * AcquireString(const char *source)
Definition: string.c:94
static double PerceptibleReciprocal(const double x)
MagickExport int AcquireUniqueFileResource(char *path)
Definition: resource.c:551
MagickExport Image * LocalContrastImage(const Image *image, const double radius, const double strength, ExceptionInfo *exception)
Definition: effect.c:2022
MagickExport Image * SpreadImage(const Image *image, const PixelInterpolateMethod method, const double radius, ExceptionInfo *exception)
Definition: effect.c:4106
MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, Image *image, ExceptionInfo *exception)
Definition: constitute.c:1083
#define BilateralBlurImageTag
#define Magick2PI
Definition: image-private.h:34
char filename[MagickPathExtent]
Definition: montage.h:63
MagickExport MagickBooleanType SegmentImage(Image *image, const ColorspaceType colorspace, const MagickBooleanType verbose, const double cluster_threshold, const double smooth_threshold, ExceptionInfo *exception)
Definition: segment.c:1796
#define DefaultTileFrame
Definition: image-private.h:28
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:665
char filename[MagickPathExtent]
Definition: image.h:480
MagickPrivate size_t GetOptimalKernelWidth2D(const double, const double)
Definition: gem.c:1685
static double DegreesToRadians(const double degrees)
Definition: image-private.h:64
double y
Definition: geometry.h:124
static int GetOpenMPThreadId(void)
MagickExport MagickBooleanType ModulateImage(Image *image, const char *modulate, ExceptionInfo *exception)
Definition: enhance.c:3625
#define MagickSQ2PI
Definition: image-private.h:43
MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
Definition: resource.c:1098
MagickExport Image * EmbossImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1609
MagickExport MagickBooleanType SetImageProperty(Image *image, const char *property, const char *value, ExceptionInfo *exception)
Definition: property.c:4235
size_t number_colors
Definition: quantize.h:38
#define MagickSigma
static MagickRealType * GetMotionBlurKernel(const size_t width, const double sigma)
Definition: effect.c:2323
MagickExport Image * RollImage(const Image *image, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: transform.c:1532
#define MagickPathExtent
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport void * RelinquishAlignedMemory(void *memory)
Definition: memory.c:1120
PixelTrait alpha_trait
Definition: image.h:280
MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
Definition: quantize.c:2311
#define MagickMaximumValue
Definition: magick-type.h:115
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:429
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
#define NumberTiles
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info, Image *image, ExceptionInfo *exception)
Definition: quantize.c:3088
MagickExport Image * RotateImage(const Image *image, const double degrees, ExceptionInfo *exception)
Definition: distort.c:2950
size_t width
Definition: morphology.h:108
MagickExport Image * AdaptiveBlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:129
size_t signature
Definition: image.h:354
MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
Definition: resource.c:793
#define QuantumScale
Definition: magick-type.h:119
size_t columns
Definition: image.h:172
#define SelectiveBlurImageTag
ssize_t x
Definition: geometry.h:135
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport Image * DespeckleImage(const Image *image, ExceptionInfo *exception)
Definition: effect.c:1317
size_t height
Definition: geometry.h:131
MagickExport Image * SwirlImage(const Image *image, double degrees, const PixelInterpolateMethod method, ExceptionInfo *exception)
MagickExport MontageInfo * DestroyMontageInfo(MontageInfo *montage_info)
Definition: montage.c:164
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2265
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2614
MagickExport MagickProgressMonitor SetImageProgressMonitor(Image *image, const MagickProgressMonitor progress_monitor, void *client_data)
Definition: monitor.c:194
MagickExport Image * DestroyImageList(Image *images)
Definition: list.c:477
PixelChannel
Definition: pixel.h:70
MagickExport void * AcquireAlignedMemory(const size_t count, const size_t quantum)
Definition: memory.c:365
double y
Definition: image.h:99
#define MagickMax(x, y)
Definition: image-private.h:36
static size_t GetPixelChannels(const Image *magick_restrict image)
#define KuwaharaImageTag
static ssize_t CastDoubleToLong(const double value)
Definition: image-private.h:53
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
size_t quality
Definition: image.h:410
#define ThrowImageException(severity, tag)
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
MagickExport Image * ShearImage(const Image *image, const double x_shear, const double y_shear, ExceptionInfo *exception)
Definition: shear.c:1575
MagickExport MagickSizeType GetBlobSize(const Image *image)
Definition: blob.c:1844
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1248
static void Hull(const Image *image, const ssize_t x_offset, const ssize_t y_offset, const size_t columns, const size_t rows, const int polarity, Quantum *magick_restrict f, Quantum *magick_restrict g)
Definition: effect.c:1221
unsigned short Quantum
Definition: magick-type.h:86
MagickExport Image * KuwaharaImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1784
MagickExport char * DestroyString(char *string)
Definition: string.c:788
MagickExport MagickBooleanType DeleteImageProperty(Image *image, const char *property)
Definition: property.c:279
MagickExport double GetPseudoRandomValue(RandomInfo *magick_restrict random_info)
Definition: random.c:584
#define MaxIntensity
size_t number_channels
Definition: image.h:283
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
char * directory
Definition: image.h:201
MagickExport void AppendImageToList(Image **images, const Image *append)
Definition: list.c:80
MagickExport Image * CharcoalImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
MagickExport Image * ConvolveImage(const Image *image, const KernelInfo *kernel_info, ExceptionInfo *exception)
Definition: effect.c:1174
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1696
ssize_t x
Definition: geometry.h:117
MagickExport MagickBooleanType ConcatenateString(char **magick_restrict destination, const char *magick_restrict source)
Definition: string.c:458
MagickExport MagickBooleanType BilevelImage(Image *image, const double threshold, ExceptionInfo *exception)
Definition: threshold.c:807
static RandomInfo * random_info
Definition: resource.c:113
MagickExport Image * SharpenImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:4002
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1162
#define MaxPixelChannels
Definition: pixel.h:27
MagickBooleanType shadow
Definition: montage.h:50
MagickExport Image * WaveImage(const Image *image, const double amplitude, const double wave_length, const PixelInterpolateMethod method, ExceptionInfo *exception)
#define AdaptiveBlurImageTag
MagickExport MagickBooleanType GammaImage(Image *image, const double gamma, ExceptionInfo *exception)
Definition: enhance.c:2315
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:250
static void SetPixelRed(const Image *magick_restrict image, const Quantum red, Quantum *magick_restrict pixel)
#define ShadeImageTag
MagickExport MagickBooleanType AutoLevelImage(Image *image, ExceptionInfo *exception)
Definition: enhance.c:185
static double ** DestroyBilateralThreadSet(const ssize_t number_threads, double **weights)
Definition: effect.c:863
static double BlurDistance(const ssize_t x, const ssize_t y, const ssize_t u, const ssize_t v)
Definition: effect.c:851
#define MagickExport
ssize_t y
Definition: morphology.h:112
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:135
MagickExport MagickBooleanType SolarizeImage(Image *image, const double threshold, ExceptionInfo *exception)
MagickExport Image * OilPaintImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: paint.c:690
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
MagickExport Image * EdgeImage(const Image *image, const double radius, ExceptionInfo *exception)
Definition: effect.c:1529
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:137
MagickExport void * GetVirtualMemoryBlob(const MemoryInfo *memory_info)
Definition: memory.c:1090
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport MontageInfo * CloneMontageInfo(const ImageInfo *image_info, const MontageInfo *montage_info)
Definition: montage.c:104
#define DefaultPreviewGeometry
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1177
MagickExport Image * GaussianBlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1718
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:788
MagickExport Image * StatisticImage(const Image *image, const StatisticType type, const size_t width, const size_t height, ExceptionInfo *exception)
Definition: statistic.c:2861
#define QuantumRange
Definition: magick-type.h:87
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickRealType * values
Definition: morphology.h:116
MagickBooleanType debug
Definition: image.h:334
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)
static double BlurGaussian(const double x, const double sigma)
Definition: effect.c:857