MagickCore  7.0.3
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-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/decorate.h"
52 #include "MagickCore/distort.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/enhance.h"
55 #include "MagickCore/exception.h"
57 #include "MagickCore/effect.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/gem-private.h"
61 #include "MagickCore/geometry.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/matrix.h"
66 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
70 #include "MagickCore/montage.h"
71 #include "MagickCore/morphology.h"
73 #include "MagickCore/paint.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantize.h"
78 #include "MagickCore/quantum.h"
80 #include "MagickCore/random_.h"
82 #include "MagickCore/resample.h"
84 #include "MagickCore/resize.h"
85 #include "MagickCore/resource_.h"
86 #include "MagickCore/segment.h"
87 #include "MagickCore/shear.h"
89 #include "MagickCore/statistic.h"
90 #include "MagickCore/string_.h"
92 #include "MagickCore/transform.h"
93 #include "MagickCore/threshold.h"
94 
95 /*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 % %
98 % %
99 % %
100 % A d a p t i v e B l u r I m a g e %
101 % %
102 % %
103 % %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 % AdaptiveBlurImage() adaptively blurs the image by blurring less
107 % intensely near image edges and more intensely far from edges. We blur the
108 % image with a Gaussian operator of the given radius and standard deviation
109 % (sigma). For reasonable results, radius should be larger than sigma. Use a
110 % radius of 0 and AdaptiveBlurImage() selects a suitable radius for you.
111 %
112 % The format of the AdaptiveBlurImage method is:
113 %
114 % Image *AdaptiveBlurImage(const Image *image,const double radius,
115 % const double sigma,ExceptionInfo *exception)
116 %
117 % A description of each parameter follows:
118 %
119 % o image: the image.
120 %
121 % o radius: the radius of the Gaussian, in pixels, not counting the center
122 % pixel.
123 %
124 % o sigma: the standard deviation of the Laplacian, in pixels.
125 %
126 % o exception: return any errors or warnings in this structure.
127 %
128 */
129 MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
130  const double sigma,ExceptionInfo *exception)
131 {
132 #define AdaptiveBlurImageTag "Convolve/Image"
133 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
134 
135  CacheView
136  *blur_view,
137  *edge_view,
138  *image_view;
139 
140  double
141  normalize,
142  **kernel;
143 
144  Image
145  *blur_image,
146  *edge_image,
147  *gaussian_image;
148 
150  status;
151 
153  progress;
154 
155  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,0,0,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) memset(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) 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  {
340  SetPixelChannel(blur_image,channel,p[center+i],q);
341  continue;
342  }
343  k=kernel[j];
344  pixels=p;
345  pixel=0.0;
346  gamma=0.0;
347  if ((blur_traits & BlendPixelTrait) == 0)
348  {
349  /*
350  No alpha blending.
351  */
352  for (v=0; v < (ssize_t) (width-j); v++)
353  {
354  for (u=0; u < (ssize_t) (width-j); u++)
355  {
356  pixel+=(*k)*pixels[i];
357  gamma+=(*k);
358  k++;
359  pixels+=GetPixelChannels(image);
360  }
361  }
362  gamma=PerceptibleReciprocal(gamma);
363  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
364  continue;
365  }
366  /*
367  Alpha blending.
368  */
369  for (v=0; v < (ssize_t) (width-j); v++)
370  {
371  for (u=0; u < (ssize_t) (width-j); u++)
372  {
373  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
374  pixel+=(*k)*alpha*pixels[i];
375  gamma+=(*k)*alpha;
376  k++;
377  pixels+=GetPixelChannels(image);
378  }
379  }
380  gamma=PerceptibleReciprocal(gamma);
381  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
382  }
383  q+=GetPixelChannels(blur_image);
384  r+=GetPixelChannels(edge_image);
385  }
386  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
387  status=MagickFalse;
388  if (image->progress_monitor != (MagickProgressMonitor) NULL)
389  {
391  proceed;
392 
393 #if defined(MAGICKCORE_OPENMP_SUPPORT)
394  #pragma omp atomic
395 #endif
396  progress++;
397  proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
398  image->rows);
399  if (proceed == MagickFalse)
400  status=MagickFalse;
401  }
402  }
403  blur_image->type=image->type;
404  blur_view=DestroyCacheView(blur_view);
405  edge_view=DestroyCacheView(edge_view);
406  image_view=DestroyCacheView(image_view);
407  edge_image=DestroyImage(edge_image);
408  for (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,0,0,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) memset(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) 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  {
661  SetPixelChannel(sharp_image,channel,p[center+i],q);
662  continue;
663  }
664  k=kernel[j];
665  pixels=p;
666  pixel=0.0;
667  gamma=0.0;
668  if ((sharp_traits & BlendPixelTrait) == 0)
669  {
670  /*
671  No alpha blending.
672  */
673  for (v=0; v < (ssize_t) (width-j); v++)
674  {
675  for (u=0; u < (ssize_t) (width-j); u++)
676  {
677  pixel+=(*k)*pixels[i];
678  gamma+=(*k);
679  k++;
680  pixels+=GetPixelChannels(image);
681  }
682  }
683  gamma=PerceptibleReciprocal(gamma);
684  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
685  continue;
686  }
687  /*
688  Alpha blending.
689  */
690  for (v=0; v < (ssize_t) (width-j); v++)
691  {
692  for (u=0; u < (ssize_t) (width-j); u++)
693  {
694  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
695  pixel+=(*k)*alpha*pixels[i];
696  gamma+=(*k)*alpha;
697  k++;
698  pixels+=GetPixelChannels(image);
699  }
700  }
701  gamma=PerceptibleReciprocal(gamma);
702  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
703  }
704  q+=GetPixelChannels(sharp_image);
705  r+=GetPixelChannels(edge_image);
706  }
707  if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
708  status=MagickFalse;
709  if (image->progress_monitor != (MagickProgressMonitor) NULL)
710  {
712  proceed;
713 
714 #if defined(MAGICKCORE_OPENMP_SUPPORT)
715  #pragma omp atomic
716 #endif
717  progress++;
718  proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
719  image->rows);
720  if (proceed == MagickFalse)
721  status=MagickFalse;
722  }
723  }
724  sharp_image->type=image->type;
725  sharp_view=DestroyCacheView(sharp_view);
726  edge_view=DestroyCacheView(edge_view);
727  image_view=DestroyCacheView(image_view);
728  edge_image=DestroyImage(edge_image);
729  for (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*((ssize_t) columns+2)+x_offset);
899 #if defined(MAGICKCORE_OPENMP_SUPPORT)
900  #pragma omp parallel for schedule(static) \
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*((ssize_t) columns+2)+x_offset);
935  s=q-(y_offset*((ssize_t) columns+2)+x_offset);
936 #if defined(MAGICKCORE_OPENMP_SUPPORT)
937  #pragma omp parallel for schedule(static) \
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) memset(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) memset(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) memset(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,0,0,MagickTrue,exception);
1479  if (kuwahara_image == (Image *) NULL)
1480  {
1481  gaussian_image=DestroyImage(gaussian_image);
1482  return((Image *) NULL);
1483  }
1484  if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1485  {
1486  gaussian_image=DestroyImage(gaussian_image);
1487  kuwahara_image=DestroyImage(kuwahara_image);
1488  return((Image *) NULL);
1489  }
1490  /*
1491  Edge preserving noise reduction filter.
1492  */
1493  status=MagickTrue;
1494  progress=0;
1495  image_view=AcquireVirtualCacheView(gaussian_image,exception);
1496  kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1497 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1498  #pragma omp parallel for schedule(static) shared(progress,status) \
1499  magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1500 #endif
1501  for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1502  {
1503  register Quantum
1504  *magick_restrict q;
1505 
1506  register ssize_t
1507  x;
1508 
1509  if (status == MagickFalse)
1510  continue;
1511  q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1512  exception);
1513  if (q == (Quantum *) NULL)
1514  {
1515  status=MagickFalse;
1516  continue;
1517  }
1518  for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1519  {
1520  const Quantum
1521  *magick_restrict p;
1522 
1523  double
1524  min_variance;
1525 
1527  quadrant,
1528  target;
1529 
1530  register size_t
1531  i;
1532 
1533  min_variance=MagickMaximumValue;
1534  SetGeometry(gaussian_image,&target);
1535  quadrant.width=width;
1536  quadrant.height=width;
1537  for (i=0; i < 4; i++)
1538  {
1539  const Quantum
1540  *magick_restrict k;
1541 
1542  double
1543  mean[MaxPixelChannels],
1544  variance;
1545 
1546  register ssize_t
1547  n;
1548 
1549  ssize_t
1550  j;
1551 
1552  quadrant.x=x;
1553  quadrant.y=y;
1554  switch (i)
1555  {
1556  case 0:
1557  {
1558  quadrant.x=x-(ssize_t) (width-1);
1559  quadrant.y=y-(ssize_t) (width-1);
1560  break;
1561  }
1562  case 1:
1563  {
1564  quadrant.y=y-(ssize_t) (width-1);
1565  break;
1566  }
1567  case 2:
1568  {
1569  quadrant.x=x-(ssize_t) (width-1);
1570  break;
1571  }
1572  case 3:
1573  default:
1574  break;
1575  }
1576  p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1577  quadrant.width,quadrant.height,exception);
1578  if (p == (const Quantum *) NULL)
1579  break;
1580  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1581  mean[j]=0.0;
1582  k=p;
1583  for (n=0; n < (ssize_t) (width*width); n++)
1584  {
1585  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1586  mean[j]+=(double) k[j];
1587  k+=GetPixelChannels(gaussian_image);
1588  }
1589  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1590  mean[j]/=(double) (width*width);
1591  k=p;
1592  variance=0.0;
1593  for (n=0; n < (ssize_t) (width*width); n++)
1594  {
1595  double
1596  luma;
1597 
1598  luma=GetPixelLuma(gaussian_image,k);
1599  variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1600  (luma-GetMeanLuma(gaussian_image,mean));
1601  k+=GetPixelChannels(gaussian_image);
1602  }
1603  if (variance < min_variance)
1604  {
1605  min_variance=variance;
1606  target=quadrant;
1607  }
1608  }
1609  if (i < 4)
1610  {
1611  status=MagickFalse;
1612  break;
1613  }
1614  status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1615  UndefinedInterpolatePixel,(double) target.x+target.width/2.0,(double)
1616  target.y+target.height/2.0,q,exception);
1617  if (status == MagickFalse)
1618  break;
1619  q+=GetPixelChannels(kuwahara_image);
1620  }
1621  if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1622  status=MagickFalse;
1623  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1624  {
1626  proceed;
1627 
1628 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1629  #pragma omp atomic
1630 #endif
1631  progress++;
1632  proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1633  if (proceed == MagickFalse)
1634  status=MagickFalse;
1635  }
1636  }
1637  kuwahara_view=DestroyCacheView(kuwahara_view);
1638  image_view=DestroyCacheView(image_view);
1639  gaussian_image=DestroyImage(gaussian_image);
1640  if (status == MagickFalse)
1641  kuwahara_image=DestroyImage(kuwahara_image);
1642  return(kuwahara_image);
1643 }
1644 
1645 /*
1646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647 % %
1648 % %
1649 % %
1650 % L o c a l C o n t r a s t I m a g e %
1651 % %
1652 % %
1653 % %
1654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655 %
1656 % LocalContrastImage() attempts to increase the appearance of large-scale
1657 % light-dark transitions. Local contrast enhancement works similarly to
1658 % sharpening with an unsharp mask, however the mask is instead created using
1659 % an image with a greater blur distance.
1660 %
1661 % The format of the LocalContrastImage method is:
1662 %
1663 % Image *LocalContrastImage(const Image *image, const double radius,
1664 % const double strength,ExceptionInfo *exception)
1665 %
1666 % A description of each parameter follows:
1667 %
1668 % o image: the image.
1669 %
1670 % o radius: the radius of the Gaussian blur, in percentage with 100%
1671 % resulting in a blur radius of 20% of largest dimension.
1672 %
1673 % o strength: the strength of the blur mask in percentage.
1674 %
1675 % o exception: return any errors or warnings in this structure.
1676 %
1677 */
1678 MagickExport Image *LocalContrastImage(const Image *image,const double radius,
1679  const double strength,ExceptionInfo *exception)
1680 {
1681 #define LocalContrastImageTag "LocalContrast/Image"
1682 
1683  CacheView
1684  *image_view,
1685  *contrast_view;
1686 
1687  float
1688  *interImage,
1689  *scanLinePixels,
1690  totalWeight;
1691 
1692  Image
1693  *contrast_image;
1694 
1696  status;
1697 
1698  MemoryInfo
1699  *scanLinePixels_info,
1700  *interImage_info;
1701 
1702  ssize_t
1703  scanLineSize,
1704  width;
1705 
1706  /*
1707  Initialize contrast image attributes.
1708  */
1709  assert(image != (const Image *) NULL);
1710  assert(image->signature == MagickCoreSignature);
1711  if (image->debug != MagickFalse)
1712  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1713  assert(exception != (ExceptionInfo *) NULL);
1714  assert(exception->signature == MagickCoreSignature);
1715 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1716  contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
1717  if (contrast_image != (Image *) NULL)
1718  return(contrast_image);
1719 #endif
1720  contrast_image=CloneImage(image,0,0,MagickTrue,exception);
1721  if (contrast_image == (Image *) NULL)
1722  return((Image *) NULL);
1723  if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
1724  {
1725  contrast_image=DestroyImage(contrast_image);
1726  return((Image *) NULL);
1727  }
1728  image_view=AcquireVirtualCacheView(image,exception);
1729  contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
1730  scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
1731  width=(ssize_t) scanLineSize*0.002f*fabs(radius);
1732  scanLineSize+=(2*width);
1733  scanLinePixels_info=AcquireVirtualMemory((size_t) GetOpenMPMaximumThreads()*
1734  scanLineSize,sizeof(*scanLinePixels));
1735  if (scanLinePixels_info == (MemoryInfo *) NULL)
1736  {
1737  contrast_view=DestroyCacheView(contrast_view);
1738  image_view=DestroyCacheView(image_view);
1739  contrast_image=DestroyImage(contrast_image);
1740  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1741  }
1742  scanLinePixels=(float *) GetVirtualMemoryBlob(scanLinePixels_info);
1743  /*
1744  Create intermediate buffer.
1745  */
1746  interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(2*width)),
1747  sizeof(*interImage));
1748  if (interImage_info == (MemoryInfo *) NULL)
1749  {
1750  scanLinePixels_info=RelinquishVirtualMemory(scanLinePixels_info);
1751  contrast_view=DestroyCacheView(contrast_view);
1752  image_view=DestroyCacheView(image_view);
1753  contrast_image=DestroyImage(contrast_image);
1754  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1755  }
1756  interImage=(float *) GetVirtualMemoryBlob(interImage_info);
1757  totalWeight=(float) ((width+1)*(width+1));
1758  /*
1759  Vertical pass.
1760  */
1761  status=MagickTrue;
1762  {
1763  ssize_t
1764  x;
1765 
1766 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1767 #pragma omp parallel for schedule(static) \
1768  magick_number_threads(image,image,image->columns,1)
1769 #endif
1770  for (x=0; x < (ssize_t) image->columns; x++)
1771  {
1772  const int
1773  id = GetOpenMPThreadId();
1774 
1775  const Quantum
1776  *magick_restrict p;
1777 
1778  float
1779  *out,
1780  *pix,
1781  *pixels;
1782 
1783  register ssize_t
1784  y;
1785 
1786  ssize_t
1787  i;
1788 
1789  if (status == MagickFalse)
1790  continue;
1791  pixels=scanLinePixels;
1792  pixels+=id*scanLineSize;
1793  pix=pixels;
1794  p=GetCacheViewVirtualPixels(image_view,x,-width,1,image->rows+(2*width),
1795  exception);
1796  if (p == (const Quantum *) NULL)
1797  {
1798  status=MagickFalse;
1799  continue;
1800  }
1801  for (y=0; y < (ssize_t) image->rows+(2*width); y++)
1802  {
1803  *pix++=(float)GetPixelLuma(image,p);
1804  p+=image->number_channels;
1805  }
1806  out=interImage+x+width;
1807  for (y=0; y < (ssize_t) image->rows; y++)
1808  {
1809  float
1810  sum,
1811  weight;
1812 
1813  weight=1.0f;
1814  sum=0;
1815  pix=pixels+y;
1816  for (i=0; i < width; i++)
1817  {
1818  sum+=weight*(*pix++);
1819  weight+=1.0f;
1820  }
1821  for (i=width+1; i < (2*width); i++)
1822  {
1823  sum+=weight*(*pix++);
1824  weight-=1.0f;
1825  }
1826  /* write to output */
1827  *out=sum/totalWeight;
1828  /* mirror into padding */
1829  if (x <= width && x != 0)
1830  *(out-(x*2))=*out;
1831  if ((x > (ssize_t) image->columns-width-2) &&
1832  (x != (ssize_t) image->columns-1))
1833  *(out+((image->columns-x-1)*2))=*out;
1834  out+=image->columns+(width*2);
1835  }
1836  }
1837  }
1838  /*
1839  Horizontal pass.
1840  */
1841  {
1842  ssize_t
1843  y;
1844 
1845 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1846 #pragma omp parallel for schedule(static) \
1847  magick_number_threads(image,image,image->rows,1)
1848 #endif
1849  for (y=0; y < (ssize_t) image->rows; y++)
1850  {
1851  const int
1852  id = GetOpenMPThreadId();
1853 
1854  const Quantum
1855  *magick_restrict p;
1856 
1857  float
1858  *pix,
1859  *pixels;
1860 
1861  register Quantum
1862  *magick_restrict q;
1863 
1864  register ssize_t
1865  x;
1866 
1867  ssize_t
1868  i;
1869 
1870  if (status == MagickFalse)
1871  continue;
1872  pixels=scanLinePixels;
1873  pixels+=id*scanLineSize;
1874  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1875  q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
1876  exception);
1877  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1878  {
1879  status=MagickFalse;
1880  continue;
1881  }
1882  memcpy(pixels,interImage+(y*(image->columns+(2*width))),(image->columns+
1883  (2*width))*sizeof(float));
1884  for (x=0; x < (ssize_t) image->columns; x++)
1885  {
1886  float
1887  mult,
1888  srcVal,
1889  sum,
1890  weight;
1891 
1892  PixelTrait
1893  traits;
1894 
1895  weight=1.0f;
1896  sum=0;
1897  pix=pixels+x;
1898  for (i=0; i < width; i++)
1899  {
1900  sum+=weight*(*pix++);
1901  weight+=1.0f;
1902  }
1903  for (i=width+1; i < (2*width); i++)
1904  {
1905  sum+=weight*(*pix++);
1906  weight-=1.0f;
1907  }
1908  /* Apply and write */
1909  srcVal=(float) GetPixelLuma(image,p);
1910  mult=(srcVal-(sum/totalWeight))*(strength/100.0f);
1911  mult=(srcVal+mult)/srcVal;
1912  traits=GetPixelChannelTraits(image,RedPixelChannel);
1913  if ((traits & UpdatePixelTrait) != 0)
1914  SetPixelRed(contrast_image,ClampToQuantum(GetPixelRed(image,p)*mult),
1915  q);
1917  if ((traits & UpdatePixelTrait) != 0)
1918  SetPixelGreen(contrast_image,ClampToQuantum(GetPixelGreen(image,p)*
1919  mult),q);
1921  if ((traits & UpdatePixelTrait) != 0)
1922  SetPixelBlue(contrast_image,ClampToQuantum(GetPixelBlue(image,p)*
1923  mult),q);
1924  p+=image->number_channels;
1925  q+=contrast_image->number_channels;
1926  }
1927  if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
1928  status=MagickFalse;
1929  }
1930  }
1931  scanLinePixels_info=RelinquishVirtualMemory(scanLinePixels_info);
1932  interImage_info=RelinquishVirtualMemory(interImage_info);
1933  contrast_view=DestroyCacheView(contrast_view);
1934  image_view=DestroyCacheView(image_view);
1935  if (status == MagickFalse)
1936  contrast_image=DestroyImage(contrast_image);
1937  return(contrast_image);
1938 }
1939 
1940 /*
1941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942 % %
1943 % %
1944 % %
1945 % M o t i o n B l u r I m a g e %
1946 % %
1947 % %
1948 % %
1949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950 %
1951 % MotionBlurImage() simulates motion blur. We convolve the image with a
1952 % Gaussian operator of the given radius and standard deviation (sigma).
1953 % For reasonable results, radius should be larger than sigma. Use a
1954 % radius of 0 and MotionBlurImage() selects a suitable radius for you.
1955 % Angle gives the angle of the blurring motion.
1956 %
1957 % Andrew Protano contributed this effect.
1958 %
1959 % The format of the MotionBlurImage method is:
1960 %
1961 % Image *MotionBlurImage(const Image *image,const double radius,
1962 % const double sigma,const double angle,ExceptionInfo *exception)
1963 %
1964 % A description of each parameter follows:
1965 %
1966 % o image: the image.
1967 %
1968 % o radius: the radius of the Gaussian, in pixels, not counting
1969 % the center pixel.
1970 %
1971 % o sigma: the standard deviation of the Gaussian, in pixels.
1972 %
1973 % o angle: Apply the effect along this angle.
1974 %
1975 % o exception: return any errors or warnings in this structure.
1976 %
1977 */
1978 
1979 static MagickRealType *GetMotionBlurKernel(const size_t width,
1980  const double sigma)
1981 {
1983  *kernel,
1984  normalize;
1985 
1986  register ssize_t
1987  i;
1988 
1989  /*
1990  Generate a 1-D convolution kernel.
1991  */
1992  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1994  width,sizeof(*kernel)));
1995  if (kernel == (MagickRealType *) NULL)
1996  return(kernel);
1997  normalize=0.0;
1998  for (i=0; i < (ssize_t) width; i++)
1999  {
2000  kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
2002  normalize+=kernel[i];
2003  }
2004  for (i=0; i < (ssize_t) width; i++)
2005  kernel[i]/=normalize;
2006  return(kernel);
2007 }
2008 
2009 MagickExport Image *MotionBlurImage(const Image *image,const double radius,
2010  const double sigma,const double angle,ExceptionInfo *exception)
2011 {
2012 #define BlurImageTag "Blur/Image"
2013 
2014  CacheView
2015  *blur_view,
2016  *image_view,
2017  *motion_view;
2018 
2019  Image
2020  *blur_image;
2021 
2023  status;
2024 
2026  progress;
2027 
2029  *kernel;
2030 
2031  OffsetInfo
2032  *offset;
2033 
2034  PointInfo
2035  point;
2036 
2037  register ssize_t
2038  i;
2039 
2040  size_t
2041  width;
2042 
2043  ssize_t
2044  y;
2045 
2046  assert(image != (Image *) NULL);
2047  assert(image->signature == MagickCoreSignature);
2048  if (image->debug != MagickFalse)
2049  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2050  assert(exception != (ExceptionInfo *) NULL);
2051  width=GetOptimalKernelWidth1D(radius,sigma);
2052  kernel=GetMotionBlurKernel(width,sigma);
2053  if (kernel == (MagickRealType *) NULL)
2054  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2055  offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
2056  if (offset == (OffsetInfo *) NULL)
2057  {
2058  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2059  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2060  }
2061  point.x=(double) width*sin(DegreesToRadians(angle));
2062  point.y=(double) width*cos(DegreesToRadians(angle));
2063  for (i=0; i < (ssize_t) width; i++)
2064  {
2065  offset[i].x=(ssize_t) ceil((double) (i*point.y)/hypot(point.x,point.y)-0.5);
2066  offset[i].y=(ssize_t) ceil((double) (i*point.x)/hypot(point.x,point.y)-0.5);
2067  }
2068  /*
2069  Motion blur image.
2070  */
2071 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2072  blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2073  if (blur_image != (Image *) NULL)
2074  {
2075  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2076  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2077  return(blur_image);
2078  }
2079 #endif
2080  blur_image=CloneImage(image,0,0,MagickTrue,exception);
2081  if (blur_image == (Image *) NULL)
2082  {
2083  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2084  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2085  return((Image *) NULL);
2086  }
2087  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2088  {
2089  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2090  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2091  blur_image=DestroyImage(blur_image);
2092  return((Image *) NULL);
2093  }
2094  status=MagickTrue;
2095  progress=0;
2096  image_view=AcquireVirtualCacheView(image,exception);
2097  motion_view=AcquireVirtualCacheView(image,exception);
2098  blur_view=AcquireAuthenticCacheView(blur_image,exception);
2099 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2100  #pragma omp parallel for schedule(static) shared(progress,status) \
2101  magick_number_threads(image,blur_image,image->rows,1)
2102 #endif
2103  for (y=0; y < (ssize_t) image->rows; y++)
2104  {
2105  register const Quantum
2106  *magick_restrict p;
2107 
2108  register Quantum
2109  *magick_restrict q;
2110 
2111  register ssize_t
2112  x;
2113 
2114  if (status == MagickFalse)
2115  continue;
2116  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2117  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2118  exception);
2119  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2120  {
2121  status=MagickFalse;
2122  continue;
2123  }
2124  for (x=0; x < (ssize_t) image->columns; x++)
2125  {
2126  register ssize_t
2127  i;
2128 
2129  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2130  {
2131  double
2132  alpha,
2133  gamma,
2134  pixel;
2135 
2136  PixelChannel
2137  channel;
2138 
2139  PixelTrait
2140  blur_traits,
2141  traits;
2142 
2143  register const Quantum
2144  *magick_restrict r;
2145 
2146  register MagickRealType
2147  *magick_restrict k;
2148 
2149  register ssize_t
2150  j;
2151 
2152  channel=GetPixelChannelChannel(image,i);
2153  traits=GetPixelChannelTraits(image,channel);
2154  blur_traits=GetPixelChannelTraits(blur_image,channel);
2155  if ((traits == UndefinedPixelTrait) ||
2156  (blur_traits == UndefinedPixelTrait))
2157  continue;
2158  if ((blur_traits & CopyPixelTrait) != 0)
2159  {
2160  SetPixelChannel(blur_image,channel,p[i],q);
2161  continue;
2162  }
2163  k=kernel;
2164  pixel=0.0;
2165  if ((blur_traits & BlendPixelTrait) == 0)
2166  {
2167  for (j=0; j < (ssize_t) width; j++)
2168  {
2169  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2170  offset[j].y,1,1,exception);
2171  if (r == (const Quantum *) NULL)
2172  {
2173  status=MagickFalse;
2174  continue;
2175  }
2176  pixel+=(*k)*r[i];
2177  k++;
2178  }
2179  SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2180  continue;
2181  }
2182  alpha=0.0;
2183  gamma=0.0;
2184  for (j=0; j < (ssize_t) width; j++)
2185  {
2186  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2187  1,exception);
2188  if (r == (const Quantum *) NULL)
2189  {
2190  status=MagickFalse;
2191  continue;
2192  }
2193  alpha=(double) (QuantumScale*GetPixelAlpha(image,r));
2194  pixel+=(*k)*alpha*r[i];
2195  gamma+=(*k)*alpha;
2196  k++;
2197  }
2198  gamma=PerceptibleReciprocal(gamma);
2199  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2200  }
2201  p+=GetPixelChannels(image);
2202  q+=GetPixelChannels(blur_image);
2203  }
2204  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2205  status=MagickFalse;
2206  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2207  {
2209  proceed;
2210 
2211 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2212  #pragma omp atomic
2213 #endif
2214  progress++;
2215  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2216  if (proceed == MagickFalse)
2217  status=MagickFalse;
2218  }
2219  }
2220  blur_view=DestroyCacheView(blur_view);
2221  motion_view=DestroyCacheView(motion_view);
2222  image_view=DestroyCacheView(image_view);
2223  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2224  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2225  if (status == MagickFalse)
2226  blur_image=DestroyImage(blur_image);
2227  return(blur_image);
2228 }
2229 
2230 /*
2231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232 % %
2233 % %
2234 % %
2235 % P r e v i e w I m a g e %
2236 % %
2237 % %
2238 % %
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 %
2241 % PreviewImage() tiles 9 thumbnails of the specified image with an image
2242 % processing operation applied with varying parameters. This may be helpful
2243 % pin-pointing an appropriate parameter for a particular image processing
2244 % operation.
2245 %
2246 % The format of the PreviewImages method is:
2247 %
2248 % Image *PreviewImages(const Image *image,const PreviewType preview,
2249 % ExceptionInfo *exception)
2250 %
2251 % A description of each parameter follows:
2252 %
2253 % o image: the image.
2254 %
2255 % o preview: the image processing operation.
2256 %
2257 % o exception: return any errors or warnings in this structure.
2258 %
2259 */
2260 MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
2261  ExceptionInfo *exception)
2262 {
2263 #define NumberTiles 9
2264 #define PreviewImageTag "Preview/Image"
2265 #define DefaultPreviewGeometry "204x204+10+10"
2266 
2267  char
2268  factor[MagickPathExtent],
2269  label[MagickPathExtent];
2270 
2271  double
2272  degrees,
2273  gamma,
2274  percentage,
2275  radius,
2276  sigma,
2277  threshold;
2278 
2279  extern const char
2280  DefaultTileFrame[];
2281 
2282  Image
2283  *images,
2284  *montage_image,
2285  *preview_image,
2286  *thumbnail;
2287 
2288  ImageInfo
2289  *preview_info;
2290 
2292  proceed;
2293 
2294  MontageInfo
2295  *montage_info;
2296 
2297  QuantizeInfo
2298  quantize_info;
2299 
2301  geometry;
2302 
2303  register ssize_t
2304  i,
2305  x;
2306 
2307  size_t
2308  colors;
2309 
2310  ssize_t
2311  y;
2312 
2313  /*
2314  Open output image file.
2315  */
2316  assert(image != (Image *) NULL);
2317  assert(image->signature == MagickCoreSignature);
2318  if (image->debug != MagickFalse)
2319  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2320  colors=2;
2321  degrees=0.0;
2322  gamma=(-0.2f);
2323  preview_info=AcquireImageInfo();
2324  SetGeometry(image,&geometry);
2325  (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2326  &geometry.width,&geometry.height);
2327  images=NewImageList();
2328  percentage=12.5;
2329  GetQuantizeInfo(&quantize_info);
2330  radius=0.0;
2331  sigma=1.0;
2332  threshold=0.0;
2333  x=0;
2334  y=0;
2335  for (i=0; i < NumberTiles; i++)
2336  {
2337  thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2338  if (thumbnail == (Image *) NULL)
2339  break;
2340  (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2341  (void *) NULL);
2342  (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
2343  if (i == (NumberTiles/2))
2344  {
2345  (void) QueryColorCompliance("#dfdfdf",AllCompliance,
2346  &thumbnail->matte_color,exception);
2347  AppendImageToList(&images,thumbnail);
2348  continue;
2349  }
2350  switch (preview)
2351  {
2352  case RotatePreview:
2353  {
2354  degrees+=45.0;
2355  preview_image=RotateImage(thumbnail,degrees,exception);
2356  (void) FormatLocaleString(label,MagickPathExtent,"rotate %g",degrees);
2357  break;
2358  }
2359  case ShearPreview:
2360  {
2361  degrees+=5.0;
2362  preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2363  (void) FormatLocaleString(label,MagickPathExtent,"shear %gx%g",degrees,
2364  2.0*degrees);
2365  break;
2366  }
2367  case RollPreview:
2368  {
2369  x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
2370  y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
2371  preview_image=RollImage(thumbnail,x,y,exception);
2372  (void) FormatLocaleString(label,MagickPathExtent,"roll %+.20gx%+.20g",
2373  (double) x,(double) y);
2374  break;
2375  }
2376  case HuePreview:
2377  {
2378  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2379  if (preview_image == (Image *) NULL)
2380  break;
2381  (void) FormatLocaleString(factor,MagickPathExtent,"100,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 SaturationPreview:
2388  {
2389  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2390  if (preview_image == (Image *) NULL)
2391  break;
2392  (void) FormatLocaleString(factor,MagickPathExtent,"100,%g",2.0*
2393  percentage);
2394  (void) ModulateImage(preview_image,factor,exception);
2395  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2396  break;
2397  }
2398  case BrightnessPreview:
2399  {
2400  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2401  if (preview_image == (Image *) NULL)
2402  break;
2403  (void) FormatLocaleString(factor,MagickPathExtent,"%g",2.0*percentage);
2404  (void) ModulateImage(preview_image,factor,exception);
2405  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2406  break;
2407  }
2408  case GammaPreview:
2409  default:
2410  {
2411  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2412  if (preview_image == (Image *) NULL)
2413  break;
2414  gamma+=0.4f;
2415  (void) GammaImage(preview_image,gamma,exception);
2416  (void) FormatLocaleString(label,MagickPathExtent,"gamma %g",gamma);
2417  break;
2418  }
2419  case SpiffPreview:
2420  {
2421  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2422  if (preview_image != (Image *) NULL)
2423  for (x=0; x < i; x++)
2424  (void) ContrastImage(preview_image,MagickTrue,exception);
2425  (void) FormatLocaleString(label,MagickPathExtent,"contrast (%.20g)",
2426  (double) i+1);
2427  break;
2428  }
2429  case DullPreview:
2430  {
2431  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2432  if (preview_image == (Image *) NULL)
2433  break;
2434  for (x=0; x < i; x++)
2435  (void) ContrastImage(preview_image,MagickFalse,exception);
2436  (void) FormatLocaleString(label,MagickPathExtent,"+contrast (%.20g)",
2437  (double) i+1);
2438  break;
2439  }
2440  case GrayscalePreview:
2441  {
2442  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2443  if (preview_image == (Image *) NULL)
2444  break;
2445  colors<<=1;
2446  quantize_info.number_colors=colors;
2447  quantize_info.colorspace=GRAYColorspace;
2448  (void) QuantizeImage(&quantize_info,preview_image,exception);
2449  (void) FormatLocaleString(label,MagickPathExtent,
2450  "-colorspace gray -colors %.20g",(double) colors);
2451  break;
2452  }
2453  case QuantizePreview:
2454  {
2455  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2456  if (preview_image == (Image *) NULL)
2457  break;
2458  colors<<=1;
2459  quantize_info.number_colors=colors;
2460  (void) QuantizeImage(&quantize_info,preview_image,exception);
2461  (void) FormatLocaleString(label,MagickPathExtent,"colors %.20g",
2462  (double) colors);
2463  break;
2464  }
2465  case DespecklePreview:
2466  {
2467  for (x=0; x < (i-1); x++)
2468  {
2469  preview_image=DespeckleImage(thumbnail,exception);
2470  if (preview_image == (Image *) NULL)
2471  break;
2472  thumbnail=DestroyImage(thumbnail);
2473  thumbnail=preview_image;
2474  }
2475  preview_image=DespeckleImage(thumbnail,exception);
2476  if (preview_image == (Image *) NULL)
2477  break;
2478  (void) FormatLocaleString(label,MagickPathExtent,"despeckle (%.20g)",
2479  (double) i+1);
2480  break;
2481  }
2482  case ReduceNoisePreview:
2483  {
2484  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t)
2485  radius,(size_t) radius,exception);
2486  (void) FormatLocaleString(label,MagickPathExtent,"noise %g",radius);
2487  break;
2488  }
2489  case AddNoisePreview:
2490  {
2491  switch ((int) i)
2492  {
2493  case 0:
2494  {
2495  (void) CopyMagickString(factor,"uniform",MagickPathExtent);
2496  break;
2497  }
2498  case 1:
2499  {
2500  (void) CopyMagickString(factor,"gaussian",MagickPathExtent);
2501  break;
2502  }
2503  case 2:
2504  {
2505  (void) CopyMagickString(factor,"multiplicative",MagickPathExtent);
2506  break;
2507  }
2508  case 3:
2509  {
2510  (void) CopyMagickString(factor,"impulse",MagickPathExtent);
2511  break;
2512  }
2513  case 5:
2514  {
2515  (void) CopyMagickString(factor,"laplacian",MagickPathExtent);
2516  break;
2517  }
2518  case 6:
2519  {
2520  (void) CopyMagickString(factor,"Poisson",MagickPathExtent);
2521  break;
2522  }
2523  default:
2524  {
2525  (void) CopyMagickString(thumbnail->magick,"NULL",MagickPathExtent);
2526  break;
2527  }
2528  }
2529  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
2530  (size_t) i,exception);
2531  (void) FormatLocaleString(label,MagickPathExtent,"+noise %s",factor);
2532  break;
2533  }
2534  case SharpenPreview:
2535  {
2536  preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2537  (void) FormatLocaleString(label,MagickPathExtent,"sharpen %gx%g",
2538  radius,sigma);
2539  break;
2540  }
2541  case BlurPreview:
2542  {
2543  preview_image=BlurImage(thumbnail,radius,sigma,exception);
2544  (void) FormatLocaleString(label,MagickPathExtent,"blur %gx%g",radius,
2545  sigma);
2546  break;
2547  }
2548  case ThresholdPreview:
2549  {
2550  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2551  if (preview_image == (Image *) NULL)
2552  break;
2553  (void) BilevelImage(thumbnail,(double) (percentage*((double)
2554  QuantumRange+1.0))/100.0,exception);
2555  (void) FormatLocaleString(label,MagickPathExtent,"threshold %g",
2556  (double) (percentage*((double) QuantumRange+1.0))/100.0);
2557  break;
2558  }
2559  case EdgeDetectPreview:
2560  {
2561  preview_image=EdgeImage(thumbnail,radius,exception);
2562  (void) FormatLocaleString(label,MagickPathExtent,"edge %g",radius);
2563  break;
2564  }
2565  case SpreadPreview:
2566  {
2567  preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2568  exception);
2569  (void) FormatLocaleString(label,MagickPathExtent,"spread %g",
2570  radius+0.5);
2571  break;
2572  }
2573  case SolarizePreview:
2574  {
2575  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2576  if (preview_image == (Image *) NULL)
2577  break;
2578  (void) SolarizeImage(preview_image,(double) QuantumRange*percentage/
2579  100.0,exception);
2580  (void) FormatLocaleString(label,MagickPathExtent,"solarize %g",
2581  (QuantumRange*percentage)/100.0);
2582  break;
2583  }
2584  case ShadePreview:
2585  {
2586  degrees+=10.0;
2587  preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2588  exception);
2589  (void) FormatLocaleString(label,MagickPathExtent,"shade %gx%g",degrees,
2590  degrees);
2591  break;
2592  }
2593  case RaisePreview:
2594  {
2596  raise;
2597 
2598  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2599  if (preview_image == (Image *) NULL)
2600  break;
2601  raise.width=(size_t) (2*i+2);
2602  raise.height=(size_t) (2*i+2);
2603  raise.x=(i-1)/2;
2604  raise.y=(i-1)/2;
2605  (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2606  (void) FormatLocaleString(label,MagickPathExtent,
2607  "raise %.20gx%.20g%+.20g%+.20g",(double) raise.width,(double)
2608  raise.height,(double) raise.x,(double) raise.y);
2609  break;
2610  }
2611  case SegmentPreview:
2612  {
2613  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2614  if (preview_image == (Image *) NULL)
2615  break;
2616  threshold+=0.4f;
2617  (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2618  threshold,exception);
2619  (void) FormatLocaleString(label,MagickPathExtent,"segment %gx%g",
2620  threshold,threshold);
2621  break;
2622  }
2623  case SwirlPreview:
2624  {
2625  preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2626  exception);
2627  (void) FormatLocaleString(label,MagickPathExtent,"swirl %g",degrees);
2628  degrees+=45.0;
2629  break;
2630  }
2631  case ImplodePreview:
2632  {
2633  degrees+=0.1f;
2634  preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2635  exception);
2636  (void) FormatLocaleString(label,MagickPathExtent,"implode %g",degrees);
2637  break;
2638  }
2639  case WavePreview:
2640  {
2641  degrees+=5.0f;
2642  preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2643  image->interpolate,exception);
2644  (void) FormatLocaleString(label,MagickPathExtent,"wave %gx%g",0.5*
2645  degrees,2.0*degrees);
2646  break;
2647  }
2648  case OilPaintPreview:
2649  {
2650  preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
2651  exception);
2652  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
2653  radius,sigma);
2654  break;
2655  }
2657  {
2658  preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
2659  exception);
2660  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
2661  radius,sigma);
2662  break;
2663  }
2664  case JPEGPreview:
2665  {
2666  char
2667  filename[MagickPathExtent];
2668 
2669  int
2670  file;
2671 
2673  status;
2674 
2675  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2676  if (preview_image == (Image *) NULL)
2677  break;
2678  preview_info->quality=(size_t) percentage;
2679  (void) FormatLocaleString(factor,MagickPathExtent,"%.20g",(double)
2680  preview_info->quality);
2681  file=AcquireUniqueFileResource(filename);
2682  if (file != -1)
2683  file=close(file)-1;
2684  (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
2685  "jpeg:%s",filename);
2686  status=WriteImage(preview_info,preview_image,exception);
2687  if (status != MagickFalse)
2688  {
2689  Image
2690  *quality_image;
2691 
2692  (void) CopyMagickString(preview_info->filename,
2693  preview_image->filename,MagickPathExtent);
2694  quality_image=ReadImage(preview_info,exception);
2695  if (quality_image != (Image *) NULL)
2696  {
2697  preview_image=DestroyImage(preview_image);
2698  preview_image=quality_image;
2699  }
2700  }
2701  (void) RelinquishUniqueFileResource(preview_image->filename);
2702  if ((GetBlobSize(preview_image)/1024) >= 1024)
2703  (void) FormatLocaleString(label,MagickPathExtent,"quality %s\n%gmb ",
2704  factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
2705  1024.0/1024.0);
2706  else
2707  if (GetBlobSize(preview_image) >= 1024)
2708  (void) FormatLocaleString(label,MagickPathExtent,
2709  "quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
2710  GetBlobSize(preview_image))/1024.0);
2711  else
2712  (void) FormatLocaleString(label,MagickPathExtent,
2713  "quality %s\n%.20gb ",factor,(double) ((MagickOffsetType)
2714  GetBlobSize(thumbnail)));
2715  break;
2716  }
2717  }
2718  thumbnail=DestroyImage(thumbnail);
2719  percentage+=12.5;
2720  radius+=0.5;
2721  sigma+=0.25;
2722  if (preview_image == (Image *) NULL)
2723  break;
2724  (void) DeleteImageProperty(preview_image,"label");
2725  (void) SetImageProperty(preview_image,"label",label,exception);
2726  AppendImageToList(&images,preview_image);
2728  NumberTiles);
2729  if (proceed == MagickFalse)
2730  break;
2731  }
2732  if (images == (Image *) NULL)
2733  {
2734  preview_info=DestroyImageInfo(preview_info);
2735  return((Image *) NULL);
2736  }
2737  /*
2738  Create the montage.
2739  */
2740  montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
2741  (void) CopyMagickString(montage_info->filename,image->filename,
2743  montage_info->shadow=MagickTrue;
2744  (void) CloneString(&montage_info->tile,"3x3");
2745  (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
2746  (void) CloneString(&montage_info->frame,DefaultTileFrame);
2747  montage_image=MontageImages(images,montage_info,exception);
2748  montage_info=DestroyMontageInfo(montage_info);
2749  images=DestroyImageList(images);
2750  if (montage_image == (Image *) NULL)
2751  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2752  if (montage_image->montage != (char *) NULL)
2753  {
2754  /*
2755  Free image directory.
2756  */
2757  montage_image->montage=(char *) RelinquishMagickMemory(
2758  montage_image->montage);
2759  if (image->directory != (char *) NULL)
2760  montage_image->directory=(char *) RelinquishMagickMemory(
2761  montage_image->directory);
2762  }
2763  preview_info=DestroyImageInfo(preview_info);
2764  return(montage_image);
2765 }
2766 
2767 /*
2768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769 % %
2770 % %
2771 % %
2772 % R o t a t i o n a l B l u r I m a g e %
2773 % %
2774 % %
2775 % %
2776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777 %
2778 % RotationalBlurImage() applies a radial blur to the image.
2779 %
2780 % Andrew Protano contributed this effect.
2781 %
2782 % The format of the RotationalBlurImage method is:
2783 %
2784 % Image *RotationalBlurImage(const Image *image,const double angle,
2785 % ExceptionInfo *exception)
2786 %
2787 % A description of each parameter follows:
2788 %
2789 % o image: the image.
2790 %
2791 % o angle: the angle of the radial blur.
2792 %
2793 % o blur: the blur.
2794 %
2795 % o exception: return any errors or warnings in this structure.
2796 %
2797 */
2798 MagickExport Image *RotationalBlurImage(const Image *image,const double angle,
2799  ExceptionInfo *exception)
2800 {
2801  CacheView
2802  *blur_view,
2803  *image_view,
2804  *radial_view;
2805 
2806  double
2807  blur_radius,
2808  *cos_theta,
2809  offset,
2810  *sin_theta,
2811  theta;
2812 
2813  Image
2814  *blur_image;
2815 
2817  status;
2818 
2820  progress;
2821 
2822  PointInfo
2823  blur_center;
2824 
2825  register ssize_t
2826  i;
2827 
2828  size_t
2829  n;
2830 
2831  ssize_t
2832  y;
2833 
2834  /*
2835  Allocate blur image.
2836  */
2837  assert(image != (Image *) NULL);
2838  assert(image->signature == MagickCoreSignature);
2839  if (image->debug != MagickFalse)
2840  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2841  assert(exception != (ExceptionInfo *) NULL);
2842  assert(exception->signature == MagickCoreSignature);
2843 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2844  blur_image=AccelerateRotationalBlurImage(image,angle,exception);
2845  if (blur_image != (Image *) NULL)
2846  return(blur_image);
2847 #endif
2848  blur_image=CloneImage(image,0,0,MagickTrue,exception);
2849  if (blur_image == (Image *) NULL)
2850  return((Image *) NULL);
2851  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2852  {
2853  blur_image=DestroyImage(blur_image);
2854  return((Image *) NULL);
2855  }
2856  blur_center.x=(double) (image->columns-1)/2.0;
2857  blur_center.y=(double) (image->rows-1)/2.0;
2858  blur_radius=hypot(blur_center.x,blur_center.y);
2859  n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
2860  theta=DegreesToRadians(angle)/(double) (n-1);
2861  cos_theta=(double *) AcquireQuantumMemory((size_t) n,
2862  sizeof(*cos_theta));
2863  sin_theta=(double *) AcquireQuantumMemory((size_t) n,
2864  sizeof(*sin_theta));
2865  if ((cos_theta == (double *) NULL) ||
2866  (sin_theta == (double *) NULL))
2867  {
2868  if (cos_theta != (double *) NULL)
2869  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
2870  if (sin_theta != (double *) NULL)
2871  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
2872  blur_image=DestroyImage(blur_image);
2873  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2874  }
2875  offset=theta*(double) (n-1)/2.0;
2876  for (i=0; i < (ssize_t) n; i++)
2877  {
2878  cos_theta[i]=cos((double) (theta*i-offset));
2879  sin_theta[i]=sin((double) (theta*i-offset));
2880  }
2881  /*
2882  Radial blur image.
2883  */
2884  status=MagickTrue;
2885  progress=0;
2886  image_view=AcquireVirtualCacheView(image,exception);
2887  radial_view=AcquireVirtualCacheView(image,exception);
2888  blur_view=AcquireAuthenticCacheView(blur_image,exception);
2889 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2890  #pragma omp parallel for schedule(static) shared(progress,status) \
2891  magick_number_threads(image,blur_image,image->rows,1)
2892 #endif
2893  for (y=0; y < (ssize_t) image->rows; y++)
2894  {
2895  register const Quantum
2896  *magick_restrict p;
2897 
2898  register Quantum
2899  *magick_restrict q;
2900 
2901  register ssize_t
2902  x;
2903 
2904  if (status == MagickFalse)
2905  continue;
2906  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2907  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2908  exception);
2909  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2910  {
2911  status=MagickFalse;
2912  continue;
2913  }
2914  for (x=0; x < (ssize_t) image->columns; x++)
2915  {
2916  double
2917  radius;
2918 
2919  PointInfo
2920  center;
2921 
2922  register ssize_t
2923  i;
2924 
2925  size_t
2926  step;
2927 
2928  center.x=(double) x-blur_center.x;
2929  center.y=(double) y-blur_center.y;
2930  radius=hypot((double) center.x,center.y);
2931  if (radius == 0)
2932  step=1;
2933  else
2934  {
2935  step=(size_t) (blur_radius/radius);
2936  if (step == 0)
2937  step=1;
2938  else
2939  if (step >= n)
2940  step=n-1;
2941  }
2942  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2943  {
2944  double
2945  gamma,
2946  pixel;
2947 
2948  PixelChannel
2949  channel;
2950 
2951  PixelTrait
2952  blur_traits,
2953  traits;
2954 
2955  register const Quantum
2956  *magick_restrict r;
2957 
2958  register ssize_t
2959  j;
2960 
2961  channel=GetPixelChannelChannel(image,i);
2962  traits=GetPixelChannelTraits(image,channel);
2963  blur_traits=GetPixelChannelTraits(blur_image,channel);
2964  if ((traits == UndefinedPixelTrait) ||
2965  (blur_traits == UndefinedPixelTrait))
2966  continue;
2967  if ((blur_traits & CopyPixelTrait) != 0)
2968  {
2969  SetPixelChannel(blur_image,channel,p[i],q);
2970  continue;
2971  }
2972  gamma=0.0;
2973  pixel=0.0;
2975  (channel == AlphaPixelChannel))
2976  {
2977  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
2978  {
2979  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
2980  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
2981  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
2982  1,1,exception);
2983  if (r == (const Quantum *) NULL)
2984  {
2985  status=MagickFalse;
2986  continue;
2987  }
2988  pixel+=r[i];
2989  gamma++;
2990  }
2991  gamma=PerceptibleReciprocal(gamma);
2992  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2993  continue;
2994  }
2995  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
2996  {
2997  double
2998  alpha;
2999 
3000  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3001  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3002  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3003  1,1,exception);
3004  if (r == (const Quantum *) NULL)
3005  {
3006  status=MagickFalse;
3007  continue;
3008  }
3009  alpha=(double) QuantumScale*GetPixelAlpha(image,r);
3010  pixel+=alpha*r[i];
3011  gamma+=alpha;
3012  }
3013  gamma=PerceptibleReciprocal(gamma);
3014  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3015  }
3016  p+=GetPixelChannels(image);
3017  q+=GetPixelChannels(blur_image);
3018  }
3019  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3020  status=MagickFalse;
3021  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3022  {
3024  proceed;
3025 
3026 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3027  #pragma omp atomic
3028 #endif
3029  progress++;
3030  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3031  if (proceed == MagickFalse)
3032  status=MagickFalse;
3033  }
3034  }
3035  blur_view=DestroyCacheView(blur_view);
3036  radial_view=DestroyCacheView(radial_view);
3037  image_view=DestroyCacheView(image_view);
3038  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
3039  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
3040  if (status == MagickFalse)
3041  blur_image=DestroyImage(blur_image);
3042  return(blur_image);
3043 }
3044 
3045 /*
3046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047 % %
3048 % %
3049 % %
3050 % S e l e c t i v e B l u r I m a g e %
3051 % %
3052 % %
3053 % %
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 %
3056 % SelectiveBlurImage() selectively blur pixels within a contrast threshold.
3057 % It is similar to the unsharpen mask that sharpens everything with contrast
3058 % above a certain threshold.
3059 %
3060 % The format of the SelectiveBlurImage method is:
3061 %
3062 % Image *SelectiveBlurImage(const Image *image,const double radius,
3063 % const double sigma,const double threshold,ExceptionInfo *exception)
3064 %
3065 % A description of each parameter follows:
3066 %
3067 % o image: the image.
3068 %
3069 % o radius: the radius of the Gaussian, in pixels, not counting the center
3070 % pixel.
3071 %
3072 % o sigma: the standard deviation of the Gaussian, in pixels.
3073 %
3074 % o threshold: only pixels within this contrast threshold are included
3075 % in the blur operation.
3076 %
3077 % o exception: return any errors or warnings in this structure.
3078 %
3079 */
3080 MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
3081  const double sigma,const double threshold,ExceptionInfo *exception)
3082 {
3083 #define SelectiveBlurImageTag "SelectiveBlur/Image"
3084 
3085  CacheView
3086  *blur_view,
3087  *image_view,
3088  *luminance_view;
3089 
3090  Image
3091  *blur_image,
3092  *luminance_image;
3093 
3095  status;
3096 
3098  progress;
3099 
3101  *kernel;
3102 
3103  register ssize_t
3104  i;
3105 
3106  size_t
3107  width;
3108 
3109  ssize_t
3110  center,
3111  j,
3112  u,
3113  v,
3114  y;
3115 
3116  /*
3117  Initialize blur image attributes.
3118  */
3119  assert(image != (Image *) NULL);
3120  assert(image->signature == MagickCoreSignature);
3121  if (image->debug != MagickFalse)
3122  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3123  assert(exception != (ExceptionInfo *) NULL);
3124  assert(exception->signature == MagickCoreSignature);
3125  width=GetOptimalKernelWidth1D(radius,sigma);
3127  width,width*sizeof(*kernel)));
3128  if (kernel == (MagickRealType *) NULL)
3129  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3130  j=(ssize_t) (width-1)/2;
3131  i=0;
3132  for (v=(-j); v <= j; v++)
3133  {
3134  for (u=(-j); u <= j; u++)
3135  kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
3136  MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3137  }
3138  if (image->debug != MagickFalse)
3139  {
3140  char
3141  format[MagickPathExtent],
3142  *message;
3143 
3144  register const MagickRealType
3145  *k;
3146 
3147  ssize_t
3148  u,
3149  v;
3150 
3152  " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
3153  width);
3154  message=AcquireString("");
3155  k=kernel;
3156  for (v=0; v < (ssize_t) width; v++)
3157  {
3158  *message='\0';
3159  (void) FormatLocaleString(format,MagickPathExtent,"%.20g: ",(double) v);
3160  (void) ConcatenateString(&message,format);
3161  for (u=0; u < (ssize_t) width; u++)
3162  {
3163  (void) FormatLocaleString(format,MagickPathExtent,"%+f ",(double)
3164  *k++);
3165  (void) ConcatenateString(&message,format);
3166  }
3167  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
3168  }
3169  message=DestroyString(message);
3170  }
3171  blur_image=CloneImage(image,0,0,MagickTrue,exception);
3172  if (blur_image == (Image *) NULL)
3173  return((Image *) NULL);
3174  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3175  {
3176  blur_image=DestroyImage(blur_image);
3177  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3178  return((Image *) NULL);
3179  }
3180  luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3181  if (luminance_image == (Image *) NULL)
3182  {
3183  blur_image=DestroyImage(blur_image);
3184  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3185  return((Image *) NULL);
3186  }
3187  status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3188  if (status == MagickFalse)
3189  {
3190  luminance_image=DestroyImage(luminance_image);
3191  blur_image=DestroyImage(blur_image);
3192  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3193  return((Image *) NULL);
3194  }
3195  /*
3196  Threshold blur image.
3197  */
3198  status=MagickTrue;
3199  progress=0;
3200  center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3201  ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3202  image_view=AcquireVirtualCacheView(image,exception);
3203  luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3204  blur_view=AcquireAuthenticCacheView(blur_image,exception);
3205 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3206  #pragma omp parallel for schedule(static) shared(progress,status) \
3207  magick_number_threads(image,blur_image,image->rows,1)
3208 #endif
3209  for (y=0; y < (ssize_t) image->rows; y++)
3210  {
3211  double
3212  contrast;
3213 
3215  sync;
3216 
3217  register const Quantum
3218  *magick_restrict l,
3219  *magick_restrict p;
3220 
3221  register Quantum
3222  *magick_restrict q;
3223 
3224  register ssize_t
3225  x;
3226 
3227  if (status == MagickFalse)
3228  continue;
3229  p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3230  ((width-1)/2L),image->columns+width,width,exception);
3231  l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3232  (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3233  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3234  exception);
3235  if ((p == (const Quantum *) NULL) || (l == (const Quantum *) NULL) ||
3236  (q == (Quantum *) NULL))
3237  {
3238  status=MagickFalse;
3239  continue;
3240  }
3241  for (x=0; x < (ssize_t) image->columns; x++)
3242  {
3243  double
3244  intensity;
3245 
3246  register ssize_t
3247  i;
3248 
3249  intensity=GetPixelIntensity(image,p+center);
3250  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3251  {
3252  double
3253  alpha,
3254  gamma,
3255  pixel;
3256 
3257  PixelChannel
3258  channel;
3259 
3260  PixelTrait
3261  blur_traits,
3262  traits;
3263 
3264  register const MagickRealType
3265  *magick_restrict k;
3266 
3267  register const Quantum
3268  *magick_restrict luminance_pixels,
3269  *magick_restrict pixels;
3270 
3271  register ssize_t
3272  u;
3273 
3274  ssize_t
3275  v;
3276 
3277  channel=GetPixelChannelChannel(image,i);
3278  traits=GetPixelChannelTraits(image,channel);
3279  blur_traits=GetPixelChannelTraits(blur_image,channel);
3280  if ((traits == UndefinedPixelTrait) ||
3281  (blur_traits == UndefinedPixelTrait))
3282  continue;
3283  if ((blur_traits & CopyPixelTrait) != 0)
3284  {
3285  SetPixelChannel(blur_image,channel,p[center+i],q);
3286  continue;
3287  }
3288  k=kernel;
3289  pixel=0.0;
3290  pixels=p;
3291  luminance_pixels=l;
3292  gamma=0.0;
3293  if ((blur_traits & BlendPixelTrait) == 0)
3294  {
3295  for (v=0; v < (ssize_t) width; v++)
3296  {
3297  for (u=0; u < (ssize_t) width; u++)
3298  {
3299  contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3300  intensity;
3301  if (fabs(contrast) < threshold)
3302  {
3303  pixel+=(*k)*pixels[i];
3304  gamma+=(*k);
3305  }
3306  k++;
3307  pixels+=GetPixelChannels(image);
3308  luminance_pixels+=GetPixelChannels(luminance_image);
3309  }
3310  pixels+=GetPixelChannels(image)*image->columns;
3311  luminance_pixels+=GetPixelChannels(luminance_image)*
3312  luminance_image->columns;
3313  }
3314  if (fabs((double) gamma) < MagickEpsilon)
3315  {
3316  SetPixelChannel(blur_image,channel,p[center+i],q);
3317  continue;
3318  }
3319  gamma=PerceptibleReciprocal(gamma);
3320  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3321  continue;
3322  }
3323  for (v=0; v < (ssize_t) width; v++)
3324  {
3325  for (u=0; u < (ssize_t) width; u++)
3326  {
3327  contrast=GetPixelIntensity(image,pixels)-intensity;
3328  if (fabs(contrast) < threshold)
3329  {
3330  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
3331  pixel+=(*k)*alpha*pixels[i];
3332  gamma+=(*k)*alpha;
3333  }
3334  k++;
3335  pixels+=GetPixelChannels(image);
3336  luminance_pixels+=GetPixelChannels(luminance_image);
3337  }
3338  pixels+=GetPixelChannels(image)*image->columns;
3339  luminance_pixels+=GetPixelChannels(luminance_image)*
3340  luminance_image->columns;
3341  }
3342  if (fabs((double) gamma) < MagickEpsilon)
3343  {
3344  SetPixelChannel(blur_image,channel,p[center+i],q);
3345  continue;
3346  }
3347  gamma=PerceptibleReciprocal(gamma);
3348  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3349  }
3350  p+=GetPixelChannels(image);
3351  l+=GetPixelChannels(luminance_image);
3352  q+=GetPixelChannels(blur_image);
3353  }
3354  sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3355  if (sync == MagickFalse)
3356  status=MagickFalse;
3357  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3358  {
3360  proceed;
3361 
3362 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3363  #pragma omp atomic
3364 #endif
3365  progress++;
3366  proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3367  image->rows);
3368  if (proceed == MagickFalse)
3369  status=MagickFalse;
3370  }
3371  }
3372  blur_image->type=image->type;
3373  blur_view=DestroyCacheView(blur_view);
3374  luminance_view=DestroyCacheView(luminance_view);
3375  image_view=DestroyCacheView(image_view);
3376  luminance_image=DestroyImage(luminance_image);
3377  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3378  if (status == MagickFalse)
3379  blur_image=DestroyImage(blur_image);
3380  return(blur_image);
3381 }
3382 
3383 /*
3384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3385 % %
3386 % %
3387 % %
3388 % S h a d e I m a g e %
3389 % %
3390 % %
3391 % %
3392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3393 %
3394 % ShadeImage() shines a distant light on an image to create a
3395 % three-dimensional effect. You control the positioning of the light with
3396 % azimuth and elevation; azimuth is measured in degrees off the x axis
3397 % and elevation is measured in pixels above the Z axis.
3398 %
3399 % The format of the ShadeImage method is:
3400 %
3401 % Image *ShadeImage(const Image *image,const MagickBooleanType gray,
3402 % const double azimuth,const double elevation,ExceptionInfo *exception)
3403 %
3404 % A description of each parameter follows:
3405 %
3406 % o image: the image.
3407 %
3408 % o gray: A value other than zero shades the intensity of each pixel.
3409 %
3410 % o azimuth, elevation: Define the light source direction.
3411 %
3412 % o exception: return any errors or warnings in this structure.
3413 %
3414 */
3416  const double azimuth,const double elevation,ExceptionInfo *exception)
3417 {
3418 #define GetShadeIntensity(image,pixel) \
3419  ClampPixel(GetPixelIntensity((image),(pixel)))
3420 #define ShadeImageTag "Shade/Image"
3421 
3422  CacheView
3423  *image_view,
3424  *shade_view;
3425 
3426  Image
3427  *linear_image,
3428  *shade_image;
3429 
3431  status;
3432 
3434  progress;
3435 
3436  PrimaryInfo
3437  light;
3438 
3439  ssize_t
3440  y;
3441 
3442  /*
3443  Initialize shaded image attributes.
3444  */
3445  assert(image != (const Image *) NULL);
3446  assert(image->signature == MagickCoreSignature);
3447  if (image->debug != MagickFalse)
3448  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3449  assert(exception != (ExceptionInfo *) NULL);
3450  assert(exception->signature == MagickCoreSignature);
3451  linear_image=CloneImage(image,0,0,MagickTrue,exception);
3452  shade_image=CloneImage(image,0,0,MagickTrue,exception);
3453  if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
3454  {
3455  if (linear_image != (Image *) NULL)
3456  linear_image=DestroyImage(linear_image);
3457  if (shade_image != (Image *) NULL)
3458  shade_image=DestroyImage(shade_image);
3459  return((Image *) NULL);
3460  }
3461  if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3462  {
3463  linear_image=DestroyImage(linear_image);
3464  shade_image=DestroyImage(shade_image);
3465  return((Image *) NULL);
3466  }
3467  /*
3468  Compute the light vector.
3469  */
3470  light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3471  cos(DegreesToRadians(elevation));
3472  light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3473  cos(DegreesToRadians(elevation));
3474  light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3475  /*
3476  Shade image.
3477  */
3478  status=MagickTrue;
3479  progress=0;
3480  image_view=AcquireVirtualCacheView(linear_image,exception);
3481  shade_view=AcquireAuthenticCacheView(shade_image,exception);
3482 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3483  #pragma omp parallel for schedule(static) shared(progress,status) \
3484  magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3485 #endif
3486  for (y=0; y < (ssize_t) linear_image->rows; y++)
3487  {
3488  double
3489  distance,
3490  normal_distance,
3491  shade;
3492 
3493  PrimaryInfo
3494  normal;
3495 
3496  register const Quantum
3497  *magick_restrict center,
3498  *magick_restrict p,
3499  *magick_restrict post,
3500  *magick_restrict pre;
3501 
3502  register Quantum
3503  *magick_restrict q;
3504 
3505  register ssize_t
3506  x;
3507 
3508  if (status == MagickFalse)
3509  continue;
3510  p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3511  exception);
3512  q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3513  exception);
3514  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3515  {
3516  status=MagickFalse;
3517  continue;
3518  }
3519  /*
3520  Shade this row of pixels.
3521  */
3522  normal.z=2.0*(double) QuantumRange; /* constant Z of surface normal */
3523  for (x=0; x < (ssize_t) linear_image->columns; x++)
3524  {
3525  register ssize_t
3526  i;
3527 
3528  /*
3529  Determine the surface normal and compute shading.
3530  */
3531  pre=p+GetPixelChannels(linear_image);
3532  center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3533  post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3534  normal.x=(double) (
3535  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3536  GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3537  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3538  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3539  GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3540  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3541  normal.y=(double) (
3542  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3543  GetShadeIntensity(linear_image,post)+
3544  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3545  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3546  GetShadeIntensity(linear_image,pre)-
3547  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3548  if ((fabs(normal.x) <= MagickEpsilon) &&
3549  (fabs(normal.y) <= MagickEpsilon))
3550  shade=light.z;
3551  else
3552  {
3553  shade=0.0;
3554  distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3555  if (distance > MagickEpsilon)
3556  {
3557  normal_distance=normal.x*normal.x+normal.y*normal.y+
3558  normal.z*normal.z;
3559  if (normal_distance > (MagickEpsilon*MagickEpsilon))
3560  shade=distance/sqrt((double) normal_distance);
3561  }
3562  }
3563  for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3564  {
3565  PixelChannel
3566  channel;
3567 
3568  PixelTrait
3569  shade_traits,
3570  traits;
3571 
3572  channel=GetPixelChannelChannel(linear_image,i);
3573  traits=GetPixelChannelTraits(linear_image,channel);
3574  shade_traits=GetPixelChannelTraits(shade_image,channel);
3575  if ((traits == UndefinedPixelTrait) ||
3576  (shade_traits == UndefinedPixelTrait))
3577  continue;
3578  if ((shade_traits & CopyPixelTrait) != 0)
3579  {
3580  SetPixelChannel(shade_image,channel,center[i],q);
3581  continue;
3582  }
3583  if ((traits & UpdatePixelTrait) == 0)
3584  {
3585  SetPixelChannel(shade_image,channel,center[i],q);
3586  continue;
3587  }
3588  if (gray != MagickFalse)
3589  {
3590  SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3591  continue;
3592  }
3593  SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
3594  center[i]),q);
3595  }
3596  p+=GetPixelChannels(linear_image);
3597  q+=GetPixelChannels(shade_image);
3598  }
3599  if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3600  status=MagickFalse;
3601  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3602  {
3604  proceed;
3605 
3606 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3607  #pragma omp atomic
3608 #endif
3609  progress++;
3610  proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3611  if (proceed == MagickFalse)
3612  status=MagickFalse;
3613  }
3614  }
3615  shade_view=DestroyCacheView(shade_view);
3616  image_view=DestroyCacheView(image_view);
3617  linear_image=DestroyImage(linear_image);
3618  if (status == MagickFalse)
3619  shade_image=DestroyImage(shade_image);
3620  return(shade_image);
3621 }
3622 
3623 /*
3624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625 % %
3626 % %
3627 % %
3628 % S h a r p e n I m a g e %
3629 % %
3630 % %
3631 % %
3632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3633 %
3634 % SharpenImage() sharpens the image. We convolve the image with a Gaussian
3635 % operator of the given radius and standard deviation (sigma). For
3636 % reasonable results, radius should be larger than sigma. Use a radius of 0
3637 % and SharpenImage() selects a suitable radius for you.
3638 %
3639 % Using a separable kernel would be faster, but the negative weights cancel
3640 % out on the corners of the kernel producing often undesirable ringing in the
3641 % filtered result; this can be avoided by using a 2D gaussian shaped image
3642 % sharpening kernel instead.
3643 %
3644 % The format of the SharpenImage method is:
3645 %
3646 % Image *SharpenImage(const Image *image,const double radius,
3647 % const double sigma,ExceptionInfo *exception)
3648 %
3649 % A description of each parameter follows:
3650 %
3651 % o image: the image.
3652 %
3653 % o radius: the radius of the Gaussian, in pixels, not counting the center
3654 % pixel.
3655 %
3656 % o sigma: the standard deviation of the Laplacian, in pixels.
3657 %
3658 % o exception: return any errors or warnings in this structure.
3659 %
3660 */
3661 MagickExport Image *SharpenImage(const Image *image,const double radius,
3662  const double sigma,ExceptionInfo *exception)
3663 {
3664  double
3665  gamma,
3666  normalize;
3667 
3668  Image
3669  *sharp_image;
3670 
3671  KernelInfo
3672  *kernel_info;
3673 
3674  register ssize_t
3675  i;
3676 
3677  size_t
3678  width;
3679 
3680  ssize_t
3681  j,
3682  u,
3683  v;
3684 
3685  assert(image != (const Image *) NULL);
3686  assert(image->signature == MagickCoreSignature);
3687  if (image->debug != MagickFalse)
3688  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3689  assert(exception != (ExceptionInfo *) NULL);
3690  assert(exception->signature == MagickCoreSignature);
3691  width=GetOptimalKernelWidth2D(radius,sigma);
3692  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
3693  if (kernel_info == (KernelInfo *) NULL)
3694  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3695  (void) memset(kernel_info,0,sizeof(*kernel_info));
3696  kernel_info->width=width;
3697  kernel_info->height=width;
3698  kernel_info->x=(ssize_t) (width-1)/2;
3699  kernel_info->y=(ssize_t) (width-1)/2;
3700  kernel_info->signature=MagickCoreSignature;
3701  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
3702  AcquireAlignedMemory(kernel_info->width,kernel_info->height*
3703  sizeof(*kernel_info->values)));
3704  if (kernel_info->values == (MagickRealType *) NULL)
3705  {
3706  kernel_info=DestroyKernelInfo(kernel_info);
3707  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3708  }
3709  normalize=0.0;
3710  j=(ssize_t) (kernel_info->width-1)/2;
3711  i=0;
3712  for (v=(-j); v <= j; v++)
3713  {
3714  for (u=(-j); u <= j; u++)
3715  {
3716  kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
3718  normalize+=kernel_info->values[i];
3719  i++;
3720  }
3721  }
3722  kernel_info->values[i/2]=(double) ((-2.0)*normalize);
3723  normalize=0.0;
3724  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
3725  normalize+=kernel_info->values[i];
3726  gamma=PerceptibleReciprocal(normalize);
3727  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
3728  kernel_info->values[i]*=gamma;
3729  sharp_image=ConvolveImage(image,kernel_info,exception);
3730  kernel_info=DestroyKernelInfo(kernel_info);
3731  return(sharp_image);
3732 }
3733 
3734 /*
3735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736 % %
3737 % %
3738 % %
3739 % S p r e a d I m a g e %
3740 % %
3741 % %
3742 % %
3743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3744 %
3745 % SpreadImage() is a special effects method that randomly displaces each
3746 % pixel in a square area defined by the radius parameter.
3747 %
3748 % The format of the SpreadImage method is:
3749 %
3750 % Image *SpreadImage(const Image *image,
3751 % const PixelInterpolateMethod method,const double radius,
3752 % ExceptionInfo *exception)
3753 %
3754 % A description of each parameter follows:
3755 %
3756 % o image: the image.
3757 %
3758 % o method: intepolation method.
3759 %
3760 % o radius: choose a random pixel in a neighborhood of this extent.
3761 %
3762 % o exception: return any errors or warnings in this structure.
3763 %
3764 */
3766  const PixelInterpolateMethod method,const double radius,
3767  ExceptionInfo *exception)
3768 {
3769 #define SpreadImageTag "Spread/Image"
3770 
3771  CacheView
3772  *image_view,
3773  *spread_view;
3774 
3775  Image
3776  *spread_image;
3777 
3779  status;
3780 
3782  progress;
3783 
3784  RandomInfo
3786 
3787  size_t
3788  width;
3789 
3790  ssize_t
3791  y;
3792 
3793 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3794  unsigned long
3795  key;
3796 #endif
3797 
3798  /*
3799  Initialize spread image attributes.
3800  */
3801  assert(image != (Image *) NULL);
3802  assert(image->signature == MagickCoreSignature);
3803  if (image->debug != MagickFalse)
3804  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3805  assert(exception != (ExceptionInfo *) NULL);
3806  assert(exception->signature == MagickCoreSignature);
3807  spread_image=CloneImage(image,0,0,MagickTrue,exception);
3808  if (spread_image == (Image *) NULL)
3809  return((Image *) NULL);
3810  if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
3811  {
3812  spread_image=DestroyImage(spread_image);
3813  return((Image *) NULL);
3814  }
3815  /*
3816  Spread image.
3817  */
3818  status=MagickTrue;
3819  progress=0;
3820  width=GetOptimalKernelWidth1D(radius,0.5);
3821  random_info=AcquireRandomInfoThreadSet();
3822  image_view=AcquireVirtualCacheView(image,exception);
3823  spread_view=AcquireAuthenticCacheView(spread_image,exception);
3824 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3825  key=GetRandomSecretKey(random_info[0]);
3826  #pragma omp parallel for schedule(static) shared(progress,status) \
3827  magick_number_threads(image,spread_image,image->rows,key == ~0UL)
3828 #endif
3829  for (y=0; y < (ssize_t) image->rows; y++)
3830  {
3831  const int
3832  id = GetOpenMPThreadId();
3833 
3834  register Quantum
3835  *magick_restrict q;
3836 
3837  register ssize_t
3838  x;
3839 
3840  if (status == MagickFalse)
3841  continue;
3842  q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
3843  exception);
3844  if (q == (Quantum *) NULL)
3845  {
3846  status=MagickFalse;
3847  continue;
3848  }
3849  for (x=0; x < (ssize_t) image->columns; x++)
3850  {
3851  PointInfo
3852  point;
3853 
3854  point.x=GetPseudoRandomValue(random_info[id]);
3855  point.y=GetPseudoRandomValue(random_info[id]);
3856  status=InterpolatePixelChannels(image,image_view,spread_image,method,
3857  (double) x+width*(point.x-0.5),(double) y+width*(point.y-0.5),q,
3858  exception);
3859  if (status == MagickFalse)
3860  break;
3861  q+=GetPixelChannels(spread_image);
3862  }
3863  if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
3864  status=MagickFalse;
3865  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3866  {
3868  proceed;
3869 
3870 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3871  #pragma omp atomic
3872 #endif
3873  progress++;
3874  proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
3875  if (proceed == MagickFalse)
3876  status=MagickFalse;
3877  }
3878  }
3879  spread_view=DestroyCacheView(spread_view);
3880  image_view=DestroyCacheView(image_view);
3881  random_info=DestroyRandomInfoThreadSet(random_info);
3882  if (status == MagickFalse)
3883  spread_image=DestroyImage(spread_image);
3884  return(spread_image);
3885 }
3886 
3887 /*
3888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3889 % %
3890 % %
3891 % %
3892 % U n s h a r p M a s k I m a g e %
3893 % %
3894 % %
3895 % %
3896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897 %
3898 % UnsharpMaskImage() sharpens one or more image channels. We convolve the
3899 % image with a Gaussian operator of the given radius and standard deviation
3900 % (sigma). For reasonable results, radius should be larger than sigma. Use a
3901 % radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
3902 %
3903 % The format of the UnsharpMaskImage method is:
3904 %
3905 % Image *UnsharpMaskImage(const Image *image,const double radius,
3906 % const double sigma,const double amount,const double threshold,
3907 % ExceptionInfo *exception)
3908 %
3909 % A description of each parameter follows:
3910 %
3911 % o image: the image.
3912 %
3913 % o radius: the radius of the Gaussian, in pixels, not counting the center
3914 % pixel.
3915 %
3916 % o sigma: the standard deviation of the Gaussian, in pixels.
3917 %
3918 % o gain: the percentage of the difference between the original and the
3919 % blur image that is added back into the original.
3920 %
3921 % o threshold: the threshold in pixels needed to apply the diffence gain.
3922 %
3923 % o exception: return any errors or warnings in this structure.
3924 %
3925 */
3926 MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
3927  const double sigma,const double gain,const double threshold,
3928  ExceptionInfo *exception)
3929 {
3930 #define SharpenImageTag "Sharpen/Image"
3931 
3932  CacheView
3933  *image_view,
3934  *unsharp_view;
3935 
3936  Image
3937  *unsharp_image;
3938 
3940  status;
3941 
3943  progress;
3944 
3945  double
3946  quantum_threshold;
3947 
3948  ssize_t
3949  y;
3950 
3951  assert(image != (const Image *) NULL);
3952  assert(image->signature == MagickCoreSignature);
3953  if (image->debug != MagickFalse)
3954  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3955  assert(exception != (ExceptionInfo *) NULL);
3956 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3957  unsharp_image=AccelerateUnsharpMaskImage(image,radius,sigma,gain,threshold,
3958  exception);
3959  if (unsharp_image != (Image *) NULL)
3960  return(unsharp_image);
3961 #endif
3962  unsharp_image=BlurImage(image,radius,sigma,exception);
3963  if (unsharp_image == (Image *) NULL)
3964  return((Image *) NULL);
3965  quantum_threshold=(double) QuantumRange*threshold;
3966  /*
3967  Unsharp-mask image.
3968  */
3969  status=MagickTrue;
3970  progress=0;
3971  image_view=AcquireVirtualCacheView(image,exception);
3972  unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
3973 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3974  #pragma omp parallel for schedule(static) shared(progress,status) \
3975  magick_number_threads(image,unsharp_image,image->rows,1)
3976 #endif
3977  for (y=0; y < (ssize_t) image->rows; y++)
3978  {
3979  register const Quantum
3980  *magick_restrict p;
3981 
3982  register Quantum
3983  *magick_restrict q;
3984 
3985  register ssize_t
3986  x;
3987 
3988  if (status == MagickFalse)
3989  continue;
3990  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3991  q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
3992  exception);
3993  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3994  {
3995  status=MagickFalse;
3996  continue;
3997  }
3998  for (x=0; x < (ssize_t) image->columns; x++)
3999  {
4000  register ssize_t
4001  i;
4002 
4003  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4004  {
4005  double
4006  pixel;
4007 
4008  PixelChannel
4009  channel;
4010 
4011  PixelTrait
4012  traits,
4013  unsharp_traits;
4014 
4015  channel=GetPixelChannelChannel(image,i);
4016  traits=GetPixelChannelTraits(image,channel);
4017  unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4018  if ((traits == UndefinedPixelTrait) ||
4019  (unsharp_traits == UndefinedPixelTrait))
4020  continue;
4021  if ((unsharp_traits & CopyPixelTrait) != 0)
4022  {
4023  SetPixelChannel(unsharp_image,channel,p[i],q);
4024  continue;
4025  }
4026  pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
4027  if (fabs(2.0*pixel) < quantum_threshold)
4028  pixel=(double) p[i];
4029  else
4030  pixel=(double) p[i]+gain*pixel;
4031  SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4032  }
4033  p+=GetPixelChannels(image);
4034  q+=GetPixelChannels(unsharp_image);
4035  }
4036  if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4037  status=MagickFalse;
4038  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4039  {
4041  proceed;
4042 
4043 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4044  #pragma omp atomic
4045 #endif
4046  progress++;
4047  proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4048  if (proceed == MagickFalse)
4049  status=MagickFalse;
4050  }
4051  }
4052  unsharp_image->type=image->type;
4053  unsharp_view=DestroyCacheView(unsharp_view);
4054  image_view=DestroyCacheView(image_view);
4055  if (status == MagickFalse)
4056  unsharp_image=DestroyImage(unsharp_image);
4057  return(unsharp_image);
4058 }
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:3080
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:120
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:2009
#define BlurImageTag
MagickExport MemoryInfo * RelinquishVirtualMemory(MemoryInfo *memory_info)
Definition: memory.c:1136
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:345
#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:1387
#define MagickAssumeAligned(address)
ssize_t y
Definition: geometry.h:116
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:3415
MagickExport Image * UnsharpMaskImage(const Image *image, const double radius, const double sigma, const double gain, const double threshold, ExceptionInfo *exception)
Definition: effect.c:3926
size_t height
Definition: morphology.h:108
MagickExport MagickBooleanType RaiseImage(Image *image, const RectangleInfo *raise_info, const MagickBooleanType raise, ExceptionInfo *exception)
Definition: decorate.c:610
MagickExport const char DefaultTileFrame[]
Definition: image.c:113
PixelInterpolateMethod
Definition: pixel.h:110
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:581
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:4135
MagickExport Image * PreviewImage(const Image *image, const PreviewType preview, ExceptionInfo *exception)
Definition: effect.c:2260
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:1368
#define AdaptiveSharpenImageTag
MagickExport MagickBooleanType InterpolatePixelChannels(const Image *magick_restrict source, const CacheView_ *source_view, const Image *magick_restrict destination, const PixelInterpolateMethod method, const double x, const double y, Quantum *pixel, ExceptionInfo *exception)
Definition: pixel.c:4915
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:2027
MagickExport Image * RotationalBlurImage(const Image *image, const double angle, ExceptionInfo *exception)
Definition: effect.c:2798
#define GetShadeIntensity(image, pixel)
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:499
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:3303
MagickExport Image * SwirlImage(const Image *image, double degrees, const PixelInterpolateMethod method, ExceptionInfo *exception)
Definition: fx.c:5141
char * montage
Definition: image.h:201
#define MagickEpsilon
Definition: magick-type.h:110
size_t width
Definition: geometry.h:130
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:129
MagickExport Image * ThumbnailImage(const Image *image, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: resize.c:4506
MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info)
Definition: random.c:742
Definition: image.h:151
#define DespeckleImageTag
MagickExport MagickBooleanType ContrastImage(Image *image, const MagickBooleanType sharpen, ExceptionInfo *exception)
Definition: enhance.c:1397
char * frame
Definition: montage.h:36
double x
Definition: geometry.h:123
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:158
MagickExport Image * NewImageList(void)
Definition: list.c:938
MagickExport char * AcquireString(const char *source)
Definition: string.c:129
static double PerceptibleReciprocal(const double x)
MagickExport int AcquireUniqueFileResource(char *path)
Definition: resource.c:548
MagickExport Image * LocalContrastImage(const Image *image, const double radius, const double strength, ExceptionInfo *exception)
Definition: effect.c:1678
MagickExport Image * SpreadImage(const Image *image, const PixelInterpolateMethod method, const double radius, ExceptionInfo *exception)
Definition: effect.c:3765
MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, Image *image, ExceptionInfo *exception)
Definition: constitute.c:1031
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:1812
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:543
char filename[MagickPathExtent]
Definition: image.h:480
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:123
static int GetOpenMPThreadId(void)
MagickExport MagickBooleanType ModulateImage(Image *image, const char *modulate, ExceptionInfo *exception)
Definition: enhance.c:3612
#define MagickSQ2PI
Definition: image-private.h:34
MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
Definition: resource.c:1095
MagickExport Image * EmbossImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1265
MagickExport MagickBooleanType SetImageProperty(Image *image, const char *property, const char *value, ExceptionInfo *exception)
Definition: property.c:4121
MagickExport MagickBooleanType ConcatenateString(char **destination, const char *source)
Definition: string.c:492
size_t number_colors
Definition: quantize.h:38
#define MagickSigma
static MagickRealType * GetMotionBlurKernel(const size_t width, const double sigma)
Definition: effect.c:1979
MagickExport Image * RollImage(const Image *image, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: transform.c:1528
MagickExport const char DefaultTileLabel[]
Definition: image.c:115
#define MagickPathExtent
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport void * RelinquishAlignedMemory(void *memory)
Definition: memory.c:1032
MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
Definition: quantize.c:2291
#define MagickMaximumValue
Definition: magick-type.h:111
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:419
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:1413
MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info, Image *image, ExceptionInfo *exception)
Definition: quantize.c:2644
MagickExport Image * RotateImage(const Image *image, const double degrees, ExceptionInfo *exception)
Definition: distort.c:2853
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:115
size_t columns
Definition: image.h:172
#define SelectiveBlurImageTag
ssize_t x
Definition: geometry.h:134
MagickExport Image * DespeckleImage(const Image *image, ExceptionInfo *exception)
Definition: effect.c:973
MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
Definition: random.c:609
size_t height
Definition: geometry.h:130
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:2216
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:2615
MagickExport MagickProgressMonitor SetImageProgressMonitor(Image *image, const MagickProgressMonitor progress_monitor, void *client_data)
Definition: monitor.c:194
MagickExport size_t CopyMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:755
MagickExport Image * DestroyImageList(Image *images)
Definition: list.c:462
PixelChannel
Definition: pixel.h:67
MagickExport void * AcquireAlignedMemory(const size_t count, const size_t quantum)
Definition: memory.c:242
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:410
#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:1576
MagickExport MagickSizeType GetBlobSize(const Image *image)
Definition: blob.c:1803
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1252
MagickExport MagickBooleanType SolarizeImage(Image *image, const double threshold, ExceptionInfo *exception)
Definition: fx.c:4694
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:823
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:78
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:1683
ssize_t x
Definition: geometry.h:116
MagickExport MagickBooleanType BilevelImage(Image *image, const double threshold, ExceptionInfo *exception)
Definition: threshold.c:800
static RandomInfo * random_info
Definition: resource.c:113
MagickExport Image * SharpenImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:3661
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1069
#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:2309
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:286
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:594
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:134
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:5655
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:134
MagickExport void * GetVirtualMemoryBlob(const MemoryInfo *memory_info)
Definition: memory.c:963
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport MontageInfo * CloneMontageInfo(const ImageInfo *image_info, const MontageInfo *montage_info)
Definition: montage.c:104
#define DefaultPreviewGeometry
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1181
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:796
MagickExport Image * StatisticImage(const Image *image, const StatisticType type, const size_t width, const size_t height, ExceptionInfo *exception)
Definition: statistic.c:2852
#define QuantumRange
Definition: magick-type.h:83
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickRealType * values
Definition: morphology.h:116
MagickBooleanType debug
Definition: image.h:334
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)