43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/blob.h"
46 #include "magick/cache-view.h"
47 #include "magick/color.h"
48 #include "magick/color-private.h"
49 #include "magick/colorspace.h"
50 #include "magick/constitute.h"
51 #include "magick/decorate.h"
52 #include "magick/distort.h"
53 #include "magick/draw.h"
54 #include "magick/enhance.h"
55 #include "magick/exception.h"
56 #include "magick/exception-private.h"
57 #include "magick/effect.h"
58 #include "magick/fx.h"
59 #include "magick/gem.h"
60 #include "magick/geometry.h"
61 #include "magick/image-private.h"
62 #include "magick/list.h"
63 #include "magick/log.h"
64 #include "magick/matrix.h"
65 #include "magick/memory_.h"
66 #include "magick/memory-private.h"
67 #include "magick/monitor.h"
68 #include "magick/monitor-private.h"
69 #include "magick/montage.h"
70 #include "magick/morphology.h"
71 #include "magick/morphology-private.h"
72 #include "magick/opencl-private.h"
73 #include "magick/paint.h"
74 #include "magick/pixel-accessor.h"
75 #include "magick/pixel-private.h"
76 #include "magick/property.h"
77 #include "magick/quantize.h"
78 #include "magick/quantum.h"
79 #include "magick/random_.h"
80 #include "magick/random-private.h"
81 #include "magick/resample.h"
82 #include "magick/resample-private.h"
83 #include "magick/resize.h"
84 #include "magick/resource_.h"
85 #include "magick/segment.h"
86 #include "magick/shear.h"
87 #include "magick/signature-private.h"
88 #include "magick/statistic.h"
89 #include "magick/string_.h"
90 #include "magick/thread-private.h"
91 #include "magick/transform.h"
92 #include "magick/threshold.h"
94 #ifdef MAGICKCORE_CLPERFMARKER
95 #include "CLPerfMarker.h"
138 MagickExport
Image *AdaptiveBlurImage(
const Image *image,
const double radius,
144 blur_image=AdaptiveBlurImageChannel(image,DefaultChannels,radius,sigma,
149 MagickExport
Image *AdaptiveBlurImageChannel(
const Image *image,
150 const ChannelType channel,
const double radius,
const double sigma,
153 #define AdaptiveBlurImageTag "Convolve/Image"
154 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
192 assert(image != (
const Image *) NULL);
193 assert(image->signature == MagickCoreSignature);
195 assert(exception->signature == MagickCoreSignature);
196 if (IsEventLogging() != MagickFalse)
197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
198 blur_image=CloneImage(image,0,0,MagickTrue,exception);
199 if (blur_image == (
Image *) NULL)
200 return((
Image *) NULL);
201 if (fabs(sigma) <= MagickEpsilon)
203 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
205 InheritException(exception,&blur_image->exception);
206 blur_image=DestroyImage(blur_image);
207 return((
Image *) NULL);
212 edge_image=EdgeImage(image,radius,exception);
213 if (edge_image == (
Image *) NULL)
215 blur_image=DestroyImage(blur_image);
216 return((
Image *) NULL);
218 (void) AutoLevelImage(edge_image);
219 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
220 if (gaussian_image != (
Image *) NULL)
222 edge_image=DestroyImage(edge_image);
223 edge_image=gaussian_image;
225 (void) AutoLevelImage(edge_image);
229 width=GetOptimalKernelWidth2D(radius,sigma);
230 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
232 if (kernel == (
double **) NULL)
234 edge_image=DestroyImage(edge_image);
235 blur_image=DestroyImage(blur_image);
236 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
238 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
239 for (i=0; i < (ssize_t) width; i+=2)
241 kernel[i]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
242 (width-i),(width-i)*
sizeof(**kernel)));
243 if (kernel[i] == (
double *) NULL)
246 j=(ssize_t) (width-i-1)/2;
248 for (v=(-j); v <= j; v++)
250 for (u=(-j); u <= j; u++)
252 kernel[i][k]=(double) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
253 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
254 normalize+=kernel[i][k];
258 kernel[i][(k-1)/2]+=(1.0-normalize);
259 if (sigma < MagickEpsilon)
260 kernel[i][(k-1)/2]=1.0;
262 if (i < (ssize_t) width)
264 for (i-=2; i >= 0; i-=2)
265 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
266 kernel=(
double **) RelinquishAlignedMemory(kernel);
267 edge_image=DestroyImage(edge_image);
268 blur_image=DestroyImage(blur_image);
269 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
276 GetMagickPixelPacket(image,&bias);
277 SetMagickPixelPacketBias(image,&bias);
278 image_view=AcquireVirtualCacheView(image,exception);
279 edge_view=AcquireVirtualCacheView(edge_image,exception);
280 blur_view=AcquireAuthenticCacheView(blur_image,exception);
281 #if defined(MAGICKCORE_OPENMP_SUPPORT)
282 #pragma omp parallel for schedule(static) shared(progress,status) \
283 magick_number_threads(image,blur_image,blur_image->rows,1)
285 for (y=0; y < (ssize_t) blur_image->rows; y++)
288 *magick_restrict indexes;
295 *magick_restrict blur_indexes;
303 if (status == MagickFalse)
305 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
306 q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
313 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
314 for (x=0; x < (ssize_t) blur_image->columns; x++)
332 i=CastDoubleToLong(ceil((
double) width*QuantumScale*
333 GetPixelIntensity(edge_image,r)-0.5));
337 if (i > (ssize_t) width)
341 p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
342 (ssize_t) ((width-i)/2L),width-i,width-i,exception);
345 indexes=GetCacheViewVirtualIndexQueue(image_view);
347 pixel.green=bias.green;
348 pixel.blue=bias.blue;
349 pixel.opacity=bias.opacity;
350 pixel.index=bias.index;
352 for (v=0; v < (ssize_t) (width-i); v++)
354 for (u=0; u < (ssize_t) (width-i); u++)
357 if (((channel & OpacityChannel) != 0) &&
358 (image->matte != MagickFalse))
359 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(p));
360 if ((channel & RedChannel) != 0)
361 pixel.red+=(*k)*alpha*GetPixelRed(p);
362 if ((channel & GreenChannel) != 0)
363 pixel.green+=(*k)*alpha*GetPixelGreen(p);
364 if ((channel & BlueChannel) != 0)
365 pixel.blue+=(*k)*alpha*GetPixelBlue(p);
366 if ((channel & OpacityChannel) != 0)
367 pixel.opacity+=(*k)*GetPixelOpacity(p);
368 if (((channel & IndexChannel) != 0) &&
369 (image->colorspace == CMYKColorspace))
370 pixel.index+=(*k)*alpha*GetPixelIndex(indexes+x+(width-i)*v+u);
376 gamma=PerceptibleReciprocal(gamma);
377 if ((channel & RedChannel) != 0)
378 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
379 if ((channel & GreenChannel) != 0)
380 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
381 if ((channel & BlueChannel) != 0)
382 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
383 if ((channel & OpacityChannel) != 0)
384 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
385 if (((channel & IndexChannel) != 0) &&
386 (image->colorspace == CMYKColorspace))
387 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*pixel.index));
391 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
393 if (image->progress_monitor != (MagickProgressMonitor) NULL)
398 #if defined(MAGICKCORE_OPENMP_SUPPORT)
402 proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
404 if (proceed == MagickFalse)
408 blur_image->type=image->type;
409 blur_view=DestroyCacheView(blur_view);
410 edge_view=DestroyCacheView(edge_view);
411 image_view=DestroyCacheView(image_view);
412 edge_image=DestroyImage(edge_image);
413 for (i=0; i < (ssize_t) width; i+=2)
414 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
415 kernel=(
double **) RelinquishAlignedMemory(kernel);
416 if (status == MagickFalse)
417 blur_image=DestroyImage(blur_image);
461 MagickExport
Image *AdaptiveSharpenImage(
const Image *image,
const double radius,
467 sharp_image=AdaptiveSharpenImageChannel(image,DefaultChannels,radius,sigma,
472 MagickExport
Image *AdaptiveSharpenImageChannel(
const Image *image,
473 const ChannelType channel,
const double radius,
const double sigma,
476 #define AdaptiveSharpenImageTag "Convolve/Image"
477 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
515 assert(image != (
const Image *) NULL);
516 assert(image->signature == MagickCoreSignature);
518 assert(exception->signature == MagickCoreSignature);
519 if (IsEventLogging() != MagickFalse)
520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
521 sharp_image=CloneImage(image,0,0,MagickTrue,exception);
522 if (sharp_image == (
Image *) NULL)
523 return((
Image *) NULL);
524 if (fabs(sigma) <= MagickEpsilon)
526 if (SetImageStorageClass(sharp_image,DirectClass) == MagickFalse)
528 InheritException(exception,&sharp_image->exception);
529 sharp_image=DestroyImage(sharp_image);
530 return((
Image *) NULL);
535 edge_image=EdgeImage(image,radius,exception);
536 if (edge_image == (
Image *) NULL)
538 sharp_image=DestroyImage(sharp_image);
539 return((
Image *) NULL);
541 (void) AutoLevelImage(edge_image);
542 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
543 if (gaussian_image != (
Image *) NULL)
545 edge_image=DestroyImage(edge_image);
546 edge_image=gaussian_image;
548 (void) AutoLevelImage(edge_image);
552 width=GetOptimalKernelWidth2D(radius,sigma);
553 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
555 if (kernel == (
double **) NULL)
557 edge_image=DestroyImage(edge_image);
558 sharp_image=DestroyImage(sharp_image);
559 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
561 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
562 for (i=0; i < (ssize_t) width; i+=2)
564 kernel[i]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
565 (width-i),(width-i)*
sizeof(**kernel)));
566 if (kernel[i] == (
double *) NULL)
569 j=(ssize_t) (width-i-1)/2;
571 for (v=(-j); v <= j; v++)
573 for (u=(-j); u <= j; u++)
575 kernel[i][k]=(double) (-exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
576 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
577 normalize+=kernel[i][k];
581 kernel[i][(k-1)/2]=(
double) ((-2.0)*normalize);
582 if (sigma < MagickEpsilon)
583 kernel[i][(k-1)/2]=1.0;
585 if (i < (ssize_t) width)
587 for (i-=2; i >= 0; i-=2)
588 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
589 kernel=(
double **) RelinquishAlignedMemory(kernel);
590 edge_image=DestroyImage(edge_image);
591 sharp_image=DestroyImage(sharp_image);
592 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
599 GetMagickPixelPacket(image,&bias);
600 SetMagickPixelPacketBias(image,&bias);
601 image_view=AcquireVirtualCacheView(image,exception);
602 edge_view=AcquireVirtualCacheView(edge_image,exception);
603 sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
604 #if defined(MAGICKCORE_OPENMP_SUPPORT)
605 #pragma omp parallel for schedule(static) shared(progress,status) \
606 magick_number_threads(image,sharp_image,sharp_image->rows,1)
608 for (y=0; y < (ssize_t) sharp_image->rows; y++)
611 *magick_restrict indexes;
618 *magick_restrict sharp_indexes;
626 if (status == MagickFalse)
628 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
629 q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
636 sharp_indexes=GetCacheViewAuthenticIndexQueue(sharp_view);
637 for (x=0; x < (ssize_t) sharp_image->columns; x++)
655 i=CastDoubleToLong(ceil((
double) width*(1.0-QuantumScale*
656 GetPixelIntensity(edge_image,r))-0.5));
660 if (i > (ssize_t) width)
664 p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
665 (ssize_t) ((width-i)/2L),width-i,width-i,exception);
668 indexes=GetCacheViewVirtualIndexQueue(image_view);
671 pixel.green=bias.green;
672 pixel.blue=bias.blue;
673 pixel.opacity=bias.opacity;
674 pixel.index=bias.index;
675 for (v=0; v < (ssize_t) (width-i); v++)
677 for (u=0; u < (ssize_t) (width-i); u++)
680 if (((channel & OpacityChannel) != 0) &&
681 (image->matte != MagickFalse))
682 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(p));
683 if ((channel & RedChannel) != 0)
684 pixel.red+=(*k)*alpha*GetPixelRed(p);
685 if ((channel & GreenChannel) != 0)
686 pixel.green+=(*k)*alpha*GetPixelGreen(p);
687 if ((channel & BlueChannel) != 0)
688 pixel.blue+=(*k)*alpha*GetPixelBlue(p);
689 if ((channel & OpacityChannel) != 0)
690 pixel.opacity+=(*k)*GetPixelOpacity(p);
691 if (((channel & IndexChannel) != 0) &&
692 (image->colorspace == CMYKColorspace))
693 pixel.index+=(*k)*alpha*GetPixelIndex(indexes+x+(width-i)*v+u);
699 gamma=PerceptibleReciprocal(gamma);
700 if ((channel & RedChannel) != 0)
701 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
702 if ((channel & GreenChannel) != 0)
703 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
704 if ((channel & BlueChannel) != 0)
705 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
706 if ((channel & OpacityChannel) != 0)
707 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
708 if (((channel & IndexChannel) != 0) &&
709 (image->colorspace == CMYKColorspace))
710 SetPixelIndex(sharp_indexes+x,ClampToQuantum(gamma*pixel.index));
714 if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
716 if (image->progress_monitor != (MagickProgressMonitor) NULL)
721 #if defined(MAGICKCORE_OPENMP_SUPPORT)
725 proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
727 if (proceed == MagickFalse)
731 sharp_image->type=image->type;
732 sharp_view=DestroyCacheView(sharp_view);
733 edge_view=DestroyCacheView(edge_view);
734 image_view=DestroyCacheView(image_view);
735 edge_image=DestroyImage(edge_image);
736 for (i=0; i < (ssize_t) width; i+=2)
737 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
738 kernel=(
double **) RelinquishAlignedMemory(kernel);
739 if (status == MagickFalse)
740 sharp_image=DestroyImage(sharp_image);
782 MagickExport
Image *BlurImage(
const Image *image,
const double radius,
788 blur_image=BlurImageChannel(image,DefaultChannels,radius,sigma,exception);
792 MagickExport
Image *BlurImageChannel(
const Image *image,
793 const ChannelType channel,
const double radius,
const double sigma,
797 geometry[MaxTextExtent];
805 assert(image != (
const Image *) NULL);
806 assert(image->signature == MagickCoreSignature);
808 assert(exception->signature == MagickCoreSignature);
809 if (IsEventLogging() != MagickFalse)
810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
811 #if defined(MAGICKCORE_OPENCL_SUPPORT)
812 blur_image=AccelerateBlurImage(image,channel,radius,sigma,exception);
813 if (blur_image != (
Image *) NULL)
816 (void) FormatLocaleString(geometry,MaxTextExtent,
817 "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
818 kernel_info=AcquireKernelInfo(geometry);
820 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
821 blur_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
822 kernel_info,exception);
823 kernel_info=DestroyKernelInfo(kernel_info);
861 MagickExport
Image *ConvolveImage(
const Image *image,
const size_t order,
867 #ifdef MAGICKCORE_CLPERFMARKER
868 clBeginPerfMarkerAMD(__FUNCTION__,
"");
871 convolve_image=ConvolveImageChannel(image,DefaultChannels,order,kernel,
874 #ifdef MAGICKCORE_CLPERFMARKER
875 clEndPerfMarkerAMD();
877 return(convolve_image);
880 MagickExport
Image *ConvolveImageChannel(
const Image *image,
881 const ChannelType channel,
const size_t order,
const double *kernel,
893 kernel_info=AcquireKernelInfo((
const char *) NULL);
895 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
896 kernel_info->width=order;
897 kernel_info->height=order;
898 kernel_info->x=(ssize_t) (order-1)/2;
899 kernel_info->y=(ssize_t) (order-1)/2;
900 kernel_info->signature=MagickCoreSignature;
901 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
902 kernel_info->width,kernel_info->width*
sizeof(*kernel_info->values)));
903 if (kernel_info->values == (
double *) NULL)
905 kernel_info=DestroyKernelInfo(kernel_info);
906 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
908 for (i=0; i < (ssize_t) (order*order); i++)
909 kernel_info->values[i]=kernel[i];
910 convolve_image=(
Image *) NULL;
911 #if defined(MAGICKCORE_OPENCL_SUPPORT)
912 convolve_image=AccelerateConvolveImageChannel(image,channel,kernel_info,
915 if (convolve_image == (
Image *) NULL)
916 convolve_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
917 kernel_info,exception);
918 kernel_info=DestroyKernelInfo(kernel_info);
919 return(convolve_image);
952 static void Hull(
const Image *image,
const ssize_t x_offset,
953 const ssize_t y_offset,
const size_t columns,
const size_t rows,
954 const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
965 assert(f != (Quantum *) NULL);
966 assert(g != (Quantum *) NULL);
969 r=p+(y_offset*((ssize_t) columns+2)+x_offset);
970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
971 #pragma omp parallel for schedule(static) \
972 magick_number_threads(image,image,rows,1)
974 for (y=0; y < (ssize_t) rows; y++)
985 for (x=0; x < (ssize_t) columns; x++)
987 v=(SignedQuantum) p[i];
988 if ((SignedQuantum) r[i] >= (v+ScaleCharToQuantum(2)))
989 v+=ScaleCharToQuantum(1);
994 for (x=0; x < (ssize_t) columns; x++)
996 v=(SignedQuantum) p[i];
997 if ((SignedQuantum) r[i] <= (v-ScaleCharToQuantum(2)))
998 v-=ScaleCharToQuantum(1);
1006 r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1007 s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1008 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1009 #pragma omp parallel for schedule(static) \
1010 magick_number_threads(image,image,rows,1)
1012 for (y=0; y < (ssize_t) rows; y++)
1021 i=(2*y+1)+y*columns;
1023 for (x=0; x < (ssize_t) columns; x++)
1025 v=(SignedQuantum) q[i];
1026 if (((SignedQuantum) s[i] >= (v+ScaleCharToQuantum(2))) &&
1027 ((SignedQuantum) r[i] > v))
1028 v+=ScaleCharToQuantum(1);
1033 for (x=0; x < (ssize_t) columns; x++)
1035 v=(SignedQuantum) q[i];
1036 if (((SignedQuantum) s[i] <= (v-ScaleCharToQuantum(2))) &&
1037 ((SignedQuantum) r[i] < v))
1038 v-=ScaleCharToQuantum(1);
1047 #define DespeckleImageTag "Despeckle/Image"
1067 *magick_restrict buffer,
1068 *magick_restrict pixels;
1074 static const ssize_t
1075 X[4] = {0, 1, 1,-1},
1076 Y[4] = {1, 0, 1, 1};
1081 assert(image != (
const Image *) NULL);
1082 assert(image->signature == MagickCoreSignature);
1084 assert(exception->signature == MagickCoreSignature);
1085 if (IsEventLogging() != MagickFalse)
1086 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1087 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1088 despeckle_image=AccelerateDespeckleImage(image, exception);
1089 if (despeckle_image != (
Image *) NULL)
1090 return(despeckle_image);
1092 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1093 if (despeckle_image == (
Image *) NULL)
1094 return((
Image *) NULL);
1095 if (SetImageStorageClass(despeckle_image,DirectClass) == MagickFalse)
1097 InheritException(exception,&despeckle_image->exception);
1098 despeckle_image=DestroyImage(despeckle_image);
1099 return((
Image *) NULL);
1104 length=(size_t) ((image->columns+2)*(image->rows+2));
1105 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1106 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1111 buffer_info=RelinquishVirtualMemory(buffer_info);
1113 pixel_info=RelinquishVirtualMemory(pixel_info);
1114 despeckle_image=DestroyImage(despeckle_image);
1115 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1117 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1118 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1123 number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
1124 image_view=AcquireVirtualCacheView(image,exception);
1125 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1126 for (i=0; i < (ssize_t) number_channels; i++)
1136 if (status == MagickFalse)
1138 if ((image->matte == MagickFalse) && (i == 3))
1140 (void) memset(pixels,0,length*
sizeof(*pixels));
1141 j=(ssize_t) image->columns+2;
1142 for (y=0; y < (ssize_t) image->rows; y++)
1145 *magick_restrict indexes;
1150 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1153 indexes=GetCacheViewVirtualIndexQueue(image_view);
1155 for (x=0; x < (ssize_t) image->columns; x++)
1159 case 0: pixels[j]=GetPixelRed(p);
break;
1160 case 1: pixels[j]=GetPixelGreen(p);
break;
1161 case 2: pixels[j]=GetPixelBlue(p);
break;
1162 case 3: pixels[j]=GetPixelOpacity(p);
break;
1163 case 4: pixels[j]=GetPixelBlack(indexes+x);
break;
1171 (void) memset(buffer,0,length*
sizeof(*buffer));
1172 for (k=0; k < 4; k++)
1174 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1175 Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1176 Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1177 Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1179 j=(ssize_t) image->columns+2;
1180 for (y=0; y < (ssize_t) image->rows; y++)
1186 *magick_restrict indexes;
1191 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1195 indexes=GetCacheViewAuthenticIndexQueue(despeckle_view);
1197 for (x=0; x < (ssize_t) image->columns; x++)
1201 case 0: SetPixelRed(q,pixels[j]);
break;
1202 case 1: SetPixelGreen(q,pixels[j]);
break;
1203 case 2: SetPixelBlue(q,pixels[j]);
break;
1204 case 3: SetPixelOpacity(q,pixels[j]);
break;
1205 case 4: SetPixelIndex(indexes+x,pixels[j]);
break;
1211 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1212 if (sync == MagickFalse)
1219 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1224 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1226 if (proceed == MagickFalse)
1230 despeckle_view=DestroyCacheView(despeckle_view);
1231 image_view=DestroyCacheView(image_view);
1232 buffer_info=RelinquishVirtualMemory(buffer_info);
1233 pixel_info=RelinquishVirtualMemory(pixel_info);
1234 despeckle_image->type=image->type;
1235 if (status == MagickFalse)
1236 despeckle_image=DestroyImage(despeckle_image);
1237 return(despeckle_image);
1269 MagickExport
Image *EdgeImage(
const Image *image,
const double radius,
1284 assert(image != (
const Image *) NULL);
1285 assert(image->signature == MagickCoreSignature);
1287 assert(exception->signature == MagickCoreSignature);
1288 if (IsEventLogging() != MagickFalse)
1289 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1290 width=GetOptimalKernelWidth1D(radius,0.5);
1291 kernel_info=AcquireKernelInfo((
const char *) NULL);
1293 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1294 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1295 kernel_info->width=width;
1296 kernel_info->height=width;
1297 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1298 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1299 kernel_info->signature=MagickCoreSignature;
1300 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
1301 kernel_info->width,kernel_info->height*
sizeof(*kernel_info->values)));
1302 if (kernel_info->values == (
double *) NULL)
1304 kernel_info=DestroyKernelInfo(kernel_info);
1305 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1307 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1308 kernel_info->values[i]=(-1.0);
1309 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1310 edge_image=(
Image *) NULL;
1311 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1312 edge_image=AccelerateConvolveImageChannel(image,DefaultChannels,kernel_info,
1315 if (edge_image == (
Image *) NULL)
1316 edge_image=MorphologyImageChannel(image,DefaultChannels,ConvolveMorphology,
1317 1,kernel_info,exception);
1318 kernel_info=DestroyKernelInfo(kernel_info);
1355 MagickExport
Image *EmbossImage(
const Image *image,
const double radius,
1380 assert(image != (
const Image *) NULL);
1381 assert(image->signature == MagickCoreSignature);
1383 assert(exception->signature == MagickCoreSignature);
1384 if (IsEventLogging() != MagickFalse)
1385 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1386 width=GetOptimalKernelWidth1D(radius,sigma);
1387 kernel_info=AcquireKernelInfo((
const char *) NULL);
1389 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1390 kernel_info->width=width;
1391 kernel_info->height=width;
1392 kernel_info->x=(ssize_t) (width-1)/2;
1393 kernel_info->y=(ssize_t) (width-1)/2;
1394 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
1395 kernel_info->width,kernel_info->width*
sizeof(*kernel_info->values)));
1396 if (kernel_info->values == (
double *) NULL)
1398 kernel_info=DestroyKernelInfo(kernel_info);
1399 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1401 j=(ssize_t) (kernel_info->width-1)/2;
1404 for (v=(-j); v <= j; v++)
1406 for (u=(-j); u <= j; u++)
1408 kernel_info->values[i]=(double) (((u < 0) || (v < 0) ? -8.0 :
1409 8.0)*exp(-((
double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1410 (2.0*MagickPI*MagickSigma*MagickSigma));
1412 kernel_info->values[i]=0.0;
1418 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1419 normalize+=kernel_info->values[i];
1420 gamma=PerceptibleReciprocal(normalize);
1421 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1422 kernel_info->values[i]*=gamma;
1423 emboss_image=(
Image *) NULL;
1424 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1425 emboss_image=AccelerateConvolveImageChannel(image,DefaultChannels,kernel_info,
1428 if (emboss_image == (
Image *) NULL)
1429 emboss_image=MorphologyImageChannel(image,DefaultChannels,
1430 ConvolveMorphology,1,kernel_info,exception);
1431 kernel_info=DestroyKernelInfo(kernel_info);
1432 if (emboss_image != (
Image *) NULL)
1433 (void) EqualizeImageChannel(emboss_image,(ChannelType)
1434 (AllChannels &~ SyncChannels));
1435 return(emboss_image);
1476 filter_image=FilterImageChannel(image,DefaultChannels,kernel,exception);
1477 return(filter_image);
1480 MagickExport
Image *FilterImageChannel(
const Image *image,
1483 #define FilterImageTag "Filter/Image"
1510 #ifdef MAGICKCORE_CLPERFMARKER
1511 clBeginPerfMarkerAMD(__FUNCTION__,
"");
1517 assert(image != (
Image *) NULL);
1518 assert(image->signature == MagickCoreSignature);
1520 assert(exception->signature == MagickCoreSignature);
1521 if (IsEventLogging() != MagickFalse)
1522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1523 if ((kernel->width % 2) == 0)
1524 ThrowImageException(OptionError,
"KernelWidthMustBeAnOddNumber");
1525 if (image->debug != MagickFalse)
1528 format[MaxTextExtent],
1538 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1539 " FilterImage with %.20gx%.20g kernel:",(double) kernel->width,(
double)
1541 message=AcquireString(
"");
1543 for (v=0; v < (ssize_t) kernel->height; v++)
1546 (void) FormatLocaleString(format,MaxTextExtent,
"%.20g: ",(
double) v);
1547 (void) ConcatenateString(&message,format);
1548 for (u=0; u < (ssize_t) kernel->width; u++)
1550 (void) FormatLocaleString(format,MaxTextExtent,
"%g ",*k++);
1551 (void) ConcatenateString(&message,format);
1553 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
1555 message=DestroyString(message);
1557 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1558 filter_image=AccelerateConvolveImageChannel(image,channel,kernel,exception);
1559 if (filter_image != (
Image *) NULL)
1561 #ifdef MAGICKCORE_CLPERFMARKER
1562 clEndPerfMarkerAMD();
1564 return(filter_image);
1567 filter_image=CloneImage(image,0,0,MagickTrue,exception);
1568 if (filter_image == (
Image *) NULL)
1569 return((
Image *) NULL);
1570 if (SetImageStorageClass(filter_image,DirectClass) == MagickFalse)
1572 InheritException(exception,&filter_image->exception);
1573 filter_image=DestroyImage(filter_image);
1574 return((
Image *) NULL);
1579 filter_kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
1580 kernel->width,kernel->height*
sizeof(*filter_kernel)));
1581 if (filter_kernel == (MagickRealType *) NULL)
1583 filter_image=DestroyImage(filter_image);
1584 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1586 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
1587 filter_kernel[i]=(MagickRealType) kernel->values[i];
1593 GetMagickPixelPacket(image,&bias);
1594 SetMagickPixelPacketBias(image,&bias);
1595 image_view=AcquireVirtualCacheView(image,exception);
1596 filter_view=AcquireAuthenticCacheView(filter_image,exception);
1597 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1598 #pragma omp parallel for schedule(static) shared(progress,status) \
1599 magick_number_threads(image,filter_image,image->rows,1)
1601 for (y=0; y < (ssize_t) image->rows; y++)
1607 *magick_restrict indexes;
1613 *magick_restrict filter_indexes;
1621 if (status == MagickFalse)
1623 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (kernel->width-1)/2L),y-
1624 (ssize_t) ((kernel->height-1)/2L),image->columns+kernel->width,
1625 kernel->height,exception);
1626 q=GetCacheViewAuthenticPixels(filter_view,0,y,filter_image->columns,1,
1633 indexes=GetCacheViewVirtualIndexQueue(image_view);
1634 filter_indexes=GetCacheViewAuthenticIndexQueue(filter_view);
1635 for (x=0; x < (ssize_t) image->columns; x++)
1640 const MagickRealType
1644 *magick_restrict kernel_pixels;
1653 pixel.green=bias.green;
1654 pixel.blue=bias.blue;
1655 pixel.opacity=bias.opacity;
1656 pixel.index=bias.index;
1659 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
1661 for (v=0; v < (ssize_t) kernel->width; v++)
1663 for (u=0; u < (ssize_t) kernel->height; u++)
1665 pixel.red+=(*k)*kernel_pixels[u].red;
1666 pixel.green+=(*k)*kernel_pixels[u].green;
1667 pixel.blue+=(*k)*kernel_pixels[u].blue;
1670 kernel_pixels+=image->columns+kernel->width;
1672 if ((channel & RedChannel) != 0)
1673 SetPixelRed(q,ClampToQuantum(pixel.red));
1674 if ((channel & GreenChannel) != 0)
1675 SetPixelGreen(q,ClampToQuantum(pixel.green));
1676 if ((channel & BlueChannel) != 0)
1677 SetPixelBlue(q,ClampToQuantum(pixel.blue));
1678 if ((channel & OpacityChannel) != 0)
1682 for (v=0; v < (ssize_t) kernel->width; v++)
1684 for (u=0; u < (ssize_t) kernel->height; u++)
1686 pixel.opacity+=(*k)*kernel_pixels[u].opacity;
1689 kernel_pixels+=image->columns+kernel->width;
1691 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
1693 if (((channel & IndexChannel) != 0) &&
1694 (image->colorspace == CMYKColorspace))
1697 *magick_restrict kernel_indexes;
1700 kernel_indexes=indexes;
1701 for (v=0; v < (ssize_t) kernel->width; v++)
1703 for (u=0; u < (ssize_t) kernel->height; u++)
1705 pixel.index+=(*k)*GetPixelIndex(kernel_indexes+u);
1708 kernel_indexes+=image->columns+kernel->width;
1710 SetPixelIndex(filter_indexes+x,ClampToQuantum(pixel.index));
1720 for (v=0; v < (ssize_t) kernel->width; v++)
1722 for (u=0; u < (ssize_t) kernel->height; u++)
1724 alpha=(MagickRealType) (QuantumScale*(QuantumRange-
1725 GetPixelOpacity(kernel_pixels+u)));
1726 pixel.red+=(*k)*alpha*GetPixelRed(kernel_pixels+u);
1727 pixel.green+=(*k)*alpha*GetPixelGreen(kernel_pixels+u);
1728 pixel.blue+=(*k)*alpha*GetPixelBlue(kernel_pixels+u);
1732 kernel_pixels+=image->columns+kernel->width;
1734 gamma=PerceptibleReciprocal(gamma);
1735 if ((channel & RedChannel) != 0)
1736 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
1737 if ((channel & GreenChannel) != 0)
1738 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
1739 if ((channel & BlueChannel) != 0)
1740 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
1741 if ((channel & OpacityChannel) != 0)
1745 for (v=0; v < (ssize_t) kernel->width; v++)
1747 for (u=0; u < (ssize_t) kernel->height; u++)
1749 pixel.opacity+=(*k)*GetPixelOpacity(kernel_pixels+u);
1752 kernel_pixels+=image->columns+kernel->width;
1754 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
1756 if (((channel & IndexChannel) != 0) &&
1757 (image->colorspace == CMYKColorspace))
1760 *magick_restrict kernel_indexes;
1764 kernel_indexes=indexes;
1765 for (v=0; v < (ssize_t) kernel->width; v++)
1767 for (u=0; u < (ssize_t) kernel->height; u++)
1769 alpha=(MagickRealType) (QuantumScale*(QuantumRange-
1770 kernel_pixels[u].opacity));
1771 pixel.index+=(*k)*alpha*GetPixelIndex(kernel_indexes+u);
1774 kernel_pixels+=image->columns+kernel->width;
1775 kernel_indexes+=image->columns+kernel->width;
1777 SetPixelIndex(filter_indexes+x,ClampToQuantum(gamma*pixel.index));
1784 sync=SyncCacheViewAuthenticPixels(filter_view,exception);
1785 if (sync == MagickFalse)
1787 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1792 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1796 proceed=SetImageProgress(image,FilterImageTag,progress,image->rows);
1797 if (proceed == MagickFalse)
1801 filter_image->type=image->type;
1802 filter_view=DestroyCacheView(filter_view);
1803 image_view=DestroyCacheView(image_view);
1804 filter_kernel=(MagickRealType *) RelinquishAlignedMemory(filter_kernel);
1805 if (status == MagickFalse)
1806 filter_image=DestroyImage(filter_image);
1807 #ifdef MAGICKCORE_CLPERFMARKER
1808 clEndPerfMarkerAMD();
1810 return(filter_image);
1852 MagickExport
Image *GaussianBlurImage(
const Image *image,
const double radius,
1858 blur_image=GaussianBlurImageChannel(image,DefaultChannels,radius,sigma,
1863 MagickExport
Image *GaussianBlurImageChannel(
const Image *image,
1864 const ChannelType channel,
const double radius,
const double sigma,
1868 geometry[MaxTextExtent];
1876 assert(image != (
const Image *) NULL);
1877 assert(image->signature == MagickCoreSignature);
1879 assert(exception->signature == MagickCoreSignature);
1880 if (IsEventLogging() != MagickFalse)
1881 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1882 (void) FormatLocaleString(geometry,MaxTextExtent,
"gaussian:%.20gx%.20g",
1884 kernel_info=AcquireKernelInfo(geometry);
1886 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1887 blur_image=(
Image *) NULL;
1888 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1889 blur_image=AccelerateConvolveImageChannel(image,channel,kernel_info,
1892 if (blur_image == (
Image *) NULL)
1893 blur_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
1894 kernel_info,exception);
1895 kernel_info=DestroyKernelInfo(kernel_info);
1943 static double *GetMotionBlurKernel(
const size_t width,
const double sigma)
1955 if (IsEventLogging() != MagickFalse)
1956 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
1957 kernel=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
1959 if (kernel == (
double *) NULL)
1962 for (i=0; i < (ssize_t) width; i++)
1964 kernel[i]=(double) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
1965 MagickSigma)))/(MagickSQ2PI*MagickSigma));
1966 normalize+=kernel[i];
1968 for (i=0; i < (ssize_t) width; i++)
1969 kernel[i]/=normalize;
1973 MagickExport
Image *MotionBlurImage(
const Image *image,
const double radius,
1974 const double sigma,
const double angle,
ExceptionInfo *exception)
1979 motion_blur=MotionBlurImageChannel(image,DefaultChannels,radius,sigma,angle,
1981 return(motion_blur);
1984 MagickExport
Image *MotionBlurImageChannel(
const Image *image,
1985 const ChannelType channel,
const double radius,
const double sigma,
1988 #define BlurImageTag "Blur/Image"
2024 assert(image != (
Image *) NULL);
2025 assert(image->signature == MagickCoreSignature);
2027 assert(exception->signature == MagickCoreSignature);
2028 if (IsEventLogging() != MagickFalse)
2029 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2030 width=GetOptimalKernelWidth1D(radius,sigma);
2031 kernel=GetMotionBlurKernel(width,sigma);
2032 if (kernel == (
double *) NULL)
2033 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2034 offset=(
OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2037 kernel=(
double *) RelinquishAlignedMemory(kernel);
2038 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2041 point.x=(double) width*sin(DegreesToRadians(angle));
2042 point.y=(double) width*cos(DegreesToRadians(angle));
2043 for (i=0; i < (ssize_t) width; i++)
2045 offset[i].x=CastDoubleToLong(ceil((
double) (i*point.y)/
2046 hypot(point.x,point.y)-0.5));
2047 offset[i].y=CastDoubleToLong(ceil((
double) (i*point.x)/
2048 hypot(point.x,point.y)-0.5));
2054 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2055 blur_image=AccelerateMotionBlurImage(image,channel,kernel,width,offset,
2057 if (blur_image != (
Image *) NULL)
2060 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2061 if (blur_image == (
Image *) NULL)
2063 kernel=(
double *) RelinquishAlignedMemory(kernel);
2064 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2065 return((
Image *) NULL);
2067 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
2069 kernel=(
double *) RelinquishAlignedMemory(kernel);
2070 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2071 InheritException(exception,&blur_image->exception);
2072 blur_image=DestroyImage(blur_image);
2073 return((
Image *) NULL);
2078 GetMagickPixelPacket(image,&bias);
2079 image_view=AcquireVirtualCacheView(image,exception);
2080 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2081 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2082 #pragma omp parallel for schedule(static) shared(progress,status) \
2083 magick_number_threads(image,blur_image,image->rows,1)
2085 for (y=0; y < (ssize_t) image->rows; y++)
2088 *magick_restrict blur_indexes;
2096 if (status == MagickFalse)
2098 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2105 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
2106 for (x=0; x < (ssize_t) image->columns; x++)
2115 *magick_restrict indexes;
2125 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
2127 for (i=0; i < (ssize_t) width; i++)
2129 (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
2130 offset[i].y,&pixel,exception);
2131 qixel.red+=(*k)*pixel.red;
2132 qixel.green+=(*k)*pixel.green;
2133 qixel.blue+=(*k)*pixel.blue;
2134 qixel.opacity+=(*k)*pixel.opacity;
2135 if (image->colorspace == CMYKColorspace)
2137 indexes=GetCacheViewVirtualIndexQueue(image_view);
2138 qixel.index+=(*k)*(*indexes);
2142 if ((channel & RedChannel) != 0)
2143 SetPixelRed(q,ClampToQuantum(qixel.red));
2144 if ((channel & GreenChannel) != 0)
2145 SetPixelGreen(q,ClampToQuantum(qixel.green));
2146 if ((channel & BlueChannel) != 0)
2147 SetPixelBlue(q,ClampToQuantum(qixel.blue));
2148 if ((channel & OpacityChannel) != 0)
2149 SetPixelOpacity(q,ClampToQuantum(qixel.opacity));
2150 if (((channel & IndexChannel) != 0) &&
2151 (image->colorspace == CMYKColorspace))
2152 SetPixelIndex(blur_indexes+x,ClampToQuantum(qixel.index));
2160 for (i=0; i < (ssize_t) width; i++)
2162 (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
2163 offset[i].y,&pixel,exception);
2164 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(&pixel));
2165 qixel.red+=(*k)*alpha*pixel.red;
2166 qixel.green+=(*k)*alpha*pixel.green;
2167 qixel.blue+=(*k)*alpha*pixel.blue;
2168 qixel.opacity+=(*k)*pixel.opacity;
2169 if (image->colorspace == CMYKColorspace)
2171 indexes=GetCacheViewVirtualIndexQueue(image_view);
2172 qixel.index+=(*k)*alpha*GetPixelIndex(indexes);
2177 gamma=PerceptibleReciprocal(gamma);
2178 if ((channel & RedChannel) != 0)
2179 SetPixelRed(q,ClampToQuantum(gamma*qixel.red));
2180 if ((channel & GreenChannel) != 0)
2181 SetPixelGreen(q,ClampToQuantum(gamma*qixel.green));
2182 if ((channel & BlueChannel) != 0)
2183 SetPixelBlue(q,ClampToQuantum(gamma*qixel.blue));
2184 if ((channel & OpacityChannel) != 0)
2185 SetPixelOpacity(q,ClampToQuantum(qixel.opacity));
2186 if (((channel & IndexChannel) != 0) &&
2187 (image->colorspace == CMYKColorspace))
2188 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*qixel.index));
2192 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2194 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2199 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2203 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2204 if (proceed == MagickFalse)
2208 blur_view=DestroyCacheView(blur_view);
2209 image_view=DestroyCacheView(image_view);
2210 kernel=(
double *) RelinquishAlignedMemory(kernel);
2211 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2212 if (status == MagickFalse)
2213 blur_image=DestroyImage(blur_image);
2251 MagickExport
Image *KuwaharaImage(
const Image *image,
const double radius,
2257 kuwahara_image=KuwaharaImageChannel(image,DefaultChannels,radius,sigma,
2259 return(kuwahara_image);
2262 MagickExport
Image *KuwaharaImageChannel(
const Image *image,
2263 const ChannelType channel,
const double radius,
const double sigma,
2266 #define KuwaharaImageTag "Kiwahara/Image"
2291 assert(image != (
Image *) NULL);
2292 assert(image->signature == MagickCoreSignature);
2294 assert(exception->signature == MagickCoreSignature);
2295 if (IsEventLogging() != MagickFalse)
2296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2298 width=(size_t) radius+1;
2299 gaussian_image=BlurImage(image,radius,sigma,exception);
2300 if (gaussian_image == (
Image *) NULL)
2301 return((
Image *) NULL);
2302 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
2303 if (kuwahara_image == (
Image *) NULL)
2305 gaussian_image=DestroyImage(gaussian_image);
2306 return((
Image *) NULL);
2308 if (SetImageStorageClass(kuwahara_image,DirectClass) == MagickFalse)
2310 InheritException(exception,&kuwahara_image->exception);
2311 gaussian_image=DestroyImage(gaussian_image);
2312 kuwahara_image=DestroyImage(kuwahara_image);
2313 return((
Image *) NULL);
2320 image_view=AcquireVirtualCacheView(gaussian_image,exception);
2321 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
2322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2323 #pragma omp parallel for schedule(static) shared(progress,status) \
2324 magick_number_threads(image,kuwahara_image,kuwahara_image->rows,1)
2326 for (y=0; y < (ssize_t) kuwahara_image->rows; y++)
2329 *magick_restrict kuwahara_indexes;
2337 if (status == MagickFalse)
2339 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
2346 kuwahara_indexes=GetCacheViewAuthenticIndexQueue(kuwahara_view);
2347 for (x=0; x < (ssize_t) kuwahara_image->columns; x++)
2362 min_variance=MagickMaximumValue;
2363 SetGeometry(gaussian_image,&target);
2364 quadrant.width=width;
2365 quadrant.height=width;
2366 for (i=0; i < 4; i++)
2389 quadrant.x=x-(ssize_t) (width-1);
2390 quadrant.y=y-(ssize_t) (width-1);
2395 quadrant.y=y-(ssize_t) (width-1);
2400 quadrant.x=x-(ssize_t) (width-1);
2406 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
2407 quadrant.width,quadrant.height,exception);
2410 GetMagickPixelPacket(image,&mean);
2412 for (n=0; n < (ssize_t) (width*width); n++)
2414 mean.red+=(double) k->red;
2415 mean.green+=(
double) k->green;
2416 mean.blue+=(double) k->blue;
2419 mean.red/=(double) (width*width);
2420 mean.green/=(double) (width*width);
2421 mean.blue/=(double) (width*width);
2424 for (n=0; n < (ssize_t) (width*width); n++)
2429 luma=GetPixelLuma(image,k);
2430 variance+=(luma-MagickPixelLuma(&mean))*(luma-MagickPixelLuma(&mean));
2433 if (variance < min_variance)
2435 min_variance=variance;
2444 status=InterpolateMagickPixelPacket(gaussian_image,image_view,
2445 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,
2446 (
double) target.y+target.height/2.0,&pixel,exception);
2447 if (status == MagickFalse)
2449 SetPixelPacket(kuwahara_image,&pixel,q,kuwahara_indexes+x);
2452 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
2454 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2459 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2463 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
2464 if (proceed == MagickFalse)
2468 kuwahara_view=DestroyCacheView(kuwahara_view);
2469 image_view=DestroyCacheView(image_view);
2470 gaussian_image=DestroyImage(gaussian_image);
2471 if (status == MagickFalse)
2472 kuwahara_image=DestroyImage(kuwahara_image);
2473 return(kuwahara_image);
2509 MagickExport
Image *LocalContrastImage(
const Image *image,
const double radius,
2512 #define LocalContrastImageTag "LocalContrast/Image"
2540 assert(image != (
const Image *) NULL);
2541 assert(image->signature == MagickCoreSignature);
2543 assert(exception->signature == MagickCoreSignature);
2544 if (IsEventLogging() != MagickFalse)
2545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2546 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2547 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2548 if (contrast_image != (
Image *) NULL)
2549 return(contrast_image);
2551 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2552 if (contrast_image == (
Image *) NULL)
2553 return((
Image *) NULL);
2554 if (SetImageStorageClass(contrast_image,DirectClass) == MagickFalse)
2556 InheritException(exception,&contrast_image->exception);
2557 contrast_image=DestroyImage(contrast_image);
2558 return((
Image *) NULL);
2560 image_view=AcquireVirtualCacheView(image,exception);
2561 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2562 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2563 width=(ssize_t) scanLineSize*0.002f*fabs(radius);
2564 scanLineSize+=(2*width);
2565 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2566 scanLineSize,
sizeof(*scanline));
2569 contrast_view=DestroyCacheView(contrast_view);
2570 image_view=DestroyCacheView(image_view);
2571 contrast_image=DestroyImage(contrast_image);
2572 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2574 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2578 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(2*width)),
2579 sizeof(*interImage));
2582 scanline_info=RelinquishVirtualMemory(scanline_info);
2583 contrast_view=DestroyCacheView(contrast_view);
2584 image_view=DestroyCacheView(image_view);
2585 contrast_image=DestroyImage(contrast_image);
2586 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2588 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2589 totalWeight=(width+1)*(width+1);
2598 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2599 #pragma omp parallel for schedule(static) \
2600 magick_number_threads(image,image,image->columns,1)
2602 for (x=0; x < (ssize_t) image->columns; x++)
2605 id = GetOpenMPThreadId();
2621 if (status == MagickFalse)
2624 pixels+=
id*scanLineSize;
2626 p=GetCacheViewVirtualPixels(image_view,x,-width,1,image->rows+(2*width),
2633 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2635 *pix++=(float)GetPixelLuma(image,p);
2638 out=interImage+x+width;
2639 for (y=0; y < (ssize_t) image->rows; y++)
2648 for (i=0; i < width; i++)
2650 sum+=weight*(*pix++);
2653 for (i=width+1; i < (2*width); i++)
2655 sum+=weight*(*pix++);
2659 *out=sum/totalWeight;
2661 if (x <= width && x != 0)
2663 if ((x > (ssize_t) image->columns-width-2) &&
2664 (x != (ssize_t) image->columns-1))
2665 *(out+((image->columns-x-1)*2))=*out;
2666 out+=image->columns+(width*2);
2677 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2678 #pragma omp parallel for schedule(static) \
2679 magick_number_threads(image,image,image->rows,1)
2681 for (y=0; y < (ssize_t) image->rows; y++)
2684 id = GetOpenMPThreadId();
2702 if (status == MagickFalse)
2705 pixels+=
id*scanLineSize;
2706 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
2708 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2715 memcpy(pixels,interImage+(y*(image->columns+(2*width))),(image->columns+
2716 (2*width))*
sizeof(
float));
2717 for (x=0; x < (ssize_t) image->columns; x++)
2728 for (i=0; i < width; i++)
2730 sum+=weight*(*pix++);
2733 for (i=width+1; i < (2*width); i++)
2735 sum+=weight*(*pix++);
2739 srcVal=(float) GetPixelLuma(image,p);
2740 mult=(srcVal-(sum/totalWeight))*(strength/100.0f);
2741 mult=(srcVal+mult)/srcVal;
2742 SetPixelRed(q,ClampToQuantum((MagickRealType) GetPixelRed(p)*mult));
2743 SetPixelGreen(q,ClampToQuantum((MagickRealType) GetPixelGreen(p)*mult));
2744 SetPixelBlue(q,ClampToQuantum((MagickRealType) GetPixelBlue(p)*mult));
2748 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2752 scanline_info=RelinquishVirtualMemory(scanline_info);
2753 interImage_info=RelinquishVirtualMemory(interImage_info);
2754 contrast_view=DestroyCacheView(contrast_view);
2755 image_view=DestroyCacheView(image_view);
2756 if (status == MagickFalse)
2757 contrast_image=DestroyImage(contrast_image);
2758 return(contrast_image);
2791 MagickExport
Image *PreviewImage(
const Image *image,
const PreviewType preview,
2794 #define NumberTiles 9
2795 #define PreviewImageTag "Preview/Image"
2796 #define DefaultPreviewGeometry "204x204+10+10"
2799 factor[MaxTextExtent],
2800 label[MaxTextExtent];
2842 assert(image != (
Image *) NULL);
2843 assert(image->signature == MagickCoreSignature);
2844 if (IsEventLogging() != MagickFalse)
2845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2849 preview_info=AcquireImageInfo();
2850 SetGeometry(image,&geometry);
2851 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2852 &geometry.width,&geometry.height);
2853 images=NewImageList();
2855 GetQuantizeInfo(&quantize_info);
2861 for (i=0; i < NumberTiles; i++)
2863 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2864 if (thumbnail == (
Image *) NULL)
2866 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2868 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel);
2869 if (i == (NumberTiles/2))
2871 (void) QueryColorDatabase(
"#dfdfdf",&thumbnail->matte_color,exception);
2872 AppendImageToList(&images,thumbnail);
2880 preview_image=RotateImage(thumbnail,degrees,exception);
2881 (void) FormatLocaleString(label,MaxTextExtent,
"rotate %g",degrees);
2887 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2888 (void) FormatLocaleString(label,MaxTextExtent,
"shear %gx%g",
2889 degrees,2.0*degrees);
2894 x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
2895 y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
2896 preview_image=RollImage(thumbnail,x,y,exception);
2897 (void) FormatLocaleString(label,MaxTextExtent,
"roll %+.20gx%+.20g",
2898 (
double) x,(double) y);
2903 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2904 if (preview_image == (
Image *) NULL)
2906 (void) FormatLocaleString(factor,MaxTextExtent,
"100,100,%g",
2908 (void) ModulateImage(preview_image,factor);
2909 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2912 case SaturationPreview:
2914 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2915 if (preview_image == (
Image *) NULL)
2917 (void) FormatLocaleString(factor,MaxTextExtent,
"100,%g",2.0*percentage);
2918 (void) ModulateImage(preview_image,factor);
2919 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2922 case BrightnessPreview:
2924 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2925 if (preview_image == (
Image *) NULL)
2927 (void) FormatLocaleString(factor,MaxTextExtent,
"%g",2.0*percentage);
2928 (void) ModulateImage(preview_image,factor);
2929 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2935 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2936 if (preview_image == (
Image *) NULL)
2939 (void) GammaImageChannel(preview_image,DefaultChannels,gamma);
2940 (void) FormatLocaleString(label,MaxTextExtent,
"gamma %g",gamma);
2945 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2946 if (preview_image != (
Image *) NULL)
2947 for (x=0; x < i; x++)
2948 (
void) ContrastImage(preview_image,MagickTrue);
2949 (void) FormatLocaleString(label,MaxTextExtent,
"contrast (%.20g)",
2955 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2956 if (preview_image == (
Image *) NULL)
2958 for (x=0; x < i; x++)
2959 (
void) ContrastImage(preview_image,MagickFalse);
2960 (void) FormatLocaleString(label,MaxTextExtent,
"+contrast (%.20g)",
2964 case GrayscalePreview:
2966 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2967 if (preview_image == (
Image *) NULL)
2970 quantize_info.number_colors=colors;
2971 quantize_info.colorspace=GRAYColorspace;
2972 (void) QuantizeImage(&quantize_info,preview_image);
2973 (void) FormatLocaleString(label,MaxTextExtent,
2974 "-colorspace gray -colors %.20g",(
double) colors);
2977 case QuantizePreview:
2979 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2980 if (preview_image == (
Image *) NULL)
2983 quantize_info.number_colors=colors;
2984 (void) QuantizeImage(&quantize_info,preview_image);
2985 (void) FormatLocaleString(label,MaxTextExtent,
"colors %.20g",(
double)
2989 case DespecklePreview:
2991 for (x=0; x < (i-1); x++)
2993 preview_image=DespeckleImage(thumbnail,exception);
2994 if (preview_image == (
Image *) NULL)
2996 thumbnail=DestroyImage(thumbnail);
2997 thumbnail=preview_image;
2999 preview_image=DespeckleImage(thumbnail,exception);
3000 if (preview_image == (
Image *) NULL)
3002 (void) FormatLocaleString(label,MaxTextExtent,
"despeckle (%.20g)",
3006 case ReduceNoisePreview:
3008 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) radius,
3009 (
size_t) radius,exception);
3010 (void) FormatLocaleString(label,MaxTextExtent,
"noise %g",radius);
3013 case AddNoisePreview:
3019 (void) CopyMagickString(factor,
"uniform",MaxTextExtent);
3024 (void) CopyMagickString(factor,
"gaussian",MaxTextExtent);
3029 (void) CopyMagickString(factor,
"multiplicative",MaxTextExtent);
3034 (void) CopyMagickString(factor,
"impulse",MaxTextExtent);
3039 (void) CopyMagickString(factor,
"laplacian",MaxTextExtent);
3044 (void) CopyMagickString(factor,
"poisson",MaxTextExtent);
3049 (void) CopyMagickString(thumbnail->magick,
"NULL",MaxTextExtent);
3053 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
3054 (
size_t) i,exception);
3055 (void) FormatLocaleString(label,MaxTextExtent,
"+noise %s",factor);
3058 case SharpenPreview:
3060 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
3061 (void) FormatLocaleString(label,MaxTextExtent,
"sharpen %gx%g",
3067 preview_image=BlurImage(thumbnail,radius,sigma,exception);
3068 (void) FormatLocaleString(label,MaxTextExtent,
"blur %gx%g",radius,
3072 case ThresholdPreview:
3074 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3075 if (preview_image == (
Image *) NULL)
3077 (void) BilevelImage(thumbnail,
3078 (
double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
3079 (void) FormatLocaleString(label,MaxTextExtent,
"threshold %g",
3080 (
double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
3083 case EdgeDetectPreview:
3085 preview_image=EdgeImage(thumbnail,radius,exception);
3086 (void) FormatLocaleString(label,MaxTextExtent,
"edge %g",radius);
3091 preview_image=SpreadImage(thumbnail,radius,exception);
3092 (void) FormatLocaleString(label,MaxTextExtent,
"spread %g",
3096 case SolarizePreview:
3098 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3099 if (preview_image == (
Image *) NULL)
3101 (void) SolarizeImage(preview_image,(
double) QuantumRange*
3103 (void) FormatLocaleString(label,MaxTextExtent,
"solarize %g",
3104 (QuantumRange*percentage)/100.0);
3110 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
3112 (void) FormatLocaleString(label,MaxTextExtent,
"shade %gx%g",
3121 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3122 if (preview_image == (
Image *) NULL)
3124 raise.width=(size_t) (2*i+2);
3125 raise.height=(size_t) (2*i+2);
3128 (void) RaiseImage(preview_image,&
raise,MagickTrue);
3129 (void) FormatLocaleString(label,MaxTextExtent,
3130 "raise %.20gx%.20g%+.20g%+.20g",(
double)
raise.width,(double)
3131 raise.height,(
double)
raise.x,(double)
raise.y);
3134 case SegmentPreview:
3136 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3137 if (preview_image == (
Image *) NULL)
3140 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
3142 (void) FormatLocaleString(label,MaxTextExtent,
"segment %gx%g",
3143 threshold,threshold);
3148 preview_image=SwirlImage(thumbnail,degrees,exception);
3149 (void) FormatLocaleString(label,MaxTextExtent,
"swirl %g",degrees);
3153 case ImplodePreview:
3156 preview_image=ImplodeImage(thumbnail,degrees,exception);
3157 (void) FormatLocaleString(label,MaxTextExtent,
"implode %g",degrees);
3163 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
3164 (void) FormatLocaleString(label,MaxTextExtent,
"wave %gx%g",
3165 0.5*degrees,2.0*degrees);
3168 case OilPaintPreview:
3170 preview_image=OilPaintImage(thumbnail,(
double) radius,exception);
3171 (void) FormatLocaleString(label,MaxTextExtent,
"paint %g",radius);
3174 case CharcoalDrawingPreview:
3176 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
3178 (void) FormatLocaleString(label,MaxTextExtent,
"charcoal %gx%g",
3185 filename[MaxTextExtent];
3193 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3194 if (preview_image == (
Image *) NULL)
3196 preview_info->quality=(size_t) percentage;
3197 (void) FormatLocaleString(factor,MaxTextExtent,
"%.20g",(
double)
3198 preview_info->quality);
3199 file=AcquireUniqueFileResource(filename);
3202 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
3203 "jpeg:%s",filename);
3204 status=WriteImage(preview_info,preview_image);
3205 if (status != MagickFalse)
3210 (void) CopyMagickString(preview_info->filename,
3211 preview_image->filename,MaxTextExtent);
3212 quality_image=ReadImage(preview_info,exception);
3213 if (quality_image != (
Image *) NULL)
3215 preview_image=DestroyImage(preview_image);
3216 preview_image=quality_image;
3219 (void) RelinquishUniqueFileResource(preview_image->filename);
3220 if ((GetBlobSize(preview_image)/1024) >= 1024)
3221 (
void) FormatLocaleString(label,MaxTextExtent,
"quality %s\n%gmb ",
3222 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3225 if (GetBlobSize(preview_image) >= 1024)
3226 (void) FormatLocaleString(label,MaxTextExtent,
3227 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3228 GetBlobSize(preview_image))/1024.0);
3230 (
void) FormatLocaleString(label,MaxTextExtent,
"quality %s\n%.20gb ",
3231 factor,(
double) ((MagickOffsetType) GetBlobSize(thumbnail)));
3235 thumbnail=DestroyImage(thumbnail);
3239 if (preview_image == (
Image *) NULL)
3241 (void) DeleteImageProperty(preview_image,
"label");
3242 (void) SetImageProperty(preview_image,
"label",label);
3243 AppendImageToList(&images,preview_image);
3244 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3246 if (proceed == MagickFalse)
3249 if (images == (
Image *) NULL)
3251 preview_info=DestroyImageInfo(preview_info);
3252 return((
Image *) NULL);
3257 montage_info=CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
3258 (void) CopyMagickString(montage_info->filename,image->filename,MaxTextExtent);
3259 montage_info->shadow=MagickTrue;
3260 (void) CloneString(&montage_info->tile,
"3x3");
3261 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3262 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3263 montage_image=MontageImages(images,montage_info,exception);
3264 montage_info=DestroyMontageInfo(montage_info);
3265 images=DestroyImageList(images);
3266 if (montage_image == (
Image *) NULL)
3267 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3268 if (montage_image->montage != (
char *) NULL)
3273 montage_image->montage=(
char *) RelinquishMagickMemory(
3274 montage_image->montage);
3275 if (image->directory != (
char *) NULL)
3276 montage_image->directory=(
char *) RelinquishMagickMemory(
3277 montage_image->directory);
3279 preview_info=DestroyImageInfo(preview_info);
3280 return(montage_image);
3317 MagickExport
Image *RotationalBlurImage(
const Image *image,
const double angle,
3323 blur_image=RotationalBlurImageChannel(image,DefaultChannels,angle,exception);
3327 MagickExport
Image *RotationalBlurImageChannel(
const Image *image,
3328 const ChannelType channel,
const double angle,
ExceptionInfo *exception)
3368 assert(image != (
Image *) NULL);
3369 assert(image->signature == MagickCoreSignature);
3371 assert(exception->signature == MagickCoreSignature);
3372 if (IsEventLogging() != MagickFalse)
3373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3374 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3375 blur_image=AccelerateRadialBlurImage(image,channel,angle,exception);
3376 if (blur_image != (
Image *) NULL)
3379 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3380 if (blur_image == (
Image *) NULL)
3381 return((
Image *) NULL);
3382 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
3384 InheritException(exception,&blur_image->exception);
3385 blur_image=DestroyImage(blur_image);
3386 return((
Image *) NULL);
3388 blur_center.x=(double) (image->columns-1)/2.0;
3389 blur_center.y=(double) (image->rows-1)/2.0;
3390 blur_radius=hypot(blur_center.x,blur_center.y);
3391 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3392 theta=DegreesToRadians(angle)/(MagickRealType) (n-1);
3393 cos_theta=(MagickRealType *) AcquireQuantumMemory((
size_t) n,
3394 sizeof(*cos_theta));
3395 sin_theta=(MagickRealType *) AcquireQuantumMemory((
size_t) n,
3396 sizeof(*sin_theta));
3397 if ((cos_theta == (MagickRealType *) NULL) ||
3398 (sin_theta == (MagickRealType *) NULL))
3400 if (cos_theta != (MagickRealType *) NULL)
3401 cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
3402 if (sin_theta != (MagickRealType *) NULL)
3403 sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
3404 blur_image=DestroyImage(blur_image);
3405 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3407 offset=theta*(MagickRealType) (n-1)/2.0;
3408 for (i=0; i < (ssize_t) n; i++)
3410 cos_theta[i]=cos((
double) (theta*i-offset));
3411 sin_theta[i]=sin((
double) (theta*i-offset));
3418 GetMagickPixelPacket(image,&bias);
3419 image_view=AcquireVirtualCacheView(image,exception);
3420 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3421 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3422 #pragma omp parallel for schedule(static) shared(progress,status) \
3423 magick_number_threads(image,blur_image,blur_image->rows,1)
3425 for (y=0; y < (ssize_t) blur_image->rows; y++)
3428 *magick_restrict indexes;
3431 *magick_restrict blur_indexes;
3439 if (status == MagickFalse)
3441 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3448 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
3449 for (x=0; x < (ssize_t) blur_image->columns; x++)
3470 center.x=(double) x-blur_center.x;
3471 center.y=(
double) y-blur_center.y;
3472 radius=hypot((
double) center.x,center.y);
3477 step=(size_t) (blur_radius/radius);
3486 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
3488 for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
3490 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3491 (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
3492 (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
3493 cos_theta[i]+0.5),&pixel,exception);
3494 qixel.red+=pixel.red;
3495 qixel.green+=pixel.green;
3496 qixel.blue+=pixel.blue;
3497 qixel.opacity+=pixel.opacity;
3498 if (image->colorspace == CMYKColorspace)
3500 indexes=GetCacheViewVirtualIndexQueue(image_view);
3501 qixel.index+=(*indexes);
3505 normalize=PerceptibleReciprocal(normalize);
3506 if ((channel & RedChannel) != 0)
3507 SetPixelRed(q,ClampToQuantum(normalize*qixel.red));
3508 if ((channel & GreenChannel) != 0)
3509 SetPixelGreen(q,ClampToQuantum(normalize*qixel.green));
3510 if ((channel & BlueChannel) != 0)
3511 SetPixelBlue(q,ClampToQuantum(normalize*qixel.blue));
3512 if ((channel & OpacityChannel) != 0)
3513 SetPixelOpacity(q,ClampToQuantum(normalize*qixel.opacity));
3514 if (((channel & IndexChannel) != 0) &&
3515 (image->colorspace == CMYKColorspace))
3516 SetPixelIndex(blur_indexes+x,ClampToQuantum(normalize*qixel.index));
3526 for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
3528 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3529 (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
3530 (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
3531 cos_theta[i]+0.5),&pixel,exception);
3532 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(&pixel));
3533 qixel.red+=alpha*pixel.red;
3534 qixel.green+=alpha*pixel.green;
3535 qixel.blue+=alpha*pixel.blue;
3536 qixel.opacity+=pixel.opacity;
3537 if (image->colorspace == CMYKColorspace)
3539 indexes=GetCacheViewVirtualIndexQueue(image_view);
3540 qixel.index+=alpha*(*indexes);
3545 gamma=PerceptibleReciprocal(gamma);
3546 normalize=PerceptibleReciprocal(normalize);
3547 if ((channel & RedChannel) != 0)
3548 SetPixelRed(q,ClampToQuantum(gamma*qixel.red));
3549 if ((channel & GreenChannel) != 0)
3550 SetPixelGreen(q,ClampToQuantum(gamma*qixel.green));
3551 if ((channel & BlueChannel) != 0)
3552 SetPixelBlue(q,ClampToQuantum(gamma*qixel.blue));
3553 if ((channel & OpacityChannel) != 0)
3554 SetPixelOpacity(q,ClampToQuantum(normalize*qixel.opacity));
3555 if (((channel & IndexChannel) != 0) &&
3556 (image->colorspace == CMYKColorspace))
3557 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*qixel.index));
3561 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3563 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3568 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3572 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3573 if (proceed == MagickFalse)
3577 blur_view=DestroyCacheView(blur_view);
3578 image_view=DestroyCacheView(image_view);
3579 cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
3580 sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
3581 if (status == MagickFalse)
3582 blur_image=DestroyImage(blur_image);
3627 MagickExport
Image *SelectiveBlurImage(
const Image *image,
const double radius,
3628 const double sigma,
const double threshold,
ExceptionInfo *exception)
3633 blur_image=SelectiveBlurImageChannel(image,DefaultChannels,radius,sigma,
3634 threshold,exception);
3638 MagickExport
Image *SelectiveBlurImageChannel(
const Image *image,
3639 const ChannelType channel,
const double radius,
const double sigma,
3642 #define SelectiveBlurImageTag "SelectiveBlur/Image"
3681 assert(image != (
Image *) NULL);
3682 assert(image->signature == MagickCoreSignature);
3684 assert(exception->signature == MagickCoreSignature);
3685 if (IsEventLogging() != MagickFalse)
3686 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3687 width=GetOptimalKernelWidth1D(radius,sigma);
3688 kernel=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
3689 width*
sizeof(*kernel)));
3690 if (kernel == (
double *) NULL)
3691 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3692 j=(ssize_t) (width-1)/2;
3694 for (v=(-j); v <= j; v++)
3696 for (u=(-j); u <= j; u++)
3697 kernel[i++]=(
double) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3698 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3700 if (image->debug != MagickFalse)
3703 format[MaxTextExtent],
3713 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3714 " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(
double)
3716 message=AcquireString(
"");
3718 for (v=0; v < (ssize_t) width; v++)
3721 (void) FormatLocaleString(format,MaxTextExtent,
"%.20g: ",(
double) v);
3722 (void) ConcatenateString(&message,format);
3723 for (u=0; u < (ssize_t) width; u++)
3725 (void) FormatLocaleString(format,MaxTextExtent,
"%+f ",*k++);
3726 (void) ConcatenateString(&message,format);
3728 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3730 message=DestroyString(message);
3732 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3733 if (blur_image == (
Image *) NULL)
3735 kernel=(
double *) RelinquishAlignedMemory(kernel);
3736 return((
Image *) NULL);
3738 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
3740 kernel=(
double *) RelinquishAlignedMemory(kernel);
3741 InheritException(exception,&blur_image->exception);
3742 blur_image=DestroyImage(blur_image);
3743 return((
Image *) NULL);
3745 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3746 if (luminance_image == (
Image *) NULL)
3748 kernel=(
double *) RelinquishAlignedMemory(kernel);
3749 blur_image=DestroyImage(blur_image);
3750 return((
Image *) NULL);
3752 status=TransformImageColorspace(luminance_image,GRAYColorspace);
3753 if (status == MagickFalse)
3755 InheritException(exception,&luminance_image->exception);
3756 kernel=(
double *) RelinquishAlignedMemory(kernel);
3757 blur_image=DestroyImage(blur_image);
3758 luminance_image=DestroyImage(luminance_image);
3759 return((
Image *) NULL);
3766 center=(ssize_t) ((image->columns+width)*((width-1)/2L)+((width-1)/2L));
3767 GetMagickPixelPacket(image,&bias);
3768 SetMagickPixelPacketBias(image,&bias);
3769 image_view=AcquireVirtualCacheView(image,exception);
3770 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3771 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3772 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3773 #pragma omp parallel for schedule(static) shared(progress,status) \
3774 magick_number_threads(image,blur_image,image->rows,1)
3776 for (y=0; y < (ssize_t) image->rows; y++)
3785 *magick_restrict indexes;
3792 *magick_restrict blur_indexes;
3800 if (status == MagickFalse)
3802 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3803 ((width-1)/2L),image->columns+width,width,exception);
3804 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3805 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3806 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3814 indexes=GetCacheViewVirtualIndexQueue(image_view);
3815 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
3816 for (x=0; x < (ssize_t) image->columns; x++)
3838 pixel.green=bias.green;
3839 pixel.blue=bias.blue;
3840 pixel.opacity=bias.opacity;
3841 pixel.index=bias.index;
3843 intensity=GetPixelIntensity(image,p+center);
3846 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
3848 for (v=0; v < (ssize_t) width; v++)
3850 for (u=0; u < (ssize_t) width; u++)
3852 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3853 if (fabs(contrast) < threshold)
3855 pixel.red+=(*k)*GetPixelRed(p+u+j);
3856 pixel.green+=(*k)*GetPixelGreen(p+u+j);
3857 pixel.blue+=(*k)*GetPixelBlue(p+u+j);
3862 j+=(ssize_t) (image->columns+width);
3866 gamma=PerceptibleReciprocal(gamma);
3867 if ((channel & RedChannel) != 0)
3868 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
3869 if ((channel & GreenChannel) != 0)
3870 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
3871 if ((channel & BlueChannel) != 0)
3872 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
3874 if ((channel & OpacityChannel) != 0)
3878 for (v=0; v < (ssize_t) width; v++)
3880 for (u=0; u < (ssize_t) width; u++)
3882 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3883 if (fabs(contrast) < threshold)
3885 pixel.opacity+=(*k)*(p+u+j)->opacity;
3890 j+=(ssize_t) (image->columns+width);
3892 gamma=PerceptibleReciprocal(gamma);
3893 SetPixelOpacity(q,ClampToQuantum(gamma*pixel.opacity));
3895 if (((channel & IndexChannel) != 0) &&
3896 (image->colorspace == CMYKColorspace))
3900 for (v=0; v < (ssize_t) width; v++)
3902 for (u=0; u < (ssize_t) width; u++)
3904 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3905 if (fabs(contrast) < threshold)
3907 pixel.index+=(*k)*GetPixelIndex(indexes+x+u+j);
3912 j+=(ssize_t) (image->columns+width);
3914 gamma=PerceptibleReciprocal(gamma);
3915 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*pixel.index));
3923 for (v=0; v < (ssize_t) width; v++)
3925 for (u=0; u < (ssize_t) width; u++)
3927 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3928 if (fabs(contrast) < threshold)
3930 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(p+u+j));
3931 pixel.red+=(*k)*alpha*GetPixelRed(p+u+j);
3932 pixel.green+=(*k)*alpha*GetPixelGreen(p+u+j);
3933 pixel.blue+=(*k)*alpha*GetPixelBlue(p+u+j);
3934 pixel.opacity+=(*k)*GetPixelOpacity(p+u+j);
3939 j+=(ssize_t) (image->columns+width);
3943 gamma=PerceptibleReciprocal(gamma);
3944 if ((channel & RedChannel) != 0)
3945 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
3946 if ((channel & GreenChannel) != 0)
3947 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
3948 if ((channel & BlueChannel) != 0)
3949 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
3951 if ((channel & OpacityChannel) != 0)
3954 for (v=0; v < (ssize_t) width; v++)
3956 for (u=0; u < (ssize_t) width; u++)
3958 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3959 if (fabs(contrast) < threshold)
3960 pixel.opacity+=(*k)*GetPixelOpacity(p+u+j);
3963 j+=(ssize_t) (image->columns+width);
3965 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3967 if (((channel & IndexChannel) != 0) &&
3968 (image->colorspace == CMYKColorspace))
3972 for (v=0; v < (ssize_t) width; v++)
3974 for (u=0; u < (ssize_t) width; u++)
3976 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3977 if (fabs(contrast) < threshold)
3979 alpha=(MagickRealType) (QuantumScale*
3980 GetPixelAlpha(p+u+j));
3981 pixel.index+=(*k)*alpha*GetPixelIndex(indexes+x+u+j);
3986 j+=(ssize_t) (image->columns+width);
3988 gamma=PerceptibleReciprocal(gamma);
3989 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*pixel.index));
3996 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3997 if (sync == MagickFalse)
3999 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4004 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4008 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
4010 if (proceed == MagickFalse)
4014 blur_image->type=image->type;
4015 blur_view=DestroyCacheView(blur_view);
4016 luminance_view=DestroyCacheView(luminance_view);
4017 image_view=DestroyCacheView(image_view);
4018 luminance_image=DestroyImage(luminance_image);
4019 kernel=(
double *) RelinquishAlignedMemory(kernel);
4020 if (status == MagickFalse)
4021 blur_image=DestroyImage(blur_image);
4057 MagickExport
Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
4058 const double azimuth,
const double elevation,
ExceptionInfo *exception)
4060 #define GetShadeIntensity(image,pixel) \
4061 ClampPixel(GetPixelIntensity((image),(pixel)))
4062 #define ShadeImageTag "Shade/Image"
4087 assert(image != (
const Image *) NULL);
4088 assert(image->signature == MagickCoreSignature);
4090 assert(exception->signature == MagickCoreSignature);
4091 if (IsEventLogging() != MagickFalse)
4092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4093 linear_image=CloneImage(image,0,0,MagickTrue,exception);
4094 shade_image=CloneImage(image,0,0,MagickTrue,exception);
4095 if ((linear_image == (
Image *) NULL) || (shade_image == (
Image *) NULL))
4097 if (linear_image != (
Image *) NULL)
4098 linear_image=DestroyImage(linear_image);
4099 if (shade_image != (
Image *) NULL)
4100 shade_image=DestroyImage(shade_image);
4101 return((
Image *) NULL);
4103 if (SetImageStorageClass(shade_image,DirectClass) == MagickFalse)
4105 InheritException(exception,&shade_image->exception);
4106 linear_image=DestroyImage(linear_image);
4107 shade_image=DestroyImage(shade_image);
4108 return((
Image *) NULL);
4113 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
4114 cos(DegreesToRadians(elevation));
4115 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
4116 cos(DegreesToRadians(elevation));
4117 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
4123 image_view=AcquireVirtualCacheView(linear_image,exception);
4124 shade_view=AcquireAuthenticCacheView(shade_image,exception);
4125 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4126 #pragma omp parallel for schedule(static) shared(progress,status) \
4127 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
4129 for (y=0; y < (ssize_t) linear_image->rows; y++)
4141 *magick_restrict s0,
4142 *magick_restrict s1,
4143 *magick_restrict s2;
4151 if (status == MagickFalse)
4153 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
4155 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
4165 normal.z=2.0*(double) QuantumRange;
4166 for (x=0; x < (ssize_t) linear_image->columns; x++)
4172 s1=s0+image->columns+2;
4173 s2=s1+image->columns+2;
4174 normal.x=(double) (GetShadeIntensity(linear_image,s0-1)+
4175 GetShadeIntensity(linear_image,s1-1)+
4176 GetShadeIntensity(linear_image,s2-1)-
4177 GetShadeIntensity(linear_image,s0+1)-
4178 GetShadeIntensity(linear_image,s1+1)-
4179 GetShadeIntensity(linear_image,s2+1));
4180 normal.y=(double) (GetShadeIntensity(linear_image,s2-1)+
4181 GetShadeIntensity(linear_image,s2)+
4182 GetShadeIntensity(linear_image,s2+1)-
4183 GetShadeIntensity(linear_image,s0-1)-
4184 GetShadeIntensity(linear_image,s0)-
4185 GetShadeIntensity(linear_image,s0+1));
4186 if ((fabs(normal.x) <= MagickEpsilon) &&
4187 (fabs(normal.y) <= MagickEpsilon))
4192 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
4193 if (distance > MagickEpsilon)
4195 normal_distance=normal.x*normal.x+normal.y*normal.y+normal.z*
4197 if (normal_distance > (MagickEpsilon*MagickEpsilon))
4198 shade=distance/sqrt((
double) normal_distance);
4201 if (gray != MagickFalse)
4203 SetPixelRed(q,shade);
4204 SetPixelGreen(q,shade);
4205 SetPixelBlue(q,shade);
4209 SetPixelRed(q,ClampToQuantum(QuantumScale*shade*GetPixelRed(s1)));
4210 SetPixelGreen(q,ClampToQuantum(QuantumScale*shade*GetPixelGreen(s1)));
4211 SetPixelBlue(q,ClampToQuantum(QuantumScale*shade*GetPixelBlue(s1)));
4213 q->opacity=s1->opacity;
4217 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
4219 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4224 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4228 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
4229 if (proceed == MagickFalse)
4233 shade_view=DestroyCacheView(shade_view);
4234 image_view=DestroyCacheView(image_view);
4235 linear_image=DestroyImage(linear_image);
4236 if (status == MagickFalse)
4237 shade_image=DestroyImage(shade_image);
4238 return(shade_image);
4284 MagickExport
Image *SharpenImage(
const Image *image,
const double radius,
4290 sharp_image=SharpenImageChannel(image,DefaultChannels,radius,sigma,exception);
4291 return(sharp_image);
4294 MagickExport
Image *SharpenImageChannel(
const Image *image,
4295 const ChannelType channel,
const double radius,
const double sigma,
4319 assert(image != (
const Image *) NULL);
4320 assert(image->signature == MagickCoreSignature);
4322 assert(exception->signature == MagickCoreSignature);
4323 if (IsEventLogging() != MagickFalse)
4324 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4325 width=GetOptimalKernelWidth2D(radius,sigma);
4326 kernel_info=AcquireKernelInfo((
const char *) NULL);
4328 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4329 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4330 kernel_info->width=width;
4331 kernel_info->height=width;
4332 kernel_info->x=(ssize_t) (width-1)/2;
4333 kernel_info->y=(ssize_t) (width-1)/2;
4334 kernel_info->signature=MagickCoreSignature;
4335 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
4336 kernel_info->width,kernel_info->height*
sizeof(*kernel_info->values)));
4337 if (kernel_info->values == (
double *) NULL)
4339 kernel_info=DestroyKernelInfo(kernel_info);
4340 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4343 j=(ssize_t) (kernel_info->width-1)/2;
4345 for (v=(-j); v <= j; v++)
4347 for (u=(-j); u <= j; u++)
4349 kernel_info->values[i]=(double) (-exp(-((
double) u*u+v*v)/(2.0*
4350 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4351 normalize+=kernel_info->values[i];
4355 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4357 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4358 normalize+=kernel_info->values[i];
4359 gamma=PerceptibleReciprocal(normalize);
4360 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4361 kernel_info->values[i]*=gamma;
4362 sharp_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
4363 kernel_info,exception);
4364 kernel_info=DestroyKernelInfo(kernel_info);
4365 return(sharp_image);
4396 MagickExport
Image *SpreadImage(
const Image *image,
const double radius,
4399 #define SpreadImageTag "Spread/Image"
4418 **magick_restrict random_info;
4426 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4434 assert(image != (
Image *) NULL);
4435 assert(image->signature == MagickCoreSignature);
4437 assert(exception->signature == MagickCoreSignature);
4438 if (IsEventLogging() != MagickFalse)
4439 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4440 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4441 if (spread_image == (
Image *) NULL)
4442 return((
Image *) NULL);
4443 if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
4445 InheritException(exception,&spread_image->exception);
4446 spread_image=DestroyImage(spread_image);
4447 return((
Image *) NULL);
4454 GetMagickPixelPacket(spread_image,&bias);
4455 width=GetOptimalKernelWidth1D(radius,0.5);
4456 random_info=AcquireRandomInfoTLS();
4457 image_view=AcquireVirtualCacheView(image,exception);
4458 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4459 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4460 key=GetRandomSecretKey(random_info[0]);
4461 #pragma omp parallel for schedule(static) shared(progress,status) \
4462 magick_number_threads(image,spread_image,spread_image->rows,key == ~0UL)
4464 for (y=0; y < (ssize_t) spread_image->rows; y++)
4467 id = GetOpenMPThreadId();
4473 *magick_restrict indexes;
4481 if (status == MagickFalse)
4483 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4490 indexes=GetCacheViewAuthenticIndexQueue(spread_view);
4492 for (x=0; x < (ssize_t) spread_image->columns; x++)
4497 point.x=GetPseudoRandomValue(random_info[
id]);
4498 point.y=GetPseudoRandomValue(random_info[
id]);
4499 status=InterpolateMagickPixelPacket(image,image_view,image->interpolate,
4500 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),&pixel,
4502 if (status == MagickFalse)
4504 SetPixelPacket(spread_image,&pixel,q,indexes+x);
4507 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4509 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4518 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4519 if (proceed == MagickFalse)
4523 spread_view=DestroyCacheView(spread_view);
4524 image_view=DestroyCacheView(image_view);
4525 random_info=DestroyRandomInfoTLS(random_info);
4526 if (status == MagickFalse)
4527 spread_image=DestroyImage(spread_image);
4528 return(spread_image);
4576 MagickExport
Image *UnsharpMaskImage(
const Image *image,
const double radius,
4577 const double sigma,
const double gain,
const double threshold,
4584 sharp_image=UnsharpMaskImageChannel(image,DefaultChannels,radius,sigma,gain,
4585 threshold,exception);
4587 return(sharp_image);
4590 MagickExport
Image *UnsharpMaskImageChannel(
const Image *image,
4591 const ChannelType channel,
const double radius,
const double sigma,
4592 const double gain,
const double threshold,
ExceptionInfo *exception)
4594 #define SharpenImageTag "Sharpen/Image"
4618 assert(image != (
const Image *) NULL);
4619 assert(image->signature == MagickCoreSignature);
4621 assert(exception->signature == MagickCoreSignature);
4622 if (IsEventLogging() != MagickFalse)
4623 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4632 unsharp_image=BlurImageChannel(image,(ChannelType) (channel &~ SyncChannels),
4633 radius,sigma,exception);
4634 if (unsharp_image == (
Image *) NULL)
4635 return((
Image *) NULL);
4636 quantum_threshold=(MagickRealType) QuantumRange*threshold;
4642 GetMagickPixelPacket(image,&bias);
4643 image_view=AcquireVirtualCacheView(image,exception);
4644 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4645 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4646 #pragma omp parallel for schedule(static) shared(progress,status) \
4647 magick_number_threads(image,unsharp_image,image->rows,1)
4649 for (y=0; y < (ssize_t) image->rows; y++)
4655 *magick_restrict indexes;
4661 *magick_restrict unsharp_indexes;
4669 if (status == MagickFalse)
4671 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4672 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4679 indexes=GetCacheViewVirtualIndexQueue(image_view);
4680 unsharp_indexes=GetCacheViewAuthenticIndexQueue(unsharp_view);
4682 pixel.green=bias.green;
4683 pixel.blue=bias.blue;
4684 pixel.opacity=bias.opacity;
4685 pixel.index=bias.index;
4686 for (x=0; x < (ssize_t) image->columns; x++)
4688 if ((channel & RedChannel) != 0)
4690 pixel.red=GetPixelRed(p)-(MagickRealType) GetPixelRed(q);
4691 if (fabs(2.0*pixel.red) < quantum_threshold)
4692 pixel.red=(MagickRealType) GetPixelRed(p);
4694 pixel.red=(MagickRealType) GetPixelRed(p)+(pixel.red*gain);
4695 SetPixelRed(q,ClampToQuantum(pixel.red));
4697 if ((channel & GreenChannel) != 0)
4699 pixel.green=GetPixelGreen(p)-(MagickRealType) q->green;
4700 if (fabs(2.0*pixel.green) < quantum_threshold)
4701 pixel.green=(MagickRealType) GetPixelGreen(p);
4703 pixel.green=(MagickRealType) GetPixelGreen(p)+(pixel.green*gain);
4704 SetPixelGreen(q,ClampToQuantum(pixel.green));
4706 if ((channel & BlueChannel) != 0)
4708 pixel.blue=GetPixelBlue(p)-(MagickRealType) q->blue;
4709 if (fabs(2.0*pixel.blue) < quantum_threshold)
4710 pixel.blue=(MagickRealType) GetPixelBlue(p);
4712 pixel.blue=(MagickRealType) GetPixelBlue(p)+(pixel.blue*gain);
4713 SetPixelBlue(q,ClampToQuantum(pixel.blue));
4715 if ((channel & OpacityChannel) != 0)
4717 pixel.opacity=GetPixelOpacity(p)-(MagickRealType) q->opacity;
4718 if (fabs(2.0*pixel.opacity) < quantum_threshold)
4719 pixel.opacity=(MagickRealType) GetPixelOpacity(p);
4721 pixel.opacity=GetPixelOpacity(p)+(pixel.opacity*gain);
4722 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
4724 if (((channel & IndexChannel) != 0) &&
4725 (image->colorspace == CMYKColorspace))
4727 pixel.index=GetPixelIndex(indexes+x)-(MagickRealType)
4728 GetPixelIndex(unsharp_indexes+x);
4729 if (fabs(2.0*pixel.index) < quantum_threshold)
4730 pixel.index=(MagickRealType) GetPixelIndex(indexes+x);
4732 pixel.index=(MagickRealType) GetPixelIndex(indexes+x)+
4734 SetPixelIndex(unsharp_indexes+x,ClampToQuantum(pixel.index));
4739 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4741 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4746 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4750 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4751 if (proceed == MagickFalse)
4755 unsharp_image->type=image->type;
4756 unsharp_view=DestroyCacheView(unsharp_view);
4757 image_view=DestroyCacheView(image_view);
4758 if (status == MagickFalse)
4759 unsharp_image=DestroyImage(unsharp_image);
4760 return(unsharp_image);