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