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