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