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*(double) GetPixelRed(p);
362 if ((channel & GreenChannel) != 0)
363 pixel.green+=(*k)*alpha*(double) GetPixelGreen(p);
364 if ((channel & BlueChannel) != 0)
365 pixel.blue+=(*k)*alpha*(double) GetPixelBlue(p);
366 if ((channel & OpacityChannel) != 0)
367 pixel.opacity+=(*k)*(double) GetPixelOpacity(p);
368 if (((channel & IndexChannel) != 0) &&
369 (image->colorspace == CMYKColorspace))
370 pixel.index+=(*k)*alpha*(double) GetPixelIndex(indexes+x+(width-i)*
377 gamma=PerceptibleReciprocal(gamma);
378 if ((channel & RedChannel) != 0)
379 SetPixelRed(q,ClampToQuantum(gamma*(MagickRealType) pixel.red));
380 if ((channel & GreenChannel) != 0)
381 SetPixelGreen(q,ClampToQuantum(gamma*(MagickRealType) pixel.green));
382 if ((channel & BlueChannel) != 0)
383 SetPixelBlue(q,ClampToQuantum(gamma*(MagickRealType) pixel.blue));
384 if ((channel & OpacityChannel) != 0)
385 SetPixelOpacity(q,ClampToQuantum((MagickRealType) pixel.opacity));
386 if (((channel & IndexChannel) != 0) &&
387 (image->colorspace == CMYKColorspace))
388 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*(MagickRealType)
393 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
395 if (image->progress_monitor != (MagickProgressMonitor) NULL)
400 #if defined(MAGICKCORE_OPENMP_SUPPORT)
404 proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
406 if (proceed == MagickFalse)
410 blur_image->type=image->type;
411 blur_view=DestroyCacheView(blur_view);
412 edge_view=DestroyCacheView(edge_view);
413 image_view=DestroyCacheView(image_view);
414 edge_image=DestroyImage(edge_image);
415 for (i=0; i < (ssize_t) width; i+=2)
416 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
417 kernel=(
double **) RelinquishAlignedMemory(kernel);
418 if (status == MagickFalse)
419 blur_image=DestroyImage(blur_image);
463 MagickExport
Image *AdaptiveSharpenImage(
const Image *image,
const double radius,
469 sharp_image=AdaptiveSharpenImageChannel(image,DefaultChannels,radius,sigma,
474 MagickExport
Image *AdaptiveSharpenImageChannel(
const Image *image,
475 const ChannelType channel,
const double radius,
const double sigma,
478 #define AdaptiveSharpenImageTag "Convolve/Image"
479 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
517 assert(image != (
const Image *) NULL);
518 assert(image->signature == MagickCoreSignature);
520 assert(exception->signature == MagickCoreSignature);
521 if (IsEventLogging() != MagickFalse)
522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
523 sharp_image=CloneImage(image,0,0,MagickTrue,exception);
524 if (sharp_image == (
Image *) NULL)
525 return((
Image *) NULL);
526 if (fabs(sigma) <= MagickEpsilon)
528 if (SetImageStorageClass(sharp_image,DirectClass) == MagickFalse)
530 InheritException(exception,&sharp_image->exception);
531 sharp_image=DestroyImage(sharp_image);
532 return((
Image *) NULL);
537 edge_image=EdgeImage(image,radius,exception);
538 if (edge_image == (
Image *) NULL)
540 sharp_image=DestroyImage(sharp_image);
541 return((
Image *) NULL);
543 (void) AutoLevelImage(edge_image);
544 gaussian_image=BlurImage(edge_image,radius,sigma,exception);
545 if (gaussian_image != (
Image *) NULL)
547 edge_image=DestroyImage(edge_image);
548 edge_image=gaussian_image;
550 (void) AutoLevelImage(edge_image);
554 width=GetOptimalKernelWidth2D(radius,sigma);
555 kernel=(
double **) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
557 if (kernel == (
double **) NULL)
559 edge_image=DestroyImage(edge_image);
560 sharp_image=DestroyImage(sharp_image);
561 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
563 (void) memset(kernel,0,(
size_t) width*
sizeof(*kernel));
564 for (i=0; i < (ssize_t) width; i+=2)
566 kernel[i]=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t)
567 (width-i),(width-i)*
sizeof(**kernel)));
568 if (kernel[i] == (
double *) NULL)
571 j=(ssize_t) (width-i-1)/2;
573 for (v=(-j); v <= j; v++)
575 for (u=(-j); u <= j; u++)
577 kernel[i][k]=(double) (-exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
578 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
579 normalize+=kernel[i][k];
583 kernel[i][(k-1)/2]=(
double) ((-2.0)*normalize);
584 if (sigma < MagickEpsilon)
585 kernel[i][(k-1)/2]=1.0;
587 if (i < (ssize_t) width)
589 for (i-=2; i >= 0; i-=2)
590 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
591 kernel=(
double **) RelinquishAlignedMemory(kernel);
592 edge_image=DestroyImage(edge_image);
593 sharp_image=DestroyImage(sharp_image);
594 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
601 GetMagickPixelPacket(image,&bias);
602 SetMagickPixelPacketBias(image,&bias);
603 image_view=AcquireVirtualCacheView(image,exception);
604 edge_view=AcquireVirtualCacheView(edge_image,exception);
605 sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
606 #if defined(MAGICKCORE_OPENMP_SUPPORT)
607 #pragma omp parallel for schedule(static) shared(progress,status) \
608 magick_number_threads(image,sharp_image,sharp_image->rows,1)
610 for (y=0; y < (ssize_t) sharp_image->rows; y++)
613 *magick_restrict indexes;
620 *magick_restrict sharp_indexes;
628 if (status == MagickFalse)
630 r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
631 q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
638 sharp_indexes=GetCacheViewAuthenticIndexQueue(sharp_view);
639 for (x=0; x < (ssize_t) sharp_image->columns; x++)
657 i=CastDoubleToLong(ceil((
double) width*(1.0-QuantumScale*
658 GetPixelIntensity(edge_image,r))-0.5));
662 if (i > (ssize_t) width)
666 p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
667 (ssize_t) ((width-i)/2L),width-i,width-i,exception);
670 indexes=GetCacheViewVirtualIndexQueue(image_view);
673 pixel.green=bias.green;
674 pixel.blue=bias.blue;
675 pixel.opacity=bias.opacity;
676 pixel.index=bias.index;
677 for (v=0; v < (ssize_t) (width-i); v++)
679 for (u=0; u < (ssize_t) (width-i); u++)
682 if (((channel & OpacityChannel) != 0) &&
683 (image->matte != MagickFalse))
684 alpha=(MagickRealType) (QuantumScale*(MagickRealType)
686 if ((channel & RedChannel) != 0)
687 pixel.red+=(*k)*alpha*(MagickRealType) GetPixelRed(p);
688 if ((channel & GreenChannel) != 0)
689 pixel.green+=(*k)*alpha*(MagickRealType) GetPixelGreen(p);
690 if ((channel & BlueChannel) != 0)
691 pixel.blue+=(*k)*alpha*(MagickRealType) GetPixelBlue(p);
692 if ((channel & OpacityChannel) != 0)
693 pixel.opacity+=(*k)*(MagickRealType) GetPixelOpacity(p);
694 if (((channel & IndexChannel) != 0) &&
695 (image->colorspace == CMYKColorspace))
696 pixel.index+=(*k)*alpha*(MagickRealType)
697 GetPixelIndex(indexes+x+(width-i)*v+u);
703 gamma=PerceptibleReciprocal(gamma);
704 if ((channel & RedChannel) != 0)
705 SetPixelRed(q,ClampToQuantum(gamma*pixel.red));
706 if ((channel & GreenChannel) != 0)
707 SetPixelGreen(q,ClampToQuantum(gamma*pixel.green));
708 if ((channel & BlueChannel) != 0)
709 SetPixelBlue(q,ClampToQuantum(gamma*pixel.blue));
710 if ((channel & OpacityChannel) != 0)
711 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
712 if (((channel & IndexChannel) != 0) &&
713 (image->colorspace == CMYKColorspace))
714 SetPixelIndex(sharp_indexes+x,ClampToQuantum(gamma*pixel.index));
718 if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
720 if (image->progress_monitor != (MagickProgressMonitor) NULL)
725 #if defined(MAGICKCORE_OPENMP_SUPPORT)
729 proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
731 if (proceed == MagickFalse)
735 sharp_image->type=image->type;
736 sharp_view=DestroyCacheView(sharp_view);
737 edge_view=DestroyCacheView(edge_view);
738 image_view=DestroyCacheView(image_view);
739 edge_image=DestroyImage(edge_image);
740 for (i=0; i < (ssize_t) width; i+=2)
741 kernel[i]=(
double *) RelinquishAlignedMemory(kernel[i]);
742 kernel=(
double **) RelinquishAlignedMemory(kernel);
743 if (status == MagickFalse)
744 sharp_image=DestroyImage(sharp_image);
786 MagickExport
Image *BlurImage(
const Image *image,
const double radius,
792 blur_image=BlurImageChannel(image,DefaultChannels,radius,sigma,exception);
796 MagickExport
Image *BlurImageChannel(
const Image *image,
797 const ChannelType channel,
const double radius,
const double sigma,
801 geometry[MaxTextExtent];
809 assert(image != (
const Image *) NULL);
810 assert(image->signature == MagickCoreSignature);
812 assert(exception->signature == MagickCoreSignature);
813 if (IsEventLogging() != MagickFalse)
814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
815 #if defined(MAGICKCORE_OPENCL_SUPPORT)
816 blur_image=AccelerateBlurImage(image,channel,radius,sigma,exception);
817 if (blur_image != (
Image *) NULL)
820 (void) FormatLocaleString(geometry,MaxTextExtent,
821 "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
822 kernel_info=AcquireKernelInfo(geometry);
824 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
825 blur_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
826 kernel_info,exception);
827 kernel_info=DestroyKernelInfo(kernel_info);
865 MagickExport
Image *ConvolveImage(
const Image *image,
const size_t order,
871 #ifdef MAGICKCORE_CLPERFMARKER
872 clBeginPerfMarkerAMD(__FUNCTION__,
"");
875 convolve_image=ConvolveImageChannel(image,DefaultChannels,order,kernel,
878 #ifdef MAGICKCORE_CLPERFMARKER
879 clEndPerfMarkerAMD();
881 return(convolve_image);
884 MagickExport
Image *ConvolveImageChannel(
const Image *image,
885 const ChannelType channel,
const size_t order,
const double *kernel,
897 kernel_info=AcquireKernelInfo((
const char *) NULL);
899 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
900 kernel_info->width=order;
901 kernel_info->height=order;
902 kernel_info->x=(ssize_t) (order-1)/2;
903 kernel_info->y=(ssize_t) (order-1)/2;
904 kernel_info->signature=MagickCoreSignature;
905 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
906 kernel_info->width,kernel_info->width*
sizeof(*kernel_info->values)));
907 if (kernel_info->values == (
double *) NULL)
909 kernel_info=DestroyKernelInfo(kernel_info);
910 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
912 for (i=0; i < (ssize_t) (order*order); i++)
913 kernel_info->values[i]=kernel[i];
914 convolve_image=(
Image *) NULL;
915 #if defined(MAGICKCORE_OPENCL_SUPPORT)
916 convolve_image=AccelerateConvolveImageChannel(image,channel,kernel_info,
919 if (convolve_image == (
Image *) NULL)
920 convolve_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
921 kernel_info,exception);
922 kernel_info=DestroyKernelInfo(kernel_info);
923 return(convolve_image);
956 static void Hull(
const Image *image,
const ssize_t x_offset,
957 const ssize_t y_offset,
const size_t columns,
const size_t rows,
958 const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
969 assert(f != (Quantum *) NULL);
970 assert(g != (Quantum *) NULL);
973 r=p+(y_offset*((ssize_t) columns+2)+x_offset);
974 #if defined(MAGICKCORE_OPENMP_SUPPORT)
975 #pragma omp parallel for schedule(static) \
976 magick_number_threads(image,image,rows,1)
978 for (y=0; y < (ssize_t) rows; y++)
989 for (x=0; x < (ssize_t) columns; x++)
991 v=(SignedQuantum) p[i];
992 if ((SignedQuantum) r[i] >= (v+ScaleCharToQuantum(2)))
993 v+=ScaleCharToQuantum(1);
998 for (x=0; x < (ssize_t) columns; x++)
1000 v=(SignedQuantum) p[i];
1001 if ((SignedQuantum) r[i] <= (v-ScaleCharToQuantum(2)))
1002 v-=ScaleCharToQuantum(1);
1010 r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1011 s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1012 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1013 #pragma omp parallel for schedule(static) \
1014 magick_number_threads(image,image,rows,1)
1016 for (y=0; y < (ssize_t) rows; y++)
1025 i=(2*y+1)+y*columns;
1027 for (x=0; x < (ssize_t) columns; x++)
1029 v=(SignedQuantum) q[i];
1030 if (((SignedQuantum) s[i] >= (v+ScaleCharToQuantum(2))) &&
1031 ((SignedQuantum) r[i] > v))
1032 v+=ScaleCharToQuantum(1);
1037 for (x=0; x < (ssize_t) columns; x++)
1039 v=(SignedQuantum) q[i];
1040 if (((SignedQuantum) s[i] <= (v-ScaleCharToQuantum(2))) &&
1041 ((SignedQuantum) r[i] < v))
1042 v-=ScaleCharToQuantum(1);
1051 #define DespeckleImageTag "Despeckle/Image"
1071 *magick_restrict buffer,
1072 *magick_restrict pixels;
1078 static const ssize_t
1079 X[4] = {0, 1, 1,-1},
1080 Y[4] = {1, 0, 1, 1};
1085 assert(image != (
const Image *) NULL);
1086 assert(image->signature == MagickCoreSignature);
1088 assert(exception->signature == MagickCoreSignature);
1089 if (IsEventLogging() != MagickFalse)
1090 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1091 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1092 despeckle_image=AccelerateDespeckleImage(image, exception);
1093 if (despeckle_image != (
Image *) NULL)
1094 return(despeckle_image);
1096 despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1097 if (despeckle_image == (
Image *) NULL)
1098 return((
Image *) NULL);
1099 if (SetImageStorageClass(despeckle_image,DirectClass) == MagickFalse)
1101 InheritException(exception,&despeckle_image->exception);
1102 despeckle_image=DestroyImage(despeckle_image);
1103 return((
Image *) NULL);
1108 length=(size_t) ((image->columns+2)*(image->rows+2));
1109 pixel_info=AcquireVirtualMemory(length,
sizeof(*pixels));
1110 buffer_info=AcquireVirtualMemory(length,
sizeof(*buffer));
1115 buffer_info=RelinquishVirtualMemory(buffer_info);
1117 pixel_info=RelinquishVirtualMemory(pixel_info);
1118 despeckle_image=DestroyImage(despeckle_image);
1119 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1121 pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1122 buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1127 number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
1128 image_view=AcquireVirtualCacheView(image,exception);
1129 despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1130 for (i=0; i < (ssize_t) number_channels; i++)
1140 if (status == MagickFalse)
1142 if ((image->matte == MagickFalse) && (i == 3))
1144 (void) memset(pixels,0,length*
sizeof(*pixels));
1145 j=(ssize_t) image->columns+2;
1146 for (y=0; y < (ssize_t) image->rows; y++)
1149 *magick_restrict indexes;
1154 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1157 indexes=GetCacheViewVirtualIndexQueue(image_view);
1159 for (x=0; x < (ssize_t) image->columns; x++)
1163 case 0: pixels[j]=GetPixelRed(p);
break;
1164 case 1: pixels[j]=GetPixelGreen(p);
break;
1165 case 2: pixels[j]=GetPixelBlue(p);
break;
1166 case 3: pixels[j]=GetPixelOpacity(p);
break;
1167 case 4: pixels[j]=GetPixelBlack(indexes+x);
break;
1175 (void) memset(buffer,0,length*
sizeof(*buffer));
1176 for (k=0; k < 4; k++)
1178 Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1179 Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1180 Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1181 Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1183 j=(ssize_t) image->columns+2;
1184 for (y=0; y < (ssize_t) image->rows; y++)
1190 *magick_restrict indexes;
1195 q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1199 indexes=GetCacheViewAuthenticIndexQueue(despeckle_view);
1201 for (x=0; x < (ssize_t) image->columns; x++)
1205 case 0: SetPixelRed(q,pixels[j]);
break;
1206 case 1: SetPixelGreen(q,pixels[j]);
break;
1207 case 2: SetPixelBlue(q,pixels[j]);
break;
1208 case 3: SetPixelOpacity(q,pixels[j]);
break;
1209 case 4: SetPixelIndex(indexes+x,pixels[j]);
break;
1215 sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1216 if (sync == MagickFalse)
1223 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1228 proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
1230 if (proceed == MagickFalse)
1234 despeckle_view=DestroyCacheView(despeckle_view);
1235 image_view=DestroyCacheView(image_view);
1236 buffer_info=RelinquishVirtualMemory(buffer_info);
1237 pixel_info=RelinquishVirtualMemory(pixel_info);
1238 despeckle_image->type=image->type;
1239 if (status == MagickFalse)
1240 despeckle_image=DestroyImage(despeckle_image);
1241 return(despeckle_image);
1273 MagickExport
Image *EdgeImage(
const Image *image,
const double radius,
1288 assert(image != (
const Image *) NULL);
1289 assert(image->signature == MagickCoreSignature);
1291 assert(exception->signature == MagickCoreSignature);
1292 if (IsEventLogging() != MagickFalse)
1293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1294 width=GetOptimalKernelWidth1D(radius,0.5);
1295 kernel_info=AcquireKernelInfo((
const char *) NULL);
1297 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1298 (void) memset(kernel_info,0,
sizeof(*kernel_info));
1299 kernel_info->width=width;
1300 kernel_info->height=width;
1301 kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1302 kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1303 kernel_info->signature=MagickCoreSignature;
1304 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
1305 kernel_info->width,kernel_info->height*
sizeof(*kernel_info->values)));
1306 if (kernel_info->values == (
double *) NULL)
1308 kernel_info=DestroyKernelInfo(kernel_info);
1309 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1311 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1312 kernel_info->values[i]=(-1.0);
1313 kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1314 edge_image=(
Image *) NULL;
1315 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1316 edge_image=AccelerateConvolveImageChannel(image,DefaultChannels,kernel_info,
1319 if (edge_image == (
Image *) NULL)
1320 edge_image=MorphologyImageChannel(image,DefaultChannels,ConvolveMorphology,
1321 1,kernel_info,exception);
1322 kernel_info=DestroyKernelInfo(kernel_info);
1359 MagickExport
Image *EmbossImage(
const Image *image,
const double radius,
1384 assert(image != (
const Image *) NULL);
1385 assert(image->signature == MagickCoreSignature);
1387 assert(exception->signature == MagickCoreSignature);
1388 if (IsEventLogging() != MagickFalse)
1389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1390 width=GetOptimalKernelWidth1D(radius,sigma);
1391 kernel_info=AcquireKernelInfo((
const char *) NULL);
1393 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1394 kernel_info->width=width;
1395 kernel_info->height=width;
1396 kernel_info->x=(ssize_t) (width-1)/2;
1397 kernel_info->y=(ssize_t) (width-1)/2;
1398 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
1399 kernel_info->width,kernel_info->width*
sizeof(*kernel_info->values)));
1400 if (kernel_info->values == (
double *) NULL)
1402 kernel_info=DestroyKernelInfo(kernel_info);
1403 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1405 j=(ssize_t) (kernel_info->width-1)/2;
1408 for (v=(-j); v <= j; v++)
1410 for (u=(-j); u <= j; u++)
1412 kernel_info->values[i]=(double) (((u < 0) || (v < 0) ? -8.0 :
1413 8.0)*exp(-((
double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1414 (2.0*MagickPI*MagickSigma*MagickSigma));
1416 kernel_info->values[i]=0.0;
1422 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1423 normalize+=kernel_info->values[i];
1424 gamma=PerceptibleReciprocal(normalize);
1425 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1426 kernel_info->values[i]*=gamma;
1427 emboss_image=(
Image *) NULL;
1428 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1429 emboss_image=AccelerateConvolveImageChannel(image,DefaultChannels,kernel_info,
1432 if (emboss_image == (
Image *) NULL)
1433 emboss_image=MorphologyImageChannel(image,DefaultChannels,
1434 ConvolveMorphology,1,kernel_info,exception);
1435 kernel_info=DestroyKernelInfo(kernel_info);
1436 if (emboss_image != (
Image *) NULL)
1437 (void) EqualizeImageChannel(emboss_image,(ChannelType)
1438 (AllChannels &~ SyncChannels));
1439 return(emboss_image);
1480 filter_image=FilterImageChannel(image,DefaultChannels,kernel,exception);
1481 return(filter_image);
1484 MagickExport
Image *FilterImageChannel(
const Image *image,
1487 #define FilterImageTag "Filter/Image"
1514 #ifdef MAGICKCORE_CLPERFMARKER
1515 clBeginPerfMarkerAMD(__FUNCTION__,
"");
1521 assert(image != (
Image *) NULL);
1522 assert(image->signature == MagickCoreSignature);
1524 assert(exception->signature == MagickCoreSignature);
1525 if (IsEventLogging() != MagickFalse)
1526 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1527 if ((kernel->width % 2) == 0)
1528 ThrowImageException(OptionError,
"KernelWidthMustBeAnOddNumber");
1529 if (image->debug != MagickFalse)
1532 format[MaxTextExtent],
1542 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1543 " FilterImage with %.20gx%.20g kernel:",(double) kernel->width,(
double)
1545 message=AcquireString(
"");
1547 for (v=0; v < (ssize_t) kernel->height; v++)
1550 (void) FormatLocaleString(format,MaxTextExtent,
"%.20g: ",(
double) v);
1551 (void) ConcatenateString(&message,format);
1552 for (u=0; u < (ssize_t) kernel->width; u++)
1554 (void) FormatLocaleString(format,MaxTextExtent,
"%g ",*k++);
1555 (void) ConcatenateString(&message,format);
1557 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
1559 message=DestroyString(message);
1561 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1562 filter_image=AccelerateConvolveImageChannel(image,channel,kernel,exception);
1563 if (filter_image != (
Image *) NULL)
1565 #ifdef MAGICKCORE_CLPERFMARKER
1566 clEndPerfMarkerAMD();
1568 return(filter_image);
1571 filter_image=CloneImage(image,0,0,MagickTrue,exception);
1572 if (filter_image == (
Image *) NULL)
1573 return((
Image *) NULL);
1574 if (SetImageStorageClass(filter_image,DirectClass) == MagickFalse)
1576 InheritException(exception,&filter_image->exception);
1577 filter_image=DestroyImage(filter_image);
1578 return((
Image *) NULL);
1583 filter_kernel=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
1584 kernel->width,kernel->height*
sizeof(*filter_kernel)));
1585 if (filter_kernel == (MagickRealType *) NULL)
1587 filter_image=DestroyImage(filter_image);
1588 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1590 for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
1591 filter_kernel[i]=(MagickRealType) kernel->values[i];
1597 GetMagickPixelPacket(image,&bias);
1598 SetMagickPixelPacketBias(image,&bias);
1599 image_view=AcquireVirtualCacheView(image,exception);
1600 filter_view=AcquireAuthenticCacheView(filter_image,exception);
1601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1602 #pragma omp parallel for schedule(static) shared(progress,status) \
1603 magick_number_threads(image,filter_image,image->rows,1)
1605 for (y=0; y < (ssize_t) image->rows; y++)
1611 *magick_restrict indexes;
1617 *magick_restrict filter_indexes;
1625 if (status == MagickFalse)
1627 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (kernel->width-1)/2L),y-
1628 (ssize_t) ((kernel->height-1)/2L),image->columns+kernel->width,
1629 kernel->height,exception);
1630 q=GetCacheViewAuthenticPixels(filter_view,0,y,filter_image->columns,1,
1637 indexes=GetCacheViewVirtualIndexQueue(image_view);
1638 filter_indexes=GetCacheViewAuthenticIndexQueue(filter_view);
1639 for (x=0; x < (ssize_t) image->columns; x++)
1644 const MagickRealType
1648 *magick_restrict kernel_pixels;
1657 pixel.green=bias.green;
1658 pixel.blue=bias.blue;
1659 pixel.opacity=bias.opacity;
1660 pixel.index=bias.index;
1663 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
1665 for (v=0; v < (ssize_t) kernel->width; v++)
1667 for (u=0; u < (ssize_t) kernel->height; u++)
1669 pixel.red+=(*k)*(double) kernel_pixels[u].red;
1670 pixel.green+=(*k)*(double) kernel_pixels[u].green;
1671 pixel.blue+=(*k)*(double) kernel_pixels[u].blue;
1674 kernel_pixels+=image->columns+kernel->width;
1676 if ((channel & RedChannel) != 0)
1677 SetPixelRed(q,ClampToQuantum(pixel.red));
1678 if ((channel & GreenChannel) != 0)
1679 SetPixelGreen(q,ClampToQuantum(pixel.green));
1680 if ((channel & BlueChannel) != 0)
1681 SetPixelBlue(q,ClampToQuantum(pixel.blue));
1682 if ((channel & OpacityChannel) != 0)
1686 for (v=0; v < (ssize_t) kernel->width; v++)
1688 for (u=0; u < (ssize_t) kernel->height; u++)
1690 pixel.opacity+=(*k)*(MagickRealType) kernel_pixels[u].opacity;
1693 kernel_pixels+=image->columns+kernel->width;
1695 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
1697 if (((channel & IndexChannel) != 0) &&
1698 (image->colorspace == CMYKColorspace))
1701 *magick_restrict kernel_indexes;
1704 kernel_indexes=indexes;
1705 for (v=0; v < (ssize_t) kernel->width; v++)
1707 for (u=0; u < (ssize_t) kernel->height; u++)
1709 pixel.index+=(*k)*(double) GetPixelIndex(kernel_indexes+u);
1712 kernel_indexes+=image->columns+kernel->width;
1714 SetPixelIndex(filter_indexes+x,ClampToQuantum(pixel.index));
1724 for (v=0; v < (ssize_t) kernel->width; v++)
1726 for (u=0; u < (ssize_t) kernel->height; u++)
1728 alpha=(MagickRealType) QuantumScale*((MagickRealType)
1729 QuantumRange-(MagickRealType) GetPixelOpacity(kernel_pixels+u));
1730 pixel.red+=(*k)*alpha*(double) GetPixelRed(kernel_pixels+u);
1731 pixel.green+=(*k)*alpha*(double) GetPixelGreen(kernel_pixels+u);
1732 pixel.blue+=(*k)*alpha*(double) GetPixelBlue(kernel_pixels+u);
1736 kernel_pixels+=image->columns+kernel->width;
1738 gamma=PerceptibleReciprocal(gamma);
1739 if ((channel & RedChannel) != 0)
1740 SetPixelRed(q,ClampToQuantum(gamma*(
double) pixel.red));
1741 if ((channel & GreenChannel) != 0)
1742 SetPixelGreen(q,ClampToQuantum(gamma*(
double) pixel.green));
1743 if ((channel & BlueChannel) != 0)
1744 SetPixelBlue(q,ClampToQuantum(gamma*(
double) pixel.blue));
1745 if ((channel & OpacityChannel) != 0)
1749 for (v=0; v < (ssize_t) kernel->width; v++)
1751 for (u=0; u < (ssize_t) kernel->height; u++)
1753 pixel.opacity+=(*k)*(double) GetPixelOpacity(kernel_pixels+u);
1756 kernel_pixels+=image->columns+kernel->width;
1758 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
1760 if (((channel & IndexChannel) != 0) &&
1761 (image->colorspace == CMYKColorspace))
1764 *magick_restrict kernel_indexes;
1768 kernel_indexes=indexes;
1769 for (v=0; v < (ssize_t) kernel->width; v++)
1771 for (u=0; u < (ssize_t) kernel->height; u++)
1773 alpha=(MagickRealType) (QuantumScale*((
double) QuantumRange-
1774 (double) kernel_pixels[u].opacity));
1775 pixel.index+=(*k)*alpha*(MagickRealType)
1776 GetPixelIndex(kernel_indexes+u);
1779 kernel_pixels+=image->columns+kernel->width;
1780 kernel_indexes+=image->columns+kernel->width;
1782 SetPixelIndex(filter_indexes+x,ClampToQuantum(gamma*(
double)
1790 sync=SyncCacheViewAuthenticPixels(filter_view,exception);
1791 if (sync == MagickFalse)
1793 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1798 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1802 proceed=SetImageProgress(image,FilterImageTag,progress,image->rows);
1803 if (proceed == MagickFalse)
1807 filter_image->type=image->type;
1808 filter_view=DestroyCacheView(filter_view);
1809 image_view=DestroyCacheView(image_view);
1810 filter_kernel=(MagickRealType *) RelinquishAlignedMemory(filter_kernel);
1811 if (status == MagickFalse)
1812 filter_image=DestroyImage(filter_image);
1813 #ifdef MAGICKCORE_CLPERFMARKER
1814 clEndPerfMarkerAMD();
1816 return(filter_image);
1858 MagickExport
Image *GaussianBlurImage(
const Image *image,
const double radius,
1864 blur_image=GaussianBlurImageChannel(image,DefaultChannels,radius,sigma,
1869 MagickExport
Image *GaussianBlurImageChannel(
const Image *image,
1870 const ChannelType channel,
const double radius,
const double sigma,
1874 geometry[MaxTextExtent];
1882 assert(image != (
const Image *) NULL);
1883 assert(image->signature == MagickCoreSignature);
1885 assert(exception->signature == MagickCoreSignature);
1886 if (IsEventLogging() != MagickFalse)
1887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1888 (void) FormatLocaleString(geometry,MaxTextExtent,
"gaussian:%.20gx%.20g",
1890 kernel_info=AcquireKernelInfo(geometry);
1892 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1893 blur_image=(
Image *) NULL;
1894 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1895 blur_image=AccelerateConvolveImageChannel(image,channel,kernel_info,
1898 if (blur_image == (
Image *) NULL)
1899 blur_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
1900 kernel_info,exception);
1901 kernel_info=DestroyKernelInfo(kernel_info);
1949 static double *GetMotionBlurKernel(
const size_t width,
const double sigma)
1961 if (IsEventLogging() != MagickFalse)
1962 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
1963 kernel=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
1965 if (kernel == (
double *) NULL)
1968 for (i=0; i < (ssize_t) width; i++)
1970 kernel[i]=(double) (exp((-((
double) i*i)/(
double) (2.0*MagickSigma*
1971 MagickSigma)))/(MagickSQ2PI*MagickSigma));
1972 normalize+=kernel[i];
1974 for (i=0; i < (ssize_t) width; i++)
1975 kernel[i]/=normalize;
1979 MagickExport
Image *MotionBlurImage(
const Image *image,
const double radius,
1980 const double sigma,
const double angle,
ExceptionInfo *exception)
1985 motion_blur=MotionBlurImageChannel(image,DefaultChannels,radius,sigma,angle,
1987 return(motion_blur);
1990 MagickExport
Image *MotionBlurImageChannel(
const Image *image,
1991 const ChannelType channel,
const double radius,
const double sigma,
1994 #define BlurImageTag "Blur/Image"
2030 assert(image != (
Image *) NULL);
2031 assert(image->signature == MagickCoreSignature);
2033 assert(exception->signature == MagickCoreSignature);
2034 if (IsEventLogging() != MagickFalse)
2035 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2036 width=GetOptimalKernelWidth1D(radius,sigma);
2037 kernel=GetMotionBlurKernel(width,sigma);
2038 if (kernel == (
double *) NULL)
2039 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2040 offset=(
OffsetInfo *) AcquireQuantumMemory(width,
sizeof(*offset));
2043 kernel=(
double *) RelinquishAlignedMemory(kernel);
2044 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2047 point.x=(double) width*sin(DegreesToRadians(angle));
2048 point.y=(double) width*cos(DegreesToRadians(angle));
2049 for (i=0; i < (ssize_t) width; i++)
2051 offset[i].x=CastDoubleToLong(ceil((
double) (i*point.y)/
2052 hypot(point.x,point.y)-0.5));
2053 offset[i].y=CastDoubleToLong(ceil((
double) (i*point.x)/
2054 hypot(point.x,point.y)-0.5));
2060 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2061 blur_image=AccelerateMotionBlurImage(image,channel,kernel,width,offset,
2063 if (blur_image != (
Image *) NULL)
2066 blur_image=CloneImage(image,0,0,MagickTrue,exception);
2067 if (blur_image == (
Image *) NULL)
2069 kernel=(
double *) RelinquishAlignedMemory(kernel);
2070 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2071 return((
Image *) NULL);
2073 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
2075 kernel=(
double *) RelinquishAlignedMemory(kernel);
2076 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2077 InheritException(exception,&blur_image->exception);
2078 blur_image=DestroyImage(blur_image);
2079 return((
Image *) NULL);
2084 GetMagickPixelPacket(image,&bias);
2085 image_view=AcquireVirtualCacheView(image,exception);
2086 blur_view=AcquireAuthenticCacheView(blur_image,exception);
2087 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2088 #pragma omp parallel for schedule(static) shared(progress,status) \
2089 magick_number_threads(image,blur_image,image->rows,1)
2091 for (y=0; y < (ssize_t) image->rows; y++)
2094 *magick_restrict blur_indexes;
2102 if (status == MagickFalse)
2104 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2111 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
2112 for (x=0; x < (ssize_t) image->columns; x++)
2121 *magick_restrict indexes;
2131 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
2133 for (i=0; i < (ssize_t) width; i++)
2135 (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
2136 offset[i].y,&pixel,exception);
2137 qixel.red+=(*k)*(double) pixel.red;
2138 qixel.green+=(*k)*(double) pixel.green;
2139 qixel.blue+=(*k)*(double) pixel.blue;
2140 qixel.opacity+=(*k)*(double) pixel.opacity;
2141 if (image->colorspace == CMYKColorspace)
2143 indexes=GetCacheViewVirtualIndexQueue(image_view);
2144 qixel.index+=(*k)*(double) (*indexes);
2148 if ((channel & RedChannel) != 0)
2149 SetPixelRed(q,ClampToQuantum(qixel.red));
2150 if ((channel & GreenChannel) != 0)
2151 SetPixelGreen(q,ClampToQuantum(qixel.green));
2152 if ((channel & BlueChannel) != 0)
2153 SetPixelBlue(q,ClampToQuantum(qixel.blue));
2154 if ((channel & OpacityChannel) != 0)
2155 SetPixelOpacity(q,ClampToQuantum(qixel.opacity));
2156 if (((channel & IndexChannel) != 0) &&
2157 (image->colorspace == CMYKColorspace))
2158 SetPixelIndex(blur_indexes+x,ClampToQuantum(qixel.index));
2166 for (i=0; i < (ssize_t) width; i++)
2168 (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
2169 offset[i].y,&pixel,exception);
2170 alpha=(MagickRealType) (QuantumScale*(
double)
2171 GetPixelAlpha(&pixel));
2172 qixel.red+=(*k)*alpha*(double) pixel.red;
2173 qixel.green+=(*k)*alpha*(double) pixel.green;
2174 qixel.blue+=(*k)*alpha*(double) pixel.blue;
2175 qixel.opacity+=(*k)*(double) pixel.opacity;
2176 if (image->colorspace == CMYKColorspace)
2178 indexes=GetCacheViewVirtualIndexQueue(image_view);
2179 qixel.index+=(*k)*alpha*(double) GetPixelIndex(indexes);
2184 gamma=PerceptibleReciprocal(gamma);
2185 if ((channel & RedChannel) != 0)
2186 SetPixelRed(q,ClampToQuantum(gamma*qixel.red));
2187 if ((channel & GreenChannel) != 0)
2188 SetPixelGreen(q,ClampToQuantum(gamma*qixel.green));
2189 if ((channel & BlueChannel) != 0)
2190 SetPixelBlue(q,ClampToQuantum(gamma*qixel.blue));
2191 if ((channel & OpacityChannel) != 0)
2192 SetPixelOpacity(q,ClampToQuantum(qixel.opacity));
2193 if (((channel & IndexChannel) != 0) &&
2194 (image->colorspace == CMYKColorspace))
2195 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*qixel.index));
2199 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2201 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2206 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2210 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2211 if (proceed == MagickFalse)
2215 blur_view=DestroyCacheView(blur_view);
2216 image_view=DestroyCacheView(image_view);
2217 kernel=(
double *) RelinquishAlignedMemory(kernel);
2218 offset=(
OffsetInfo *) RelinquishMagickMemory(offset);
2219 if (status == MagickFalse)
2220 blur_image=DestroyImage(blur_image);
2258 MagickExport
Image *KuwaharaImage(
const Image *image,
const double radius,
2264 kuwahara_image=KuwaharaImageChannel(image,DefaultChannels,radius,sigma,
2266 return(kuwahara_image);
2269 MagickExport
Image *KuwaharaImageChannel(
const Image *image,
2270 const ChannelType channel,
const double radius,
const double sigma,
2273 #define KuwaharaImageTag "Kiwahara/Image"
2298 assert(image != (
Image *) NULL);
2299 assert(image->signature == MagickCoreSignature);
2301 assert(exception->signature == MagickCoreSignature);
2302 if (IsEventLogging() != MagickFalse)
2303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2305 width=(size_t) radius+1;
2306 gaussian_image=BlurImage(image,radius,sigma,exception);
2307 if (gaussian_image == (
Image *) NULL)
2308 return((
Image *) NULL);
2309 kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
2310 if (kuwahara_image == (
Image *) NULL)
2312 gaussian_image=DestroyImage(gaussian_image);
2313 return((
Image *) NULL);
2315 if (SetImageStorageClass(kuwahara_image,DirectClass) == MagickFalse)
2317 InheritException(exception,&kuwahara_image->exception);
2318 gaussian_image=DestroyImage(gaussian_image);
2319 kuwahara_image=DestroyImage(kuwahara_image);
2320 return((
Image *) NULL);
2327 image_view=AcquireVirtualCacheView(gaussian_image,exception);
2328 kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
2329 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2330 #pragma omp parallel for schedule(static) shared(progress,status) \
2331 magick_number_threads(image,kuwahara_image,kuwahara_image->rows,1)
2333 for (y=0; y < (ssize_t) kuwahara_image->rows; y++)
2336 *magick_restrict kuwahara_indexes;
2344 if (status == MagickFalse)
2346 q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
2353 kuwahara_indexes=GetCacheViewAuthenticIndexQueue(kuwahara_view);
2354 for (x=0; x < (ssize_t) kuwahara_image->columns; x++)
2369 min_variance=MagickMaximumValue;
2370 SetGeometry(gaussian_image,&target);
2371 quadrant.width=width;
2372 quadrant.height=width;
2373 for (i=0; i < 4; i++)
2396 quadrant.x=x-(ssize_t) (width-1);
2397 quadrant.y=y-(ssize_t) (width-1);
2402 quadrant.y=y-(ssize_t) (width-1);
2407 quadrant.x=x-(ssize_t) (width-1);
2413 p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
2414 quadrant.width,quadrant.height,exception);
2417 GetMagickPixelPacket(image,&mean);
2419 for (n=0; n < (ssize_t) (width*width); n++)
2421 mean.red+=(double) k->red;
2422 mean.green+=(
double) k->green;
2423 mean.blue+=(double) k->blue;
2426 mean.red/=(double) (width*width);
2427 mean.green/=(double) (width*width);
2428 mean.blue/=(double) (width*width);
2431 for (n=0; n < (ssize_t) (width*width); n++)
2436 luma=GetPixelLuma(image,k);
2437 variance+=(luma-MagickPixelLuma(&mean))*(luma-MagickPixelLuma(&mean));
2440 if (variance < min_variance)
2442 min_variance=variance;
2451 status=InterpolateMagickPixelPacket(gaussian_image,image_view,
2452 UndefinedInterpolatePixel,(
double) target.x+target.width/2.0,
2453 (
double) target.y+target.height/2.0,&pixel,exception);
2454 if (status == MagickFalse)
2456 SetPixelPacket(kuwahara_image,&pixel,q,kuwahara_indexes+x);
2459 if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
2461 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2466 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2470 proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
2471 if (proceed == MagickFalse)
2475 kuwahara_view=DestroyCacheView(kuwahara_view);
2476 image_view=DestroyCacheView(image_view);
2477 gaussian_image=DestroyImage(gaussian_image);
2478 if (status == MagickFalse)
2479 kuwahara_image=DestroyImage(kuwahara_image);
2480 return(kuwahara_image);
2516 MagickExport
Image *LocalContrastImage(
const Image *image,
const double radius,
2519 #define LocalContrastImageTag "LocalContrast/Image"
2547 assert(image != (
const Image *) NULL);
2548 assert(image->signature == MagickCoreSignature);
2550 assert(exception->signature == MagickCoreSignature);
2551 if (IsEventLogging() != MagickFalse)
2552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2553 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2554 contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2555 if (contrast_image != (
Image *) NULL)
2556 return(contrast_image);
2558 contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2559 if (contrast_image == (
Image *) NULL)
2560 return((
Image *) NULL);
2561 if (SetImageStorageClass(contrast_image,DirectClass) == MagickFalse)
2563 InheritException(exception,&contrast_image->exception);
2564 contrast_image=DestroyImage(contrast_image);
2565 return((
Image *) NULL);
2567 image_view=AcquireVirtualCacheView(image,exception);
2568 contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2569 scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2570 width=(ssize_t) scanLineSize*0.002*fabs(radius);
2571 scanLineSize+=(2*width);
2572 scanline_info=AcquireVirtualMemory(GetOpenMPMaximumThreads()*
2573 scanLineSize,
sizeof(*scanline));
2576 contrast_view=DestroyCacheView(contrast_view);
2577 image_view=DestroyCacheView(image_view);
2578 contrast_image=DestroyImage(contrast_image);
2579 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2581 scanline=(
float *) GetVirtualMemoryBlob(scanline_info);
2585 interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(2*width)),
2586 sizeof(*interImage));
2589 scanline_info=RelinquishVirtualMemory(scanline_info);
2590 contrast_view=DestroyCacheView(contrast_view);
2591 image_view=DestroyCacheView(image_view);
2592 contrast_image=DestroyImage(contrast_image);
2593 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2595 interImage=(
float *) GetVirtualMemoryBlob(interImage_info);
2596 totalWeight=(width+1)*(width+1);
2605 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2606 #pragma omp parallel for schedule(static) \
2607 magick_number_threads(image,image,image->columns,1)
2609 for (x=0; x < (ssize_t) image->columns; x++)
2612 id = GetOpenMPThreadId();
2628 if (status == MagickFalse)
2631 pixels+=
id*scanLineSize;
2633 p=GetCacheViewVirtualPixels(image_view,x,-width,1,image->rows+(2*width),
2640 for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2642 *pix++=(float)GetPixelLuma(image,p);
2645 out=interImage+x+width;
2646 for (y=0; y < (ssize_t) image->rows; y++)
2655 for (i=0; i < width; i++)
2657 sum+=weight*(*pix++);
2660 for (i=width+1; i < (2*width); i++)
2662 sum+=weight*(*pix++);
2666 *out=sum/totalWeight;
2668 if (x <= width && x != 0)
2670 if ((x > (ssize_t) image->columns-width-2) &&
2671 (x != (ssize_t) image->columns-1))
2672 *(out+((image->columns-x-1)*2))=*out;
2673 out+=image->columns+(width*2);
2684 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2685 #pragma omp parallel for schedule(static) \
2686 magick_number_threads(image,image,image->rows,1)
2688 for (y=0; y < (ssize_t) image->rows; y++)
2691 id = GetOpenMPThreadId();
2709 if (status == MagickFalse)
2712 pixels+=
id*scanLineSize;
2713 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
2715 q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2722 memcpy(pixels,interImage+(y*(image->columns+(2*width))),(image->columns+
2723 (2*width))*
sizeof(
float));
2724 for (x=0; x < (ssize_t) image->columns; x++)
2735 for (i=0; i < width; i++)
2737 sum+=weight*(*pix++);
2740 for (i=width+1; i < (2*width); i++)
2742 sum+=weight*(*pix++);
2746 srcVal=(float) GetPixelLuma(image,p);
2747 mult=(srcVal-(sum/totalWeight))*(float) (0.01*strength);
2748 mult=(srcVal+mult)/srcVal;
2749 SetPixelRed(q,ClampToQuantum((MagickRealType) GetPixelRed(p)*
2750 (MagickRealType) mult));
2751 SetPixelGreen(q,ClampToQuantum((MagickRealType) GetPixelGreen(p)*
2752 (MagickRealType) mult));
2753 SetPixelBlue(q,ClampToQuantum((MagickRealType) GetPixelBlue(p)*
2754 (MagickRealType) mult));
2758 if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2762 scanline_info=RelinquishVirtualMemory(scanline_info);
2763 interImage_info=RelinquishVirtualMemory(interImage_info);
2764 contrast_view=DestroyCacheView(contrast_view);
2765 image_view=DestroyCacheView(image_view);
2766 if (status == MagickFalse)
2767 contrast_image=DestroyImage(contrast_image);
2768 return(contrast_image);
2801 MagickExport
Image *PreviewImage(
const Image *image,
const PreviewType preview,
2804 #define NumberTiles 9
2805 #define PreviewImageTag "Preview/Image"
2806 #define DefaultPreviewGeometry "204x204+10+10"
2809 factor[MaxTextExtent],
2810 label[MaxTextExtent];
2852 assert(image != (
Image *) NULL);
2853 assert(image->signature == MagickCoreSignature);
2854 if (IsEventLogging() != MagickFalse)
2855 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2859 preview_info=AcquireImageInfo();
2860 SetGeometry(image,&geometry);
2861 (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2862 &geometry.width,&geometry.height);
2863 images=NewImageList();
2865 GetQuantizeInfo(&quantize_info);
2871 for (i=0; i < NumberTiles; i++)
2873 thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2874 if (thumbnail == (
Image *) NULL)
2876 (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2878 (void) SetImageProperty(thumbnail,
"label",DefaultTileLabel);
2879 if (i == (NumberTiles/2))
2881 (void) QueryColorDatabase(
"#dfdfdf",&thumbnail->matte_color,exception);
2882 AppendImageToList(&images,thumbnail);
2890 preview_image=RotateImage(thumbnail,degrees,exception);
2891 (void) FormatLocaleString(label,MaxTextExtent,
"rotate %g",degrees);
2897 preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2898 (void) FormatLocaleString(label,MaxTextExtent,
"shear %gx%g",
2899 degrees,2.0*degrees);
2904 x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
2905 y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
2906 preview_image=RollImage(thumbnail,x,y,exception);
2907 (void) FormatLocaleString(label,MaxTextExtent,
"roll %+.20gx%+.20g",
2908 (
double) x,(double) y);
2913 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2914 if (preview_image == (
Image *) NULL)
2916 (void) FormatLocaleString(factor,MaxTextExtent,
"100,100,%g",
2918 (void) ModulateImage(preview_image,factor);
2919 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2922 case SaturationPreview:
2924 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2925 if (preview_image == (
Image *) NULL)
2927 (void) FormatLocaleString(factor,MaxTextExtent,
"100,%g",2.0*percentage);
2928 (void) ModulateImage(preview_image,factor);
2929 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2932 case BrightnessPreview:
2934 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2935 if (preview_image == (
Image *) NULL)
2937 (void) FormatLocaleString(factor,MaxTextExtent,
"%g",2.0*percentage);
2938 (void) ModulateImage(preview_image,factor);
2939 (void) FormatLocaleString(label,MaxTextExtent,
"modulate %s",factor);
2945 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2946 if (preview_image == (
Image *) NULL)
2949 (void) GammaImageChannel(preview_image,DefaultChannels,gamma);
2950 (void) FormatLocaleString(label,MaxTextExtent,
"gamma %g",gamma);
2955 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2956 if (preview_image != (
Image *) NULL)
2957 for (x=0; x < i; x++)
2958 (
void) ContrastImage(preview_image,MagickTrue);
2959 (void) FormatLocaleString(label,MaxTextExtent,
"contrast (%.20g)",
2965 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2966 if (preview_image == (
Image *) NULL)
2968 for (x=0; x < i; x++)
2969 (
void) ContrastImage(preview_image,MagickFalse);
2970 (void) FormatLocaleString(label,MaxTextExtent,
"+contrast (%.20g)",
2974 case GrayscalePreview:
2976 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2977 if (preview_image == (
Image *) NULL)
2980 quantize_info.number_colors=colors;
2981 quantize_info.colorspace=GRAYColorspace;
2982 (void) QuantizeImage(&quantize_info,preview_image);
2983 (void) FormatLocaleString(label,MaxTextExtent,
2984 "-colorspace gray -colors %.20g",(
double) colors);
2987 case QuantizePreview:
2989 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2990 if (preview_image == (
Image *) NULL)
2993 quantize_info.number_colors=colors;
2994 (void) QuantizeImage(&quantize_info,preview_image);
2995 (void) FormatLocaleString(label,MaxTextExtent,
"colors %.20g",(
double)
2999 case DespecklePreview:
3001 for (x=0; x < (i-1); x++)
3003 preview_image=DespeckleImage(thumbnail,exception);
3004 if (preview_image == (
Image *) NULL)
3006 thumbnail=DestroyImage(thumbnail);
3007 thumbnail=preview_image;
3009 preview_image=DespeckleImage(thumbnail,exception);
3010 if (preview_image == (
Image *) NULL)
3012 (void) FormatLocaleString(label,MaxTextExtent,
"despeckle (%.20g)",
3016 case ReduceNoisePreview:
3018 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) radius,
3019 (
size_t) radius,exception);
3020 (void) FormatLocaleString(label,MaxTextExtent,
"noise %g",radius);
3023 case AddNoisePreview:
3029 (void) CopyMagickString(factor,
"uniform",MaxTextExtent);
3034 (void) CopyMagickString(factor,
"gaussian",MaxTextExtent);
3039 (void) CopyMagickString(factor,
"multiplicative",MaxTextExtent);
3044 (void) CopyMagickString(factor,
"impulse",MaxTextExtent);
3049 (void) CopyMagickString(factor,
"laplacian",MaxTextExtent);
3054 (void) CopyMagickString(factor,
"poisson",MaxTextExtent);
3059 (void) CopyMagickString(thumbnail->magick,
"NULL",MaxTextExtent);
3063 preview_image=StatisticImage(thumbnail,NonpeakStatistic,(
size_t) i,
3064 (
size_t) i,exception);
3065 (void) FormatLocaleString(label,MaxTextExtent,
"+noise %s",factor);
3068 case SharpenPreview:
3070 preview_image=SharpenImage(thumbnail,radius,sigma,exception);
3071 (void) FormatLocaleString(label,MaxTextExtent,
"sharpen %gx%g",
3077 preview_image=BlurImage(thumbnail,radius,sigma,exception);
3078 (void) FormatLocaleString(label,MaxTextExtent,
"blur %gx%g",radius,
3082 case ThresholdPreview:
3084 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3085 if (preview_image == (
Image *) NULL)
3087 (void) BilevelImage(thumbnail,
3088 (
double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
3089 (void) FormatLocaleString(label,MaxTextExtent,
"threshold %g",
3090 (
double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
3093 case EdgeDetectPreview:
3095 preview_image=EdgeImage(thumbnail,radius,exception);
3096 (void) FormatLocaleString(label,MaxTextExtent,
"edge %g",radius);
3101 preview_image=SpreadImage(thumbnail,radius,exception);
3102 (void) FormatLocaleString(label,MaxTextExtent,
"spread %g",
3106 case SolarizePreview:
3108 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3109 if (preview_image == (
Image *) NULL)
3111 (void) SolarizeImage(preview_image,(
double) QuantumRange*
3113 (void) FormatLocaleString(label,MaxTextExtent,
"solarize %g",
3114 ((
double) QuantumRange*percentage)/100.0);
3120 preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
3122 (void) FormatLocaleString(label,MaxTextExtent,
"shade %gx%g",
3131 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3132 if (preview_image == (
Image *) NULL)
3134 raise.width=(size_t) (2*i+2);
3135 raise.height=(size_t) (2*i+2);
3138 (void) RaiseImage(preview_image,&
raise,MagickTrue);
3139 (void) FormatLocaleString(label,MaxTextExtent,
3140 "raise %.20gx%.20g%+.20g%+.20g",(
double)
raise.width,(double)
3141 raise.height,(
double)
raise.x,(double)
raise.y);
3144 case SegmentPreview:
3146 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3147 if (preview_image == (
Image *) NULL)
3150 (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
3152 (void) FormatLocaleString(label,MaxTextExtent,
"segment %gx%g",
3153 threshold,threshold);
3158 preview_image=SwirlImage(thumbnail,degrees,exception);
3159 (void) FormatLocaleString(label,MaxTextExtent,
"swirl %g",degrees);
3163 case ImplodePreview:
3166 preview_image=ImplodeImage(thumbnail,degrees,exception);
3167 (void) FormatLocaleString(label,MaxTextExtent,
"implode %g",degrees);
3173 preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
3174 (void) FormatLocaleString(label,MaxTextExtent,
"wave %gx%g",
3175 0.5*degrees,2.0*degrees);
3178 case OilPaintPreview:
3180 preview_image=OilPaintImage(thumbnail,(
double) radius,exception);
3181 (void) FormatLocaleString(label,MaxTextExtent,
"paint %g",radius);
3184 case CharcoalDrawingPreview:
3186 preview_image=CharcoalImage(thumbnail,(
double) radius,(
double) sigma,
3188 (void) FormatLocaleString(label,MaxTextExtent,
"charcoal %gx%g",
3195 filename[MaxTextExtent];
3203 preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3204 if (preview_image == (
Image *) NULL)
3206 preview_info->quality=(size_t) percentage;
3207 (void) FormatLocaleString(factor,MaxTextExtent,
"%.20g",(
double)
3208 preview_info->quality);
3209 file=AcquireUniqueFileResource(filename);
3212 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
3213 "jpeg:%s",filename);
3214 status=WriteImage(preview_info,preview_image);
3215 if (status != MagickFalse)
3220 (void) CopyMagickString(preview_info->filename,
3221 preview_image->filename,MaxTextExtent);
3222 quality_image=ReadImage(preview_info,exception);
3223 if (quality_image != (
Image *) NULL)
3225 preview_image=DestroyImage(preview_image);
3226 preview_image=quality_image;
3229 (void) RelinquishUniqueFileResource(preview_image->filename);
3230 if ((GetBlobSize(preview_image)/1024) >= 1024)
3231 (
void) FormatLocaleString(label,MaxTextExtent,
"quality %s\n%gmb ",
3232 factor,(
double) ((MagickOffsetType) GetBlobSize(preview_image))/
3235 if (GetBlobSize(preview_image) >= 1024)
3236 (void) FormatLocaleString(label,MaxTextExtent,
3237 "quality %s\n%gkb ",factor,(
double) ((MagickOffsetType)
3238 GetBlobSize(preview_image))/1024.0);
3240 (
void) FormatLocaleString(label,MaxTextExtent,
"quality %s\n%.20gb ",
3241 factor,(
double) ((MagickOffsetType) GetBlobSize(thumbnail)));
3245 thumbnail=DestroyImage(thumbnail);
3249 if (preview_image == (
Image *) NULL)
3251 (void) DeleteImageProperty(preview_image,
"label");
3252 (void) SetImageProperty(preview_image,
"label",label);
3253 AppendImageToList(&images,preview_image);
3254 proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
3256 if (proceed == MagickFalse)
3259 if (images == (
Image *) NULL)
3261 preview_info=DestroyImageInfo(preview_info);
3262 return((
Image *) NULL);
3267 montage_info=CloneMontageInfo(preview_info,(
MontageInfo *) NULL);
3268 (void) CopyMagickString(montage_info->filename,image->filename,MaxTextExtent);
3269 montage_info->shadow=MagickTrue;
3270 (void) CloneString(&montage_info->tile,
"3x3");
3271 (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3272 (void) CloneString(&montage_info->frame,DefaultTileFrame);
3273 montage_image=MontageImages(images,montage_info,exception);
3274 montage_info=DestroyMontageInfo(montage_info);
3275 images=DestroyImageList(images);
3276 if (montage_image == (
Image *) NULL)
3277 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3278 if (montage_image->montage != (
char *) NULL)
3283 montage_image->montage=(
char *) RelinquishMagickMemory(
3284 montage_image->montage);
3285 if (image->directory != (
char *) NULL)
3286 montage_image->directory=(
char *) RelinquishMagickMemory(
3287 montage_image->directory);
3289 preview_info=DestroyImageInfo(preview_info);
3290 return(montage_image);
3327 MagickExport
Image *RotationalBlurImage(
const Image *image,
const double angle,
3333 blur_image=RotationalBlurImageChannel(image,DefaultChannels,angle,exception);
3337 MagickExport
Image *RotationalBlurImageChannel(
const Image *image,
3338 const ChannelType channel,
const double angle,
ExceptionInfo *exception)
3378 assert(image != (
Image *) NULL);
3379 assert(image->signature == MagickCoreSignature);
3381 assert(exception->signature == MagickCoreSignature);
3382 if (IsEventLogging() != MagickFalse)
3383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3384 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3385 blur_image=AccelerateRadialBlurImage(image,channel,angle,exception);
3386 if (blur_image != (
Image *) NULL)
3389 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3390 if (blur_image == (
Image *) NULL)
3391 return((
Image *) NULL);
3392 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
3394 InheritException(exception,&blur_image->exception);
3395 blur_image=DestroyImage(blur_image);
3396 return((
Image *) NULL);
3398 blur_center.x=(double) (image->columns-1)/2.0;
3399 blur_center.y=(double) (image->rows-1)/2.0;
3400 blur_radius=hypot(blur_center.x,blur_center.y);
3401 n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((
double) blur_radius)+2UL);
3402 theta=DegreesToRadians(angle)/(MagickRealType) (n-1);
3403 cos_theta=(MagickRealType *) AcquireQuantumMemory((
size_t) n,
3404 sizeof(*cos_theta));
3405 sin_theta=(MagickRealType *) AcquireQuantumMemory((
size_t) n,
3406 sizeof(*sin_theta));
3407 if ((cos_theta == (MagickRealType *) NULL) ||
3408 (sin_theta == (MagickRealType *) NULL))
3410 if (cos_theta != (MagickRealType *) NULL)
3411 cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
3412 if (sin_theta != (MagickRealType *) NULL)
3413 sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
3414 blur_image=DestroyImage(blur_image);
3415 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3417 offset=theta*(MagickRealType) (n-1)/2.0;
3418 for (i=0; i < (ssize_t) n; i++)
3420 cos_theta[i]=cos((
double) (theta*i-offset));
3421 sin_theta[i]=sin((
double) (theta*i-offset));
3428 GetMagickPixelPacket(image,&bias);
3429 image_view=AcquireVirtualCacheView(image,exception);
3430 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3431 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3432 #pragma omp parallel for schedule(static) shared(progress,status) \
3433 magick_number_threads(image,blur_image,blur_image->rows,1)
3435 for (y=0; y < (ssize_t) blur_image->rows; y++)
3438 *magick_restrict indexes;
3441 *magick_restrict blur_indexes;
3449 if (status == MagickFalse)
3451 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3458 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
3459 for (x=0; x < (ssize_t) blur_image->columns; x++)
3480 center.x=(double) x-blur_center.x;
3481 center.y=(
double) y-blur_center.y;
3482 radius=hypot((
double) center.x,center.y);
3487 step=(size_t) (blur_radius/radius);
3496 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
3498 for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
3500 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3501 (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
3502 (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
3503 cos_theta[i]+0.5),&pixel,exception);
3504 qixel.red+=(MagickRealType) pixel.red;
3505 qixel.green+=(MagickRealType) pixel.green;
3506 qixel.blue+=(MagickRealType) pixel.blue;
3507 qixel.opacity+=(MagickRealType) pixel.opacity;
3508 if (image->colorspace == CMYKColorspace)
3510 indexes=GetCacheViewVirtualIndexQueue(image_view);
3511 qixel.index+=(MagickRealType) (*indexes);
3515 normalize=PerceptibleReciprocal(normalize);
3516 if ((channel & RedChannel) != 0)
3517 SetPixelRed(q,ClampToQuantum(normalize*qixel.red));
3518 if ((channel & GreenChannel) != 0)
3519 SetPixelGreen(q,ClampToQuantum(normalize*qixel.green));
3520 if ((channel & BlueChannel) != 0)
3521 SetPixelBlue(q,ClampToQuantum(normalize*qixel.blue));
3522 if ((channel & OpacityChannel) != 0)
3523 SetPixelOpacity(q,ClampToQuantum(normalize*qixel.opacity));
3524 if (((channel & IndexChannel) != 0) &&
3525 (image->colorspace == CMYKColorspace))
3526 SetPixelIndex(blur_indexes+x,ClampToQuantum(normalize*qixel.index));
3536 for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
3538 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3539 (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
3540 (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
3541 cos_theta[i]+0.5),&pixel,exception);
3542 alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(&pixel));
3543 qixel.red+=alpha*(MagickRealType) pixel.red;
3544 qixel.green+=alpha*(MagickRealType) pixel.green;
3545 qixel.blue+=alpha*(MagickRealType) pixel.blue;
3546 qixel.opacity+=(MagickRealType) pixel.opacity;
3547 if (image->colorspace == CMYKColorspace)
3549 indexes=GetCacheViewVirtualIndexQueue(image_view);
3550 qixel.index+=alpha*(MagickRealType) (*indexes);
3555 gamma=PerceptibleReciprocal(gamma);
3556 normalize=PerceptibleReciprocal(normalize);
3557 if ((channel & RedChannel) != 0)
3558 SetPixelRed(q,ClampToQuantum(gamma*(MagickRealType) qixel.red));
3559 if ((channel & GreenChannel) != 0)
3560 SetPixelGreen(q,ClampToQuantum(gamma*(MagickRealType) qixel.green));
3561 if ((channel & BlueChannel) != 0)
3562 SetPixelBlue(q,ClampToQuantum(gamma*(MagickRealType) qixel.blue));
3563 if ((channel & OpacityChannel) != 0)
3564 SetPixelOpacity(q,ClampToQuantum(normalize*(MagickRealType)
3566 if (((channel & IndexChannel) != 0) &&
3567 (image->colorspace == CMYKColorspace))
3568 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*(MagickRealType)
3573 if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3575 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3580 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3584 proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3585 if (proceed == MagickFalse)
3589 blur_view=DestroyCacheView(blur_view);
3590 image_view=DestroyCacheView(image_view);
3591 cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
3592 sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
3593 if (status == MagickFalse)
3594 blur_image=DestroyImage(blur_image);
3639 MagickExport
Image *SelectiveBlurImage(
const Image *image,
const double radius,
3640 const double sigma,
const double threshold,
ExceptionInfo *exception)
3645 blur_image=SelectiveBlurImageChannel(image,DefaultChannels,radius,sigma,
3646 threshold,exception);
3650 MagickExport
Image *SelectiveBlurImageChannel(
const Image *image,
3651 const ChannelType channel,
const double radius,
const double sigma,
3654 #define SelectiveBlurImageTag "SelectiveBlur/Image"
3693 assert(image != (
Image *) NULL);
3694 assert(image->signature == MagickCoreSignature);
3696 assert(exception->signature == MagickCoreSignature);
3697 if (IsEventLogging() != MagickFalse)
3698 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3699 width=GetOptimalKernelWidth1D(radius,sigma);
3700 kernel=(
double *) MagickAssumeAligned(AcquireAlignedMemory((
size_t) width,
3701 width*
sizeof(*kernel)));
3702 if (kernel == (
double *) NULL)
3703 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3704 j=(ssize_t) (width-1)/2;
3706 for (v=(-j); v <= j; v++)
3708 for (u=(-j); u <= j; u++)
3709 kernel[i++]=(
double) (exp(-((
double) u*u+v*v)/(2.0*MagickSigma*
3710 MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
3712 if (image->debug != MagickFalse)
3715 format[MaxTextExtent],
3725 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
3726 " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(
double)
3728 message=AcquireString(
"");
3730 for (v=0; v < (ssize_t) width; v++)
3733 (void) FormatLocaleString(format,MaxTextExtent,
"%.20g: ",(
double) v);
3734 (void) ConcatenateString(&message,format);
3735 for (u=0; u < (ssize_t) width; u++)
3737 (void) FormatLocaleString(format,MaxTextExtent,
"%+f ",*k++);
3738 (void) ConcatenateString(&message,format);
3740 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
"%s",message);
3742 message=DestroyString(message);
3744 blur_image=CloneImage(image,0,0,MagickTrue,exception);
3745 if (blur_image == (
Image *) NULL)
3747 kernel=(
double *) RelinquishAlignedMemory(kernel);
3748 return((
Image *) NULL);
3750 if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
3752 kernel=(
double *) RelinquishAlignedMemory(kernel);
3753 InheritException(exception,&blur_image->exception);
3754 blur_image=DestroyImage(blur_image);
3755 return((
Image *) NULL);
3757 luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3758 if (luminance_image == (
Image *) NULL)
3760 kernel=(
double *) RelinquishAlignedMemory(kernel);
3761 blur_image=DestroyImage(blur_image);
3762 return((
Image *) NULL);
3764 status=TransformImageColorspace(luminance_image,GRAYColorspace);
3765 if (status == MagickFalse)
3767 InheritException(exception,&luminance_image->exception);
3768 kernel=(
double *) RelinquishAlignedMemory(kernel);
3769 blur_image=DestroyImage(blur_image);
3770 luminance_image=DestroyImage(luminance_image);
3771 return((
Image *) NULL);
3778 center=(ssize_t) ((image->columns+width)*((width-1)/2L)+((width-1)/2L));
3779 GetMagickPixelPacket(image,&bias);
3780 SetMagickPixelPacketBias(image,&bias);
3781 image_view=AcquireVirtualCacheView(image,exception);
3782 luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3783 blur_view=AcquireAuthenticCacheView(blur_image,exception);
3784 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3785 #pragma omp parallel for schedule(static) shared(progress,status) \
3786 magick_number_threads(image,blur_image,image->rows,1)
3788 for (y=0; y < (ssize_t) image->rows; y++)
3797 *magick_restrict indexes;
3804 *magick_restrict blur_indexes;
3812 if (status == MagickFalse)
3814 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3815 ((width-1)/2L),image->columns+width,width,exception);
3816 l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3817 (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3818 q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3826 indexes=GetCacheViewVirtualIndexQueue(image_view);
3827 blur_indexes=GetCacheViewAuthenticIndexQueue(blur_view);
3828 for (x=0; x < (ssize_t) image->columns; x++)
3850 pixel.green=bias.green;
3851 pixel.blue=bias.blue;
3852 pixel.opacity=bias.opacity;
3853 pixel.index=bias.index;
3855 intensity=GetPixelIntensity(image,p+center);
3858 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
3860 for (v=0; v < (ssize_t) width; v++)
3862 for (u=0; u < (ssize_t) width; u++)
3864 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3865 if (fabs(contrast) < threshold)
3867 pixel.red+=(*k)*(MagickRealType) GetPixelRed(p+u+j);
3868 pixel.green+=(*k)*(MagickRealType) GetPixelGreen(p+u+j);
3869 pixel.blue+=(*k)*(MagickRealType) GetPixelBlue(p+u+j);
3874 j+=(ssize_t) (image->columns+width);
3878 gamma=PerceptibleReciprocal(gamma);
3879 if ((channel & RedChannel) != 0)
3880 SetPixelRed(q,ClampToQuantum(gamma*(MagickRealType)
3882 if ((channel & GreenChannel) != 0)
3883 SetPixelGreen(q,ClampToQuantum(gamma*(MagickRealType)
3885 if ((channel & BlueChannel) != 0)
3886 SetPixelBlue(q,ClampToQuantum(gamma*(MagickRealType)
3889 if ((channel & OpacityChannel) != 0)
3893 for (v=0; v < (ssize_t) width; v++)
3895 for (u=0; u < (ssize_t) width; u++)
3897 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3898 if (fabs(contrast) < threshold)
3900 pixel.opacity+=(*k)*(MagickRealType) (p+u+j)->opacity;
3905 j+=(ssize_t) (image->columns+width);
3907 gamma=PerceptibleReciprocal(gamma);
3908 SetPixelOpacity(q,ClampToQuantum(gamma*pixel.opacity));
3910 if (((channel & IndexChannel) != 0) &&
3911 (image->colorspace == CMYKColorspace))
3915 for (v=0; v < (ssize_t) width; v++)
3917 for (u=0; u < (ssize_t) width; u++)
3919 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3920 if (fabs(contrast) < threshold)
3922 pixel.index+=(*k)*(MagickRealType)
3923 GetPixelIndex(indexes+x+u+j);
3928 j+=(ssize_t) (image->columns+width);
3930 gamma=PerceptibleReciprocal(gamma);
3931 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*pixel.index));
3939 for (v=0; v < (ssize_t) width; v++)
3941 for (u=0; u < (ssize_t) width; u++)
3943 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3944 if (fabs(contrast) < threshold)
3946 alpha=(MagickRealType) (QuantumScale*(MagickRealType)
3947 GetPixelAlpha(p+u+j));
3948 pixel.red+=(*k)*alpha*(MagickRealType) GetPixelRed(p+u+j);
3949 pixel.green+=(*k)*alpha*(MagickRealType) GetPixelGreen(p+u+j);
3950 pixel.blue+=(*k)*alpha*(MagickRealType) GetPixelBlue(p+u+j);
3951 pixel.opacity+=(*k)*(MagickRealType) GetPixelOpacity(p+u+j);
3956 j+=(ssize_t) (image->columns+width);
3960 gamma=PerceptibleReciprocal(gamma);
3961 if ((channel & RedChannel) != 0)
3962 SetPixelRed(q,ClampToQuantum(gamma*(MagickRealType) pixel.red));
3963 if ((channel & GreenChannel) != 0)
3964 SetPixelGreen(q,ClampToQuantum(gamma*(MagickRealType)
3966 if ((channel & BlueChannel) != 0)
3967 SetPixelBlue(q,ClampToQuantum(gamma*(MagickRealType)
3970 if ((channel & OpacityChannel) != 0)
3973 for (v=0; v < (ssize_t) width; v++)
3975 for (u=0; u < (ssize_t) width; u++)
3977 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3978 if (fabs(contrast) < threshold)
3979 pixel.opacity+=(*k)*(MagickRealType) GetPixelOpacity(p+u+j);
3982 j+=(ssize_t) (image->columns+width);
3984 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3986 if (((channel & IndexChannel) != 0) &&
3987 (image->colorspace == CMYKColorspace))
3991 for (v=0; v < (ssize_t) width; v++)
3993 for (u=0; u < (ssize_t) width; u++)
3995 contrast=GetPixelIntensity(luminance_image,l+u+j)-intensity;
3996 if (fabs(contrast) < threshold)
3998 alpha=(MagickRealType) (QuantumScale*(MagickRealType)
3999 GetPixelAlpha(p+u+j));
4000 pixel.index+=(*k)*alpha*(MagickRealType)
4001 GetPixelIndex(indexes+x+u+j);
4006 j+=(ssize_t) (image->columns+width);
4008 gamma=PerceptibleReciprocal(gamma);
4009 SetPixelIndex(blur_indexes+x,ClampToQuantum(gamma*pixel.index));
4016 sync=SyncCacheViewAuthenticPixels(blur_view,exception);
4017 if (sync == MagickFalse)
4019 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4024 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4028 proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
4030 if (proceed == MagickFalse)
4034 blur_image->type=image->type;
4035 blur_view=DestroyCacheView(blur_view);
4036 luminance_view=DestroyCacheView(luminance_view);
4037 image_view=DestroyCacheView(image_view);
4038 luminance_image=DestroyImage(luminance_image);
4039 kernel=(
double *) RelinquishAlignedMemory(kernel);
4040 if (status == MagickFalse)
4041 blur_image=DestroyImage(blur_image);
4077 MagickExport
Image *ShadeImage(
const Image *image,
const MagickBooleanType gray,
4078 const double azimuth,
const double elevation,
ExceptionInfo *exception)
4080 #define GetShadeIntensity(image,pixel) \
4081 ClampPixel(GetPixelIntensity((image),(pixel)))
4082 #define ShadeImageTag "Shade/Image"
4107 assert(image != (
const Image *) NULL);
4108 assert(image->signature == MagickCoreSignature);
4110 assert(exception->signature == MagickCoreSignature);
4111 if (IsEventLogging() != MagickFalse)
4112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4113 linear_image=CloneImage(image,0,0,MagickTrue,exception);
4114 shade_image=CloneImage(image,0,0,MagickTrue,exception);
4115 if ((linear_image == (
Image *) NULL) || (shade_image == (
Image *) NULL))
4117 if (linear_image != (
Image *) NULL)
4118 linear_image=DestroyImage(linear_image);
4119 if (shade_image != (
Image *) NULL)
4120 shade_image=DestroyImage(shade_image);
4121 return((
Image *) NULL);
4123 if (SetImageStorageClass(shade_image,DirectClass) == MagickFalse)
4125 InheritException(exception,&shade_image->exception);
4126 linear_image=DestroyImage(linear_image);
4127 shade_image=DestroyImage(shade_image);
4128 return((
Image *) NULL);
4133 light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
4134 cos(DegreesToRadians(elevation));
4135 light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
4136 cos(DegreesToRadians(elevation));
4137 light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
4143 image_view=AcquireVirtualCacheView(linear_image,exception);
4144 shade_view=AcquireAuthenticCacheView(shade_image,exception);
4145 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4146 #pragma omp parallel for schedule(static) shared(progress,status) \
4147 magick_number_threads(linear_image,shade_image,linear_image->rows,1)
4149 for (y=0; y < (ssize_t) linear_image->rows; y++)
4161 *magick_restrict s0,
4162 *magick_restrict s1,
4163 *magick_restrict s2;
4171 if (status == MagickFalse)
4173 p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
4175 q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
4185 normal.z=2.0*(double) QuantumRange;
4186 for (x=0; x < (ssize_t) linear_image->columns; x++)
4192 s1=s0+image->columns+2;
4193 s2=s1+image->columns+2;
4194 normal.x=(double) (GetShadeIntensity(linear_image,s0-1)+
4195 GetShadeIntensity(linear_image,s1-1)+
4196 GetShadeIntensity(linear_image,s2-1)-
4197 GetShadeIntensity(linear_image,s0+1)-
4198 GetShadeIntensity(linear_image,s1+1)-
4199 GetShadeIntensity(linear_image,s2+1));
4200 normal.y=(double) (GetShadeIntensity(linear_image,s2-1)+
4201 GetShadeIntensity(linear_image,s2)+
4202 GetShadeIntensity(linear_image,s2+1)-
4203 GetShadeIntensity(linear_image,s0-1)-
4204 GetShadeIntensity(linear_image,s0)-
4205 GetShadeIntensity(linear_image,s0+1));
4206 if ((fabs(normal.x) <= MagickEpsilon) &&
4207 (fabs(normal.y) <= MagickEpsilon))
4212 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
4213 if (distance > MagickEpsilon)
4215 normal_distance=normal.x*normal.x+normal.y*normal.y+normal.z*
4217 if (normal_distance > (MagickEpsilon*MagickEpsilon))
4218 shade=distance/sqrt((
double) normal_distance);
4221 if (gray != MagickFalse)
4223 SetPixelRed(q,shade);
4224 SetPixelGreen(q,shade);
4225 SetPixelBlue(q,shade);
4229 SetPixelRed(q,ClampToQuantum(QuantumScale*shade*(MagickRealType)
4231 SetPixelGreen(q,ClampToQuantum(QuantumScale*shade*(MagickRealType)
4232 GetPixelGreen(s1)));
4233 SetPixelBlue(q,ClampToQuantum(QuantumScale*shade*(MagickRealType)
4236 q->opacity=s1->opacity;
4240 if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
4242 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4247 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4251 proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
4252 if (proceed == MagickFalse)
4256 shade_view=DestroyCacheView(shade_view);
4257 image_view=DestroyCacheView(image_view);
4258 linear_image=DestroyImage(linear_image);
4259 if (status == MagickFalse)
4260 shade_image=DestroyImage(shade_image);
4261 return(shade_image);
4307 MagickExport
Image *SharpenImage(
const Image *image,
const double radius,
4313 sharp_image=SharpenImageChannel(image,DefaultChannels,radius,sigma,exception);
4314 return(sharp_image);
4317 MagickExport
Image *SharpenImageChannel(
const Image *image,
4318 const ChannelType channel,
const double radius,
const double sigma,
4342 assert(image != (
const Image *) NULL);
4343 assert(image->signature == MagickCoreSignature);
4345 assert(exception->signature == MagickCoreSignature);
4346 if (IsEventLogging() != MagickFalse)
4347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4348 width=GetOptimalKernelWidth2D(radius,sigma);
4349 kernel_info=AcquireKernelInfo((
const char *) NULL);
4351 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4352 (void) memset(kernel_info,0,
sizeof(*kernel_info));
4353 kernel_info->width=width;
4354 kernel_info->height=width;
4355 kernel_info->x=(ssize_t) (width-1)/2;
4356 kernel_info->y=(ssize_t) (width-1)/2;
4357 kernel_info->signature=MagickCoreSignature;
4358 kernel_info->values=(
double *) MagickAssumeAligned(AcquireAlignedMemory(
4359 kernel_info->width,kernel_info->height*
sizeof(*kernel_info->values)));
4360 if (kernel_info->values == (
double *) NULL)
4362 kernel_info=DestroyKernelInfo(kernel_info);
4363 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4366 j=(ssize_t) (kernel_info->width-1)/2;
4368 for (v=(-j); v <= j; v++)
4370 for (u=(-j); u <= j; u++)
4372 kernel_info->values[i]=(double) (-exp(-((
double) u*u+v*v)/(2.0*
4373 MagickSigma*MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
4374 normalize+=kernel_info->values[i];
4378 kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4380 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4381 normalize+=kernel_info->values[i];
4382 gamma=PerceptibleReciprocal(normalize);
4383 for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4384 kernel_info->values[i]*=gamma;
4385 sharp_image=MorphologyImageChannel(image,channel,ConvolveMorphology,1,
4386 kernel_info,exception);
4387 kernel_info=DestroyKernelInfo(kernel_info);
4388 return(sharp_image);
4419 MagickExport
Image *SpreadImage(
const Image *image,
const double radius,
4422 #define SpreadImageTag "Spread/Image"
4441 **magick_restrict random_info;
4449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4457 assert(image != (
Image *) NULL);
4458 assert(image->signature == MagickCoreSignature);
4460 assert(exception->signature == MagickCoreSignature);
4461 if (IsEventLogging() != MagickFalse)
4462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4463 spread_image=CloneImage(image,0,0,MagickTrue,exception);
4464 if (spread_image == (
Image *) NULL)
4465 return((
Image *) NULL);
4466 if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
4468 InheritException(exception,&spread_image->exception);
4469 spread_image=DestroyImage(spread_image);
4470 return((
Image *) NULL);
4477 GetMagickPixelPacket(spread_image,&bias);
4478 width=GetOptimalKernelWidth1D(radius,0.5);
4479 random_info=AcquireRandomInfoTLS();
4480 image_view=AcquireVirtualCacheView(image,exception);
4481 spread_view=AcquireAuthenticCacheView(spread_image,exception);
4482 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4483 key=GetRandomSecretKey(random_info[0]);
4484 #pragma omp parallel for schedule(static) shared(progress,status) \
4485 magick_number_threads(image,spread_image,spread_image->rows,key == ~0UL)
4487 for (y=0; y < (ssize_t) spread_image->rows; y++)
4490 id = GetOpenMPThreadId();
4496 *magick_restrict indexes;
4504 if (status == MagickFalse)
4506 q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4513 indexes=GetCacheViewAuthenticIndexQueue(spread_view);
4515 for (x=0; x < (ssize_t) spread_image->columns; x++)
4520 point.x=GetPseudoRandomValue(random_info[
id]);
4521 point.y=GetPseudoRandomValue(random_info[
id]);
4522 status=InterpolateMagickPixelPacket(image,image_view,image->interpolate,
4523 (
double) x+width*(point.x-0.5),(
double) y+width*(point.y-0.5),&pixel,
4525 if (status == MagickFalse)
4527 SetPixelPacket(spread_image,&pixel,q,indexes+x);
4530 if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4532 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4537 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4541 proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4542 if (proceed == MagickFalse)
4546 spread_view=DestroyCacheView(spread_view);
4547 image_view=DestroyCacheView(image_view);
4548 random_info=DestroyRandomInfoTLS(random_info);
4549 if (status == MagickFalse)
4550 spread_image=DestroyImage(spread_image);
4551 return(spread_image);
4599 MagickExport
Image *UnsharpMaskImage(
const Image *image,
const double radius,
4600 const double sigma,
const double gain,
const double threshold,
4607 sharp_image=UnsharpMaskImageChannel(image,DefaultChannels,radius,sigma,gain,
4608 threshold,exception);
4610 return(sharp_image);
4613 MagickExport
Image *UnsharpMaskImageChannel(
const Image *image,
4614 const ChannelType channel,
const double radius,
const double sigma,
4615 const double gain,
const double threshold,
ExceptionInfo *exception)
4617 #define SharpenImageTag "Sharpen/Image"
4641 assert(image != (
const Image *) NULL);
4642 assert(image->signature == MagickCoreSignature);
4644 assert(exception->signature == MagickCoreSignature);
4645 if (IsEventLogging() != MagickFalse)
4646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4655 unsharp_image=BlurImageChannel(image,(ChannelType) (channel &~ SyncChannels),
4656 radius,sigma,exception);
4657 if (unsharp_image == (
Image *) NULL)
4658 return((
Image *) NULL);
4659 quantum_threshold=(MagickRealType) QuantumRange*threshold;
4665 GetMagickPixelPacket(image,&bias);
4666 image_view=AcquireVirtualCacheView(image,exception);
4667 unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4668 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4669 #pragma omp parallel for schedule(static) shared(progress,status) \
4670 magick_number_threads(image,unsharp_image,image->rows,1)
4672 for (y=0; y < (ssize_t) image->rows; y++)
4678 *magick_restrict indexes;
4684 *magick_restrict unsharp_indexes;
4692 if (status == MagickFalse)
4694 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4695 q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4702 indexes=GetCacheViewVirtualIndexQueue(image_view);
4703 unsharp_indexes=GetCacheViewAuthenticIndexQueue(unsharp_view);
4705 pixel.green=bias.green;
4706 pixel.blue=bias.blue;
4707 pixel.opacity=bias.opacity;
4708 pixel.index=bias.index;
4709 for (x=0; x < (ssize_t) image->columns; x++)
4711 if ((channel & RedChannel) != 0)
4713 pixel.red=(MagickRealType) GetPixelRed(p)-(MagickRealType)
4715 if (fabs(2.0*pixel.red) < quantum_threshold)
4716 pixel.red=(MagickRealType) GetPixelRed(p);
4718 pixel.red=(MagickRealType) GetPixelRed(p)+(pixel.red*gain);
4719 SetPixelRed(q,ClampToQuantum(pixel.red));
4721 if ((channel & GreenChannel) != 0)
4723 pixel.green=(MagickRealType) GetPixelGreen(p)-(MagickRealType)
4725 if (fabs(2.0*pixel.green) < quantum_threshold)
4726 pixel.green=(MagickRealType) GetPixelGreen(p);
4728 pixel.green=(MagickRealType) GetPixelGreen(p)+(pixel.green*gain);
4729 SetPixelGreen(q,ClampToQuantum(pixel.green));
4731 if ((channel & BlueChannel) != 0)
4733 pixel.blue=(MagickRealType) GetPixelBlue(p)-(MagickRealType) q->blue;
4734 if (fabs(2.0*pixel.blue) < quantum_threshold)
4735 pixel.blue=(MagickRealType) GetPixelBlue(p);
4737 pixel.blue=(MagickRealType) GetPixelBlue(p)+(pixel.blue*gain);
4738 SetPixelBlue(q,ClampToQuantum(pixel.blue));
4740 if ((channel & OpacityChannel) != 0)
4742 pixel.opacity=(MagickRealType) GetPixelOpacity(p)-(MagickRealType)
4744 if (fabs(2.0*pixel.opacity) < quantum_threshold)
4745 pixel.opacity=(MagickRealType) GetPixelOpacity(p);
4747 pixel.opacity=(MagickRealType) GetPixelOpacity(p)+
4748 (pixel.opacity*gain);
4749 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
4751 if (((channel & IndexChannel) != 0) &&
4752 (image->colorspace == CMYKColorspace))
4754 pixel.index=(MagickRealType) GetPixelIndex(indexes+x)-
4755 (MagickRealType) GetPixelIndex(unsharp_indexes+x);
4756 if (fabs(2.0*pixel.index) < quantum_threshold)
4757 pixel.index=(MagickRealType) GetPixelIndex(indexes+x);
4759 pixel.index=(MagickRealType) GetPixelIndex(indexes+x)+
4761 SetPixelIndex(unsharp_indexes+x,ClampToQuantum(pixel.index));
4766 if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4768 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4773 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4777 proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4778 if (proceed == MagickFalse)
4782 unsharp_image->type=image->type;
4783 unsharp_view=DestroyCacheView(unsharp_view);
4784 image_view=DestroyCacheView(image_view);
4785 if (status == MagickFalse)
4786 unsharp_image=DestroyImage(unsharp_image);
4787 return(unsharp_image);