43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/cache.h"
48 #include "magick/cache-view.h"
49 #include "magick/channel.h"
50 #include "magick/color.h"
51 #include "magick/color-private.h"
52 #include "magick/colorspace.h"
53 #include "magick/colorspace-private.h"
54 #include "magick/composite-private.h"
55 #include "magick/enhance.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/fx.h"
59 #include "magick/gem.h"
60 #include "magick/geometry.h"
61 #include "magick/histogram.h"
62 #include "magick/image.h"
63 #include "magick/image-private.h"
64 #include "magick/memory_.h"
65 #include "magick/monitor.h"
66 #include "magick/monitor-private.h"
67 #include "magick/opencl.h"
68 #include "magick/opencl-private.h"
69 #include "magick/option.h"
70 #include "magick/pixel-accessor.h"
71 #include "magick/pixel-private.h"
72 #include "magick/quantum.h"
73 #include "magick/quantum-private.h"
74 #include "magick/resample.h"
75 #include "magick/resample-private.h"
76 #include "magick/resource_.h"
77 #include "magick/statistic.h"
78 #include "magick/string_.h"
79 #include "magick/string-private.h"
80 #include "magick/thread-private.h"
81 #include "magick/threshold.h"
82 #include "magick/token.h"
83 #include "magick/xml-tree.h"
115 MagickExport MagickBooleanType AutoGammaImage(
Image *image)
117 return(AutoGammaImageChannel(image,DefaultChannels));
120 MagickExport MagickBooleanType AutoGammaImageChannel(
Image *image,
121 const ChannelType channel)
133 if ((channel & SyncChannels) != 0)
138 (void) GetImageChannelMean(image,channel,&mean,&sans,&image->exception);
139 gamma=log(mean*QuantumScale)/logmean;
140 return(LevelImageChannel(image,channel,0.0,(
double) QuantumRange,gamma));
146 if ((channel & RedChannel) != 0)
148 (void) GetImageChannelMean(image,RedChannel,&mean,&sans,
150 gamma=log(mean*QuantumScale)/logmean;
151 status&=LevelImageChannel(image,RedChannel,0.0,(
double) QuantumRange,
154 if ((channel & GreenChannel) != 0)
156 (void) GetImageChannelMean(image,GreenChannel,&mean,&sans,
158 gamma=log(mean*QuantumScale)/logmean;
159 status&=LevelImageChannel(image,GreenChannel,0.0,(
double) QuantumRange,
162 if ((channel & BlueChannel) != 0)
164 (void) GetImageChannelMean(image,BlueChannel,&mean,&sans,
166 gamma=log(mean*QuantumScale)/logmean;
167 status&=LevelImageChannel(image,BlueChannel,0.0,(
double) QuantumRange,
170 if (((channel & OpacityChannel) != 0) &&
171 (image->matte != MagickFalse))
173 (void) GetImageChannelMean(image,OpacityChannel,&mean,&sans,
175 gamma=log(mean*QuantumScale)/logmean;
176 status&=LevelImageChannel(image,OpacityChannel,0.0,(
double) QuantumRange,
179 if (((channel & IndexChannel) != 0) &&
180 (image->colorspace == CMYKColorspace))
182 (void) GetImageChannelMean(image,IndexChannel,&mean,&sans,
184 gamma=log(mean*QuantumScale)/logmean;
185 status&=LevelImageChannel(image,IndexChannel,0.0,(
double) QuantumRange,
188 return(status != 0 ? MagickTrue : MagickFalse);
221 MagickExport MagickBooleanType AutoLevelImage(
Image *image)
223 return(AutoLevelImageChannel(image,DefaultChannels));
226 MagickExport MagickBooleanType AutoLevelImageChannel(
Image *image,
227 const ChannelType channel)
232 return(MinMaxStretchImage(image,channel,0.0,0.0));
270 MagickExport MagickBooleanType BrightnessContrastImage(
Image *image,
271 const double brightness,
const double contrast)
276 status=BrightnessContrastImageChannel(image,DefaultChannels,brightness,
281 MagickExport MagickBooleanType BrightnessContrastImageChannel(
Image *image,
282 const ChannelType channel,
const double brightness,
const double contrast)
284 #define BrightnessContastImageTag "BrightnessContast/Image"
298 assert(image != (
Image *) NULL);
299 assert(image->signature == MagickCoreSignature);
300 if (IsEventLogging() != MagickFalse)
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
303 slope=tan((
double) (MagickPI*(alpha/100.0+1.0)/4.0));
306 intercept=brightness/100.0+((100-brightness)/200.0)*(1.0-slope);
307 coefficients[0]=slope;
308 coefficients[1]=intercept;
309 status=FunctionImageChannel(image,channel,PolynomialFunction,2,coefficients,
357 MagickExport MagickBooleanType ColorDecisionListImage(
Image *image,
358 const char *color_correction_collection)
360 #define ColorDecisionListCorrectImageTag "ColorDecisionList/Image"
362 typedef struct _Correction
370 typedef struct _ColorCorrection
385 token[MaxTextExtent];
421 assert(image != (
Image *) NULL);
422 assert(image->signature == MagickCoreSignature);
423 if (IsEventLogging() != MagickFalse)
424 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
425 if (color_correction_collection == (
const char *) NULL)
427 exception=(&image->exception);
428 ccc=NewXMLTree((
const char *) color_correction_collection,&image->exception);
431 cc=GetXMLTreeChild(ccc,
"ColorCorrection");
434 ccc=DestroyXMLTree(ccc);
437 color_correction.red.slope=1.0;
438 color_correction.red.offset=0.0;
439 color_correction.red.power=1.0;
440 color_correction.green.slope=1.0;
441 color_correction.green.offset=0.0;
442 color_correction.green.power=1.0;
443 color_correction.blue.slope=1.0;
444 color_correction.blue.offset=0.0;
445 color_correction.blue.power=1.0;
446 color_correction.saturation=0.0;
447 sop=GetXMLTreeChild(cc,
"SOPNode");
455 slope=GetXMLTreeChild(sop,
"Slope");
458 content=GetXMLTreeContent(slope);
459 p=(
const char *) content;
460 for (i=0; (*p !=
'\0') && (i < 3); i++)
462 (void) GetNextToken(p,&p,MaxTextExtent,token);
464 (void) GetNextToken(p,&p,MaxTextExtent,token);
469 color_correction.red.slope=StringToDouble(token,(
char **) NULL);
474 color_correction.green.slope=StringToDouble(token,
480 color_correction.blue.slope=StringToDouble(token,
487 offset=GetXMLTreeChild(sop,
"Offset");
490 content=GetXMLTreeContent(offset);
491 p=(
const char *) content;
492 for (i=0; (*p !=
'\0') && (i < 3); i++)
494 (void) GetNextToken(p,&p,MaxTextExtent,token);
496 (void) GetNextToken(p,&p,MaxTextExtent,token);
501 color_correction.red.offset=StringToDouble(token,
507 color_correction.green.offset=StringToDouble(token,
513 color_correction.blue.offset=StringToDouble(token,
520 power=GetXMLTreeChild(sop,
"Power");
523 content=GetXMLTreeContent(power);
524 p=(
const char *) content;
525 for (i=0; (*p !=
'\0') && (i < 3); i++)
527 (void) GetNextToken(p,&p,MaxTextExtent,token);
529 (void) GetNextToken(p,&p,MaxTextExtent,token);
534 color_correction.red.power=StringToDouble(token,(
char **) NULL);
539 color_correction.green.power=StringToDouble(token,
545 color_correction.blue.power=StringToDouble(token,
553 sat=GetXMLTreeChild(cc,
"SATNode");
559 saturation=GetXMLTreeChild(sat,
"Saturation");
562 content=GetXMLTreeContent(saturation);
563 p=(
const char *) content;
564 (void) GetNextToken(p,&p,MaxTextExtent,token);
565 color_correction.saturation=StringToDouble(token,(
char **) NULL);
568 ccc=DestroyXMLTree(ccc);
569 if (image->debug != MagickFalse)
571 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
572 " Color Correction Collection:");
573 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
574 " color_correction.red.slope: %g",color_correction.red.slope);
575 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
576 " color_correction.red.offset: %g",color_correction.red.offset);
577 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
578 " color_correction.red.power: %g",color_correction.red.power);
579 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
580 " color_correction.green.slope: %g",color_correction.green.slope);
581 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
582 " color_correction.green.offset: %g",color_correction.green.offset);
583 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
584 " color_correction.green.power: %g",color_correction.green.power);
585 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
586 " color_correction.blue.slope: %g",color_correction.blue.slope);
587 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
588 " color_correction.blue.offset: %g",color_correction.blue.offset);
589 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
590 " color_correction.blue.power: %g",color_correction.blue.power);
591 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
592 " color_correction.saturation: %g",color_correction.saturation);
594 cdl_map=(
PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*cdl_map));
596 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
598 for (i=0; i <= (ssize_t) MaxMap; i++)
600 cdl_map[i].red=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
601 MagickRealType) (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
602 color_correction.red.offset,color_correction.red.power)))));
603 cdl_map[i].green=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
604 MagickRealType) (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
605 color_correction.green.offset,color_correction.green.power)))));
606 cdl_map[i].blue=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
607 MagickRealType) (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
608 color_correction.blue.offset,color_correction.blue.power)))));
610 if (image->storage_class == PseudoClass)
615 for (i=0; i < (ssize_t) image->colors; i++)
620 luma=0.212656*image->colormap[i].red+0.715158*image->colormap[i].green+
621 0.072186*image->colormap[i].blue;
622 image->colormap[i].red=ClampToQuantum(luma+color_correction.saturation*
623 cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
624 image->colormap[i].green=ClampToQuantum(luma+
625 color_correction.saturation*cdl_map[ScaleQuantumToMap(
626 image->colormap[i].green)].green-luma);
627 image->colormap[i].blue=ClampToQuantum(luma+color_correction.saturation*
628 cdl_map[ScaleQuantumToMap(image->colormap[i].blue)].blue-luma);
636 image_view=AcquireAuthenticCacheView(image,exception);
637 #if defined(MAGICKCORE_OPENMP_SUPPORT)
638 #pragma omp parallel for schedule(static) shared(progress,status) \
639 magick_number_threads(image,image,image->rows,1)
641 for (y=0; y < (ssize_t) image->rows; y++)
652 if (status == MagickFalse)
654 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
660 for (x=0; x < (ssize_t) image->columns; x++)
662 luma=0.212656*GetPixelRed(q)+0.715158*GetPixelGreen(q)+
663 0.072186*GetPixelBlue(q);
664 SetPixelRed(q,ClampToQuantum(luma+color_correction.saturation*
665 (cdl_map[ScaleQuantumToMap(GetPixelRed(q))].red-luma)));
666 SetPixelGreen(q,ClampToQuantum(luma+color_correction.saturation*
667 (cdl_map[ScaleQuantumToMap(GetPixelGreen(q))].green-luma)));
668 SetPixelBlue(q,ClampToQuantum(luma+color_correction.saturation*
669 (cdl_map[ScaleQuantumToMap(GetPixelBlue(q))].blue-luma)));
672 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
674 if (image->progress_monitor != (MagickProgressMonitor) NULL)
679 #if defined(MAGICKCORE_OPENMP_SUPPORT)
683 proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
684 progress,image->rows);
685 if (proceed == MagickFalse)
689 image_view=DestroyCacheView(image_view);
690 cdl_map=(
PixelPacket *) RelinquishMagickMemory(cdl_map);
739 MagickExport MagickBooleanType ClutImage(
Image *image,
const Image *clut_image)
741 return(ClutImageChannel(image,DefaultChannels,clut_image));
744 MagickExport MagickBooleanType ClutImageChannel(
Image *image,
745 const ChannelType channel,
const Image *clut_image)
747 #define ClutImageTag "Clut/Image"
772 assert(image != (
Image *) NULL);
773 assert(image->signature == MagickCoreSignature);
774 assert(clut_image != (
Image *) NULL);
775 assert(clut_image->signature == MagickCoreSignature);
776 if (IsEventLogging() != MagickFalse)
777 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
778 exception=(&image->exception);
779 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
781 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
782 (IsGrayColorspace(clut_image->colorspace) == MagickFalse))
783 (void) SetImageColorspace(image,sRGBColorspace);
787 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
794 adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
795 clut_view=AcquireAuthenticCacheView(clut_image,exception);
796 for (i=0; i <= (ssize_t) MaxMap; i++)
798 GetMagickPixelPacket(clut_image,clut_map+i);
799 status=InterpolateMagickPixelPacket(clut_image,clut_view,
800 UndefinedInterpolatePixel,(
double) i*(clut_image->columns-adjust)/MaxMap,
801 (
double) i*(clut_image->rows-adjust)/MaxMap,clut_map+i,exception);
802 if (status == MagickFalse)
805 clut_view=DestroyCacheView(clut_view);
806 image_view=AcquireAuthenticCacheView(image,exception);
807 #if defined(MAGICKCORE_OPENMP_SUPPORT)
808 #pragma omp parallel for schedule(static) shared(progress,status) \
809 magick_number_threads(image,image,image->rows,1)
811 for (y=0; y < (ssize_t) image->rows; y++)
817 *magick_restrict indexes;
825 if (status == MagickFalse)
827 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
833 indexes=GetCacheViewAuthenticIndexQueue(image_view);
834 GetMagickPixelPacket(image,&pixel);
835 for (x=0; x < (ssize_t) image->columns; x++)
837 SetMagickPixelPacket(image,q,indexes+x,&pixel);
838 if ((channel & RedChannel) != 0)
839 SetPixelRed(q,ClampPixelRed(clut_map+
840 ScaleQuantumToMap(GetPixelRed(q))));
841 if ((channel & GreenChannel) != 0)
842 SetPixelGreen(q,ClampPixelGreen(clut_map+
843 ScaleQuantumToMap(GetPixelGreen(q))));
844 if ((channel & BlueChannel) != 0)
845 SetPixelBlue(q,ClampPixelBlue(clut_map+
846 ScaleQuantumToMap(GetPixelBlue(q))));
847 if ((channel & OpacityChannel) != 0)
849 if (clut_image->matte == MagickFalse)
850 SetPixelAlpha(q,MagickPixelIntensityToQuantum(clut_map+
851 ScaleQuantumToMap((Quantum) GetPixelAlpha(q))));
853 if (image->matte == MagickFalse)
854 SetPixelOpacity(q,ClampPixelOpacity(clut_map+
855 ScaleQuantumToMap((Quantum) MagickPixelIntensity(&pixel))));
857 SetPixelOpacity(q,ClampPixelOpacity(
858 clut_map+ScaleQuantumToMap(GetPixelOpacity(q))));
860 if (((channel & IndexChannel) != 0) &&
861 (image->colorspace == CMYKColorspace))
862 SetPixelIndex(indexes+x,ClampToQuantum((clut_map+(ssize_t)
863 GetPixelIndex(indexes+x))->index));
866 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
868 if (image->progress_monitor != (MagickProgressMonitor) NULL)
873 #if defined(MAGICKCORE_OPENMP_SUPPORT)
877 proceed=SetImageProgress(image,ClutImageTag,progress,image->rows);
878 if (proceed == MagickFalse)
882 image_view=DestroyCacheView(image_view);
884 if ((clut_image->matte != MagickFalse) && ((channel & OpacityChannel) != 0))
885 (
void) SetImageAlphaChannel(image,ActivateAlphaChannel);
917 static void Contrast(
const int sign,Quantum *red,Quantum *green,Quantum *blue)
927 assert(red != (Quantum *) NULL);
928 assert(green != (Quantum *) NULL);
929 assert(blue != (Quantum *) NULL);
933 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
934 brightness+=0.5*sign*(0.5*(sin((
double) (MagickPI*(brightness-0.5)))+1.0)-
936 if (brightness > 1.0)
939 if (brightness < 0.0)
941 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
944 MagickExport MagickBooleanType ContrastImage(
Image *image,
945 const MagickBooleanType sharpen)
947 #define ContrastImageTag "Contrast/Image"
969 assert(image != (
Image *) NULL);
970 assert(image->signature == MagickCoreSignature);
971 if (IsEventLogging() != MagickFalse)
972 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
973 sign=sharpen != MagickFalse ? 1 : -1;
974 if (image->storage_class == PseudoClass)
979 for (i=0; i < (ssize_t) image->colors; i++)
980 Contrast(sign,&image->colormap[i].red,&image->colormap[i].green,
981 &image->colormap[i].blue);
986 #if defined(MAGICKCORE_OPENCL_SUPPORT)
987 status=AccelerateContrastImage(image,sharpen,&image->exception);
988 if (status != MagickFalse)
993 exception=(&image->exception);
994 image_view=AcquireAuthenticCacheView(image,exception);
995 #if defined(MAGICKCORE_OPENMP_SUPPORT)
996 #pragma omp parallel for schedule(static) shared(progress,status) \
997 magick_number_threads(image,image,image->rows,1)
999 for (y=0; y < (ssize_t) image->rows; y++)
1012 if (status == MagickFalse)
1014 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1020 for (x=0; x < (ssize_t) image->columns; x++)
1023 green=GetPixelGreen(q);
1024 blue=GetPixelBlue(q);
1025 Contrast(sign,&red,&green,&blue);
1027 SetPixelGreen(q,green);
1028 SetPixelBlue(q,blue);
1031 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1033 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1038 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1042 proceed=SetImageProgress(image,ContrastImageTag,progress,image->rows);
1043 if (proceed == MagickFalse)
1047 image_view=DestroyCacheView(image_view);
1092 MagickExport MagickBooleanType ContrastStretchImage(
Image *image,
1097 white_point = (double) image->columns*image->rows;
1111 if (levels == (
char *) NULL)
1112 return(MagickFalse);
1113 flags=ParseGeometry(levels,&geometry_info);
1114 if ((flags & RhoValue) != 0)
1115 black_point=geometry_info.rho;
1116 if ((flags & SigmaValue) != 0)
1117 white_point=geometry_info.sigma;
1118 if ((flags & PercentValue) != 0)
1120 black_point*=(double) QuantumRange/100.0;
1121 white_point*=(double) QuantumRange/100.0;
1123 if ((flags & SigmaValue) == 0)
1124 white_point=(
double) image->columns*image->rows-black_point;
1125 status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
1130 MagickExport MagickBooleanType ContrastStretchImageChannel(
Image *image,
1131 const ChannelType channel,
const double black_point,
const double white_point)
1133 #define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
1134 #define ContrastStretchImageTag "ContrastStretch/Image"
1168 assert(image != (
Image *) NULL);
1169 assert(image->signature == MagickCoreSignature);
1170 if (IsEventLogging() != MagickFalse)
1171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1172 exception=(&image->exception);
1174 #if defined(MAGICKCORE_OPENCL_SUPPORT) && 0
1176 status=AccelerateContrastStretchImageChannel(image,channel,black_point,
1177 white_point,&image->exception);
1178 if (status != MagickFalse)
1182 sizeof(*histogram));
1184 sizeof(*stretch_map));
1192 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1198 if (SetImageGray(image,exception) != MagickFalse)
1199 (void) SetImageColorspace(image,GRAYColorspace);
1201 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1202 image_view=AcquireAuthenticCacheView(image,exception);
1203 for (y=0; y < (ssize_t) image->rows; y++)
1209 *magick_restrict indexes;
1214 if (status == MagickFalse)
1216 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1222 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1223 if ((channel & SyncChannels) != 0)
1224 for (x=0; x < (ssize_t) image->columns; x++)
1229 intensity=ClampToQuantum(GetPixelIntensity(image,p));
1230 histogram[ScaleQuantumToMap(intensity)].red++;
1231 histogram[ScaleQuantumToMap(intensity)].green++;
1232 histogram[ScaleQuantumToMap(intensity)].blue++;
1233 histogram[ScaleQuantumToMap(intensity)].index++;
1237 for (x=0; x < (ssize_t) image->columns; x++)
1239 if ((channel & RedChannel) != 0)
1240 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1241 if ((channel & GreenChannel) != 0)
1242 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1243 if ((channel & BlueChannel) != 0)
1244 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1245 if ((channel & OpacityChannel) != 0)
1246 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1247 if (((channel & IndexChannel) != 0) &&
1248 (image->colorspace == CMYKColorspace))
1249 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1257 white.red=MaxRange(QuantumRange);
1258 if ((channel & RedChannel) != 0)
1261 for (i=0; i <= (ssize_t) MaxMap; i++)
1263 intensity+=histogram[i].red;
1264 if (intensity > black_point)
1267 black.red=(MagickRealType) i;
1269 for (i=(ssize_t) MaxMap; i != 0; i--)
1271 intensity+=histogram[i].red;
1272 if (intensity > ((
double) image->columns*image->rows-white_point))
1275 white.red=(MagickRealType) i;
1278 white.green=MaxRange(QuantumRange);
1279 if ((channel & GreenChannel) != 0)
1282 for (i=0; i <= (ssize_t) MaxMap; i++)
1284 intensity+=histogram[i].green;
1285 if (intensity > black_point)
1288 black.green=(MagickRealType) i;
1290 for (i=(ssize_t) MaxMap; i != 0; i--)
1292 intensity+=histogram[i].green;
1293 if (intensity > ((
double) image->columns*image->rows-white_point))
1296 white.green=(MagickRealType) i;
1299 white.blue=MaxRange(QuantumRange);
1300 if ((channel & BlueChannel) != 0)
1303 for (i=0; i <= (ssize_t) MaxMap; i++)
1305 intensity+=histogram[i].blue;
1306 if (intensity > black_point)
1309 black.blue=(MagickRealType) i;
1311 for (i=(ssize_t) MaxMap; i != 0; i--)
1313 intensity+=histogram[i].blue;
1314 if (intensity > ((
double) image->columns*image->rows-white_point))
1317 white.blue=(MagickRealType) i;
1320 white.opacity=MaxRange(QuantumRange);
1321 if ((channel & OpacityChannel) != 0)
1324 for (i=0; i <= (ssize_t) MaxMap; i++)
1326 intensity+=histogram[i].opacity;
1327 if (intensity > black_point)
1330 black.opacity=(MagickRealType) i;
1332 for (i=(ssize_t) MaxMap; i != 0; i--)
1334 intensity+=histogram[i].opacity;
1335 if (intensity > ((
double) image->columns*image->rows-white_point))
1338 white.opacity=(MagickRealType) i;
1341 white.index=MaxRange(QuantumRange);
1342 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1345 for (i=0; i <= (ssize_t) MaxMap; i++)
1347 intensity+=histogram[i].index;
1348 if (intensity > black_point)
1351 black.index=(MagickRealType) i;
1353 for (i=(ssize_t) MaxMap; i != 0; i--)
1355 intensity+=histogram[i].index;
1356 if (intensity > ((
double) image->columns*image->rows-white_point))
1359 white.index=(MagickRealType) i;
1365 (void) memset(stretch_map,0,(MaxMap+1)*
sizeof(*stretch_map));
1366 for (i=0; i <= (ssize_t) MaxMap; i++)
1368 if ((channel & RedChannel) != 0)
1370 if (i < (ssize_t) black.red)
1371 stretch_map[i].red=(Quantum) 0;
1373 if (i > (ssize_t) white.red)
1374 stretch_map[i].red=QuantumRange;
1376 if (black.red != white.red)
1377 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
1378 (i-black.red)/(white.red-black.red)));
1380 if ((channel & GreenChannel) != 0)
1382 if (i < (ssize_t) black.green)
1383 stretch_map[i].green=0;
1385 if (i > (ssize_t) white.green)
1386 stretch_map[i].green=QuantumRange;
1388 if (black.green != white.green)
1389 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
1390 (i-black.green)/(white.green-black.green)));
1392 if ((channel & BlueChannel) != 0)
1394 if (i < (ssize_t) black.blue)
1395 stretch_map[i].blue=0;
1397 if (i > (ssize_t) white.blue)
1398 stretch_map[i].blue= QuantumRange;
1400 if (black.blue != white.blue)
1401 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
1402 (i-black.blue)/(white.blue-black.blue)));
1404 if ((channel & OpacityChannel) != 0)
1406 if (i < (ssize_t) black.opacity)
1407 stretch_map[i].opacity=0;
1409 if (i > (ssize_t) white.opacity)
1410 stretch_map[i].opacity=QuantumRange;
1412 if (black.opacity != white.opacity)
1413 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
1414 (i-black.opacity)/(white.opacity-black.opacity)));
1416 if (((channel & IndexChannel) != 0) &&
1417 (image->colorspace == CMYKColorspace))
1419 if (i < (ssize_t) black.index)
1420 stretch_map[i].index=0;
1422 if (i > (ssize_t) white.index)
1423 stretch_map[i].index=QuantumRange;
1425 if (black.index != white.index)
1426 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
1427 (i-black.index)/(white.index-black.index)));
1433 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
1434 (image->colorspace == CMYKColorspace)))
1435 image->storage_class=DirectClass;
1436 if (image->storage_class == PseudoClass)
1441 for (i=0; i < (ssize_t) image->colors; i++)
1443 if ((channel & RedChannel) != 0)
1445 if (black.red != white.red)
1446 image->colormap[i].red=stretch_map[
1447 ScaleQuantumToMap(image->colormap[i].red)].red;
1449 if ((channel & GreenChannel) != 0)
1451 if (black.green != white.green)
1452 image->colormap[i].green=stretch_map[
1453 ScaleQuantumToMap(image->colormap[i].green)].green;
1455 if ((channel & BlueChannel) != 0)
1457 if (black.blue != white.blue)
1458 image->colormap[i].blue=stretch_map[
1459 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1461 if ((channel & OpacityChannel) != 0)
1463 if (black.opacity != white.opacity)
1464 image->colormap[i].opacity=stretch_map[
1465 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1474 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1475 #pragma omp parallel for schedule(static) shared(progress,status) \
1476 magick_number_threads(image,image,image->rows,1)
1478 for (y=0; y < (ssize_t) image->rows; y++)
1481 *magick_restrict indexes;
1489 if (status == MagickFalse)
1491 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1497 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1498 for (x=0; x < (ssize_t) image->columns; x++)
1500 if ((channel & RedChannel) != 0)
1502 if (black.red != white.red)
1503 SetPixelRed(q,stretch_map[
1504 ScaleQuantumToMap(GetPixelRed(q))].red);
1506 if ((channel & GreenChannel) != 0)
1508 if (black.green != white.green)
1509 SetPixelGreen(q,stretch_map[
1510 ScaleQuantumToMap(GetPixelGreen(q))].green);
1512 if ((channel & BlueChannel) != 0)
1514 if (black.blue != white.blue)
1515 SetPixelBlue(q,stretch_map[
1516 ScaleQuantumToMap(GetPixelBlue(q))].blue);
1518 if ((channel & OpacityChannel) != 0)
1520 if (black.opacity != white.opacity)
1521 SetPixelOpacity(q,stretch_map[
1522 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
1524 if (((channel & IndexChannel) != 0) &&
1525 (image->colorspace == CMYKColorspace))
1527 if (black.index != white.index)
1528 SetPixelIndex(indexes+x,stretch_map[
1529 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
1533 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1535 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1540 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1544 proceed=SetImageProgress(image,ContrastStretchImageTag,progress,
1546 if (proceed == MagickFalse)
1550 image_view=DestroyCacheView(image_view);
1582 #define EnhancePixel(weight) \
1583 mean=QuantumScale*((double) GetPixelRed(r)+pixel.red)/2.0; \
1584 distance=QuantumScale*((double) GetPixelRed(r)-pixel.red); \
1585 distance_squared=(4.0+mean)*distance*distance; \
1586 mean=QuantumScale*((double) GetPixelGreen(r)+pixel.green)/2.0; \
1587 distance=QuantumScale*((double) GetPixelGreen(r)-pixel.green); \
1588 distance_squared+=(7.0-mean)*distance*distance; \
1589 mean=QuantumScale*((double) GetPixelBlue(r)+pixel.blue)/2.0; \
1590 distance=QuantumScale*((double) GetPixelBlue(r)-pixel.blue); \
1591 distance_squared+=(5.0-mean)*distance*distance; \
1592 mean=QuantumScale*((double) GetPixelOpacity(r)+pixel.opacity)/2.0; \
1593 distance=QuantumScale*((double) GetPixelOpacity(r)-pixel.opacity); \
1594 distance_squared+=(5.0-mean)*distance*distance; \
1595 if (distance_squared < 0.069) \
1597 aggregate.red+=(weight)*GetPixelRed(r); \
1598 aggregate.green+=(weight)*GetPixelGreen(r); \
1599 aggregate.blue+=(weight)*GetPixelBlue(r); \
1600 aggregate.opacity+=(weight)*GetPixelOpacity(r); \
1601 total_weight+=(weight); \
1604 #define EnhanceImageTag "Enhance/Image"
1628 assert(image != (
const Image *) NULL);
1629 assert(image->signature == MagickCoreSignature);
1630 if (IsEventLogging() != MagickFalse)
1631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1633 assert(exception->signature == MagickCoreSignature);
1634 if ((image->columns < 5) || (image->rows < 5))
1635 return((
Image *) NULL);
1636 enhance_image=CloneImage(image,0,0,MagickTrue,exception);
1637 if (enhance_image == (
Image *) NULL)
1638 return((
Image *) NULL);
1639 if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
1641 InheritException(exception,&enhance_image->exception);
1642 enhance_image=DestroyImage(enhance_image);
1643 return((
Image *) NULL);
1650 (void) memset(&zero,0,
sizeof(zero));
1651 image_view=AcquireAuthenticCacheView(image,exception);
1652 enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
1653 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1654 #pragma omp parallel for schedule(static) shared(progress,status) \
1655 magick_number_threads(image,enhance_image,image->rows,1)
1657 for (y=0; y < (ssize_t) image->rows; y++)
1671 if (status == MagickFalse)
1673 p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
1674 q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
1681 for (x=0; x < (ssize_t) image->columns; x++)
1703 r=p+2*(image->columns+4)+2;
1706 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1707 EnhancePixel(8.0); EnhancePixel(5.0);
1708 r=p+(image->columns+4);
1709 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1710 EnhancePixel(20.0); EnhancePixel(8.0);
1711 r=p+2*(image->columns+4);
1712 EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
1713 EnhancePixel(40.0); EnhancePixel(10.0);
1714 r=p+3*(image->columns+4);
1715 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1716 EnhancePixel(20.0); EnhancePixel(8.0);
1717 r=p+4*(image->columns+4);
1718 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1719 EnhancePixel(8.0); EnhancePixel(5.0);
1720 if (total_weight > MagickEpsilon)
1722 SetPixelRed(q,(aggregate.red+(total_weight/2)-1)/total_weight);
1723 SetPixelGreen(q,(aggregate.green+(total_weight/2)-1)/total_weight);
1724 SetPixelBlue(q,(aggregate.blue+(total_weight/2)-1)/total_weight);
1725 SetPixelOpacity(q,(aggregate.opacity+(total_weight/2)-1)/
1731 if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
1733 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1738 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1742 proceed=SetImageProgress(image,EnhanceImageTag,progress,image->rows);
1743 if (proceed == MagickFalse)
1747 enhance_view=DestroyCacheView(enhance_view);
1748 image_view=DestroyCacheView(image_view);
1749 if (status == MagickFalse)
1750 enhance_image=DestroyImage(enhance_image);
1751 return(enhance_image);
1781 MagickExport MagickBooleanType EqualizeImage(
Image *image)
1783 return(EqualizeImageChannel(image,DefaultChannels));
1786 MagickExport MagickBooleanType EqualizeImageChannel(
Image *image,
1787 const ChannelType channel)
1789 #define EqualizeImageTag "Equalize/Image"
1819 assert(image != (
Image *) NULL);
1820 assert(image->signature == MagickCoreSignature);
1821 if (IsEventLogging() != MagickFalse)
1822 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1823 exception=(&image->exception);
1825 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1827 status=AccelerateEqualizeImage(image,channel,&image->exception);
1828 if (status != MagickFalse)
1835 sizeof(*equalize_map));
1837 sizeof(*histogram));
1850 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1856 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1857 image_view=AcquireVirtualCacheView(image,exception);
1858 for (y=0; y < (ssize_t) image->rows; y++)
1861 *magick_restrict indexes;
1869 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1872 indexes=GetCacheViewVirtualIndexQueue(image_view);
1873 if ((channel & SyncChannels) != 0)
1874 for (x=0; x < (ssize_t) image->columns; x++)
1876 MagickRealType intensity=GetPixelIntensity(image,p);
1877 histogram[ScaleQuantumToMap(ClampToQuantum(intensity))].red++;
1881 for (x=0; x < (ssize_t) image->columns; x++)
1883 if ((channel & RedChannel) != 0)
1884 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1885 if ((channel & GreenChannel) != 0)
1886 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1887 if ((channel & BlueChannel) != 0)
1888 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1889 if ((channel & OpacityChannel) != 0)
1890 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1891 if (((channel & IndexChannel) != 0) &&
1892 (image->colorspace == CMYKColorspace))
1893 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1897 image_view=DestroyCacheView(image_view);
1901 (void) memset(&intensity,0,
sizeof(intensity));
1902 for (i=0; i <= (ssize_t) MaxMap; i++)
1904 if ((channel & SyncChannels) != 0)
1906 intensity.red+=histogram[i].red;
1910 if ((channel & RedChannel) != 0)
1911 intensity.red+=histogram[i].red;
1912 if ((channel & GreenChannel) != 0)
1913 intensity.green+=histogram[i].green;
1914 if ((channel & BlueChannel) != 0)
1915 intensity.blue+=histogram[i].blue;
1916 if ((channel & OpacityChannel) != 0)
1917 intensity.opacity+=histogram[i].opacity;
1918 if (((channel & IndexChannel) != 0) &&
1919 (image->colorspace == CMYKColorspace))
1920 intensity.index+=histogram[i].index;
1924 white=map[(int) MaxMap];
1925 (void) memset(equalize_map,0,(MaxMap+1)*
sizeof(*equalize_map));
1926 for (i=0; i <= (ssize_t) MaxMap; i++)
1928 if ((channel & SyncChannels) != 0)
1930 if (white.red != black.red)
1931 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1932 (map[i].red-black.red))/(white.red-black.red)));
1935 if (((channel & RedChannel) != 0) && (white.red != black.red))
1936 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1937 (map[i].red-black.red))/(white.red-black.red)));
1938 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1939 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1940 (map[i].green-black.green))/(white.green-black.green)));
1941 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1942 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1943 (map[i].blue-black.blue))/(white.blue-black.blue)));
1944 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
1945 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1946 (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
1947 if ((((channel & IndexChannel) != 0) &&
1948 (image->colorspace == CMYKColorspace)) &&
1949 (white.index != black.index))
1950 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1951 (map[i].index-black.index))/(white.index-black.index)));
1955 if (image->storage_class == PseudoClass)
1960 for (i=0; i < (ssize_t) image->colors; i++)
1962 if ((channel & SyncChannels) != 0)
1964 if (white.red != black.red)
1966 image->colormap[i].red=equalize_map[
1967 ScaleQuantumToMap(image->colormap[i].red)].red;
1968 image->colormap[i].green=equalize_map[
1969 ScaleQuantumToMap(image->colormap[i].green)].red;
1970 image->colormap[i].blue=equalize_map[
1971 ScaleQuantumToMap(image->colormap[i].blue)].red;
1972 image->colormap[i].opacity=equalize_map[
1973 ScaleQuantumToMap(image->colormap[i].opacity)].red;
1977 if (((channel & RedChannel) != 0) && (white.red != black.red))
1978 image->colormap[i].red=equalize_map[
1979 ScaleQuantumToMap(image->colormap[i].red)].red;
1980 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1981 image->colormap[i].green=equalize_map[
1982 ScaleQuantumToMap(image->colormap[i].green)].green;
1983 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1984 image->colormap[i].blue=equalize_map[
1985 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1986 if (((channel & OpacityChannel) != 0) &&
1987 (white.opacity != black.opacity))
1988 image->colormap[i].opacity=equalize_map[
1989 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1997 image_view=AcquireAuthenticCacheView(image,exception);
1998 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1999 #pragma omp parallel for schedule(static) shared(progress,status) \
2000 magick_number_threads(image,image,image->rows,1)
2002 for (y=0; y < (ssize_t) image->rows; y++)
2005 *magick_restrict indexes;
2013 if (status == MagickFalse)
2015 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2021 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2022 for (x=0; x < (ssize_t) image->columns; x++)
2024 if ((channel & SyncChannels) != 0)
2026 if (white.red != black.red)
2028 SetPixelRed(q,equalize_map[
2029 ScaleQuantumToMap(GetPixelRed(q))].red);
2030 SetPixelGreen(q,equalize_map[
2031 ScaleQuantumToMap(GetPixelGreen(q))].red);
2032 SetPixelBlue(q,equalize_map[
2033 ScaleQuantumToMap(GetPixelBlue(q))].red);
2034 SetPixelOpacity(q,equalize_map[
2035 ScaleQuantumToMap(GetPixelOpacity(q))].red);
2036 if (image->colorspace == CMYKColorspace)
2037 SetPixelIndex(indexes+x,equalize_map[
2038 ScaleQuantumToMap(GetPixelIndex(indexes+x))].red);
2043 if (((channel & RedChannel) != 0) && (white.red != black.red))
2044 SetPixelRed(q,equalize_map[
2045 ScaleQuantumToMap(GetPixelRed(q))].red);
2046 if (((channel & GreenChannel) != 0) && (white.green != black.green))
2047 SetPixelGreen(q,equalize_map[
2048 ScaleQuantumToMap(GetPixelGreen(q))].green);
2049 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
2050 SetPixelBlue(q,equalize_map[
2051 ScaleQuantumToMap(GetPixelBlue(q))].blue);
2052 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
2053 SetPixelOpacity(q,equalize_map[
2054 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
2055 if ((((channel & IndexChannel) != 0) &&
2056 (image->colorspace == CMYKColorspace)) &&
2057 (white.index != black.index))
2058 SetPixelIndex(indexes+x,equalize_map[
2059 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
2062 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2064 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2069 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2073 proceed=SetImageProgress(image,EqualizeImageTag,progress,image->rows);
2074 if (proceed == MagickFalse)
2078 image_view=DestroyCacheView(image_view);
2121 static inline double gamma_pow(
const double value,
const double gamma)
2123 return(value < 0.0 ? value : pow(value,gamma));
2126 MagickExport MagickBooleanType GammaImage(
Image *image,
const char *level)
2138 assert(image != (
Image *) NULL);
2139 assert(image->signature == MagickCoreSignature);
2140 if (IsEventLogging() != MagickFalse)
2141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2142 if (level == (
char *) NULL)
2143 return(MagickFalse);
2145 flags=ParseGeometry(level,&geometry_info);
2146 if ((flags & RhoValue) != 0)
2147 gamma.red=geometry_info.rho;
2148 gamma.green=gamma.red;
2149 if ((flags & SigmaValue) != 0)
2150 gamma.green=geometry_info.sigma;
2151 gamma.blue=gamma.red;
2152 if ((flags & XiValue) != 0)
2153 gamma.blue=geometry_info.xi;
2154 if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
2156 if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
2157 status=GammaImageChannel(image,(ChannelType) (RedChannel | GreenChannel |
2158 BlueChannel),(
double) gamma.red);
2161 status=GammaImageChannel(image,RedChannel,(
double) gamma.red);
2162 status&=GammaImageChannel(image,GreenChannel,(
double) gamma.green);
2163 status&=GammaImageChannel(image,BlueChannel,(
double) gamma.blue);
2165 return(status != 0 ? MagickTrue : MagickFalse);
2168 MagickExport MagickBooleanType GammaImageChannel(
Image *image,
2169 const ChannelType channel,
const double gamma)
2171 #define GammaImageTag "Gamma/Image"
2197 assert(image != (
Image *) NULL);
2198 assert(image->signature == MagickCoreSignature);
2199 if (IsEventLogging() != MagickFalse)
2200 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2201 exception=(&image->exception);
2204 gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*gamma_map));
2205 if (gamma_map == (Quantum *) NULL)
2206 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2208 (void) memset(gamma_map,0,(MaxMap+1)*
sizeof(*gamma_map));
2210 for (i=0; i <= (ssize_t) MaxMap; i++)
2211 gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
2212 MagickRealType) (MaxMap*pow((
double) i/MaxMap,
2213 PerceptibleReciprocal(gamma)))));
2214 if (image->storage_class == PseudoClass)
2219 for (i=0; i < (ssize_t) image->colors; i++)
2221 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2222 if ((channel & RedChannel) != 0)
2223 image->colormap[i].red=gamma_map[ScaleQuantumToMap(
2224 image->colormap[i].red)];
2225 if ((channel & GreenChannel) != 0)
2226 image->colormap[i].green=gamma_map[ScaleQuantumToMap(
2227 image->colormap[i].green)];
2228 if ((channel & BlueChannel) != 0)
2229 image->colormap[i].blue=gamma_map[ScaleQuantumToMap(
2230 image->colormap[i].blue)];
2231 if ((channel & OpacityChannel) != 0)
2233 if (image->matte == MagickFalse)
2234 image->colormap[i].opacity=gamma_map[ScaleQuantumToMap(
2235 image->colormap[i].opacity)];
2237 image->colormap[i].opacity=QuantumRange-gamma_map[
2238 ScaleQuantumToMap((Quantum) (QuantumRange-
2239 image->colormap[i].opacity))];
2242 if ((channel & RedChannel) != 0)
2243 image->colormap[i].red=QuantumRange*gamma_pow(QuantumScale*
2244 image->colormap[i].red,PerceptibleReciprocal(gamma));
2245 if ((channel & GreenChannel) != 0)
2246 image->colormap[i].green=QuantumRange*gamma_pow(QuantumScale*
2247 image->colormap[i].green,PerceptibleReciprocal(gamma));
2248 if ((channel & BlueChannel) != 0)
2249 image->colormap[i].blue=QuantumRange*gamma_pow(QuantumScale*
2250 image->colormap[i].blue,PerceptibleReciprocal(gamma));
2251 if ((channel & OpacityChannel) != 0)
2253 if (image->matte == MagickFalse)
2254 image->colormap[i].opacity=QuantumRange*gamma_pow(QuantumScale*
2255 image->colormap[i].opacity,PerceptibleReciprocal(gamma));
2257 image->colormap[i].opacity=QuantumRange-QuantumRange*gamma_pow(
2258 QuantumScale*(QuantumRange-image->colormap[i].opacity),1.0/
2269 image_view=AcquireAuthenticCacheView(image,exception);
2270 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2271 #pragma omp parallel for schedule(static) shared(progress,status) \
2272 magick_number_threads(image,image,image->rows,1)
2274 for (y=0; y < (ssize_t) image->rows; y++)
2277 *magick_restrict indexes;
2285 if (status == MagickFalse)
2287 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2293 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2294 for (x=0; x < (ssize_t) image->columns; x++)
2296 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2297 if ((channel & SyncChannels) != 0)
2299 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2300 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2301 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2305 if ((channel & RedChannel) != 0)
2306 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2307 if ((channel & GreenChannel) != 0)
2308 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2309 if ((channel & BlueChannel) != 0)
2310 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2311 if ((channel & OpacityChannel) != 0)
2313 if (image->matte == MagickFalse)
2314 SetPixelOpacity(q,gamma_map[ScaleQuantumToMap(
2315 GetPixelOpacity(q))]);
2317 SetPixelAlpha(q,gamma_map[ScaleQuantumToMap((Quantum)
2318 GetPixelAlpha(q))]);
2322 if ((channel & SyncChannels) != 0)
2324 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2325 PerceptibleReciprocal(gamma)));
2326 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*GetPixelGreen(q),
2327 PerceptibleReciprocal(gamma)));
2328 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2329 PerceptibleReciprocal(gamma)));
2333 if ((channel & RedChannel) != 0)
2334 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2335 PerceptibleReciprocal(gamma)));
2336 if ((channel & GreenChannel) != 0)
2337 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*
2338 GetPixelGreen(q),PerceptibleReciprocal(gamma)));
2339 if ((channel & BlueChannel) != 0)
2340 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2341 PerceptibleReciprocal(gamma)));
2342 if ((channel & OpacityChannel) != 0)
2344 if (image->matte == MagickFalse)
2345 SetPixelOpacity(q,QuantumRange*gamma_pow(QuantumScale*
2346 GetPixelOpacity(q),PerceptibleReciprocal(gamma)));
2348 SetPixelAlpha(q,QuantumRange*gamma_pow(QuantumScale*
2349 GetPixelAlpha(q),PerceptibleReciprocal(gamma)));
2355 if (((channel & IndexChannel) != 0) &&
2356 (image->colorspace == CMYKColorspace))
2357 for (x=0; x < (ssize_t) image->columns; x++)
2358 SetPixelIndex(indexes+x,gamma_map[ScaleQuantumToMap(
2359 GetPixelIndex(indexes+x))]);
2360 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2362 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2367 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2371 proceed=SetImageProgress(image,GammaImageTag,progress,image->rows);
2372 if (proceed == MagickFalse)
2376 image_view=DestroyCacheView(image_view);
2377 gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
2378 if (image->gamma != 0.0)
2379 image->gamma*=gamma;
2408 MagickExport MagickBooleanType GrayscaleImage(
Image *image,
2409 const PixelIntensityMethod method)
2411 #define GrayscaleImageTag "Grayscale/Image"
2428 assert(image != (
Image *) NULL);
2429 assert(image->signature == MagickCoreSignature);
2430 if (IsEventLogging() != MagickFalse)
2431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2432 if (image->storage_class == PseudoClass)
2434 if (SyncImage(image) == MagickFalse)
2435 return(MagickFalse);
2436 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2437 return(MagickFalse);
2445 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2446 if (AccelerateGrayscaleImage(image,method,&image->exception) != MagickFalse)
2448 image->intensity=method;
2449 image->type=GrayscaleType;
2450 if ((method == Rec601LuminancePixelIntensityMethod) ||
2451 (method == Rec709LuminancePixelIntensityMethod))
2452 return(SetImageColorspace(image,LinearGRAYColorspace));
2453 return(SetImageColorspace(image,GRAYColorspace));
2458 exception=(&image->exception);
2459 image_view=AcquireAuthenticCacheView(image,exception);
2460 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2461 #pragma omp parallel for schedule(static) shared(progress,status) \
2462 magick_number_threads(image,image,image->rows,1)
2464 for (y=0; y < (ssize_t) image->rows; y++)
2472 if (status == MagickFalse)
2474 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2480 for (x=0; x < (ssize_t) image->columns; x++)
2488 red=(MagickRealType) q->red;
2489 green=(MagickRealType) q->green;
2490 blue=(MagickRealType) q->blue;
2494 case AveragePixelIntensityMethod:
2496 intensity=(red+green+blue)/3.0;
2499 case BrightnessPixelIntensityMethod:
2501 intensity=MagickMax(MagickMax(red,green),blue);
2504 case LightnessPixelIntensityMethod:
2506 intensity=(MagickMin(MagickMin(red,green),blue)+
2507 MagickMax(MagickMax(red,green),blue))/2.0;
2510 case MSPixelIntensityMethod:
2512 intensity=(MagickRealType) (((
double) red*red+green*green+
2513 blue*blue)/(3.0*QuantumRange));
2516 case Rec601LumaPixelIntensityMethod:
2518 if (image->colorspace == RGBColorspace)
2520 red=EncodePixelGamma(red);
2521 green=EncodePixelGamma(green);
2522 blue=EncodePixelGamma(blue);
2524 intensity=0.298839*red+0.586811*green+0.114350*blue;
2527 case Rec601LuminancePixelIntensityMethod:
2529 if (image->colorspace == sRGBColorspace)
2531 red=DecodePixelGamma(red);
2532 green=DecodePixelGamma(green);
2533 blue=DecodePixelGamma(blue);
2535 intensity=0.298839*red+0.586811*green+0.114350*blue;
2538 case Rec709LumaPixelIntensityMethod:
2541 if (image->colorspace == RGBColorspace)
2543 red=EncodePixelGamma(red);
2544 green=EncodePixelGamma(green);
2545 blue=EncodePixelGamma(blue);
2547 intensity=0.212656*red+0.715158*green+0.072186*blue;
2550 case Rec709LuminancePixelIntensityMethod:
2552 if (image->colorspace == sRGBColorspace)
2554 red=DecodePixelGamma(red);
2555 green=DecodePixelGamma(green);
2556 blue=DecodePixelGamma(blue);
2558 intensity=0.212656*red+0.715158*green+0.072186*blue;
2561 case RMSPixelIntensityMethod:
2563 intensity=(MagickRealType) (sqrt((
double) red*red+green*green+
2564 blue*blue)/sqrt(3.0));
2568 SetPixelGray(q,ClampToQuantum(intensity));
2571 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2573 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2578 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2582 proceed=SetImageProgress(image,GrayscaleImageTag,progress,image->rows);
2583 if (proceed == MagickFalse)
2587 image_view=DestroyCacheView(image_view);
2588 image->intensity=method;
2589 image->type=GrayscaleType;
2590 if ((method == Rec601LuminancePixelIntensityMethod) ||
2591 (method == Rec709LuminancePixelIntensityMethod))
2592 return(SetImageColorspace(image,LinearGRAYColorspace));
2593 return(SetImageColorspace(image,GRAYColorspace));
2629 MagickExport MagickBooleanType HaldClutImage(
Image *image,
2630 const Image *hald_image)
2632 return(HaldClutImageChannel(image,DefaultChannels,hald_image));
2635 MagickExport MagickBooleanType HaldClutImageChannel(
Image *image,
2636 const ChannelType channel,
const Image *hald_image)
2638 #define HaldClutImageTag "Clut/Image"
2640 typedef struct _HaldInfo
2675 assert(image != (
Image *) NULL);
2676 assert(image->signature == MagickCoreSignature);
2677 if (IsEventLogging() != MagickFalse)
2678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2679 assert(hald_image != (
Image *) NULL);
2680 assert(hald_image->signature == MagickCoreSignature);
2681 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2682 return(MagickFalse);
2683 if (IsGrayColorspace(image->colorspace) != MagickFalse)
2684 (void) SetImageColorspace(image,sRGBColorspace);
2685 if (image->matte == MagickFalse)
2686 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
2692 length=(size_t) MagickMin((MagickRealType) hald_image->columns,
2693 (MagickRealType) hald_image->rows);
2694 for (level=2; (level*level*level) < length; level++) ;
2696 cube_size=level*level;
2697 width=(double) hald_image->columns;
2698 GetMagickPixelPacket(hald_image,&zero);
2699 exception=(&image->exception);
2700 image_view=AcquireAuthenticCacheView(image,exception);
2701 hald_view=AcquireAuthenticCacheView(hald_image,exception);
2702 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2703 #pragma omp parallel for schedule(static) shared(progress,status) \
2704 magick_number_threads(image,hald_image,image->rows,1)
2706 for (y=0; y < (ssize_t) image->rows; y++)
2723 *magick_restrict indexes;
2731 if (status == MagickFalse)
2733 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2739 indexes=GetCacheViewAuthenticIndexQueue(hald_view);
2745 for (x=0; x < (ssize_t) image->columns; x++)
2747 point.x=QuantumScale*(level-1.0)*GetPixelRed(q);
2748 point.y=QuantumScale*(level-1.0)*GetPixelGreen(q);
2749 point.z=QuantumScale*(level-1.0)*GetPixelBlue(q);
2750 offset=(double) (point.x+level*floor(point.y)+cube_size*floor(point.z));
2751 point.x-=floor(point.x);
2752 point.y-=floor(point.y);
2753 point.z-=floor(point.z);
2754 status=InterpolateMagickPixelPacket(image,hald_view,
2755 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2757 if (status == MagickFalse)
2759 status=InterpolateMagickPixelPacket(image,hald_view,
2760 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2761 width),&pixel2,exception);
2762 if (status == MagickFalse)
2765 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2766 area=(point.y < 0.5) ? 0.0 : 1.0;
2767 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2768 pixel2.opacity,area,&pixel3);
2770 status=InterpolateMagickPixelPacket(image,hald_view,
2771 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2773 if (status == MagickFalse)
2775 status=InterpolateMagickPixelPacket(image,hald_view,
2776 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2777 width),&pixel2,exception);
2778 if (status == MagickFalse)
2780 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2781 pixel2.opacity,area,&pixel4);
2783 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2784 area=(point.z < 0.5)? 0.0 : 1.0;
2785 MagickPixelCompositeAreaBlend(&pixel3,pixel3.opacity,&pixel4,
2786 pixel4.opacity,area,&pixel);
2787 if ((channel & RedChannel) != 0)
2788 SetPixelRed(q,ClampToQuantum(pixel.red));
2789 if ((channel & GreenChannel) != 0)
2790 SetPixelGreen(q,ClampToQuantum(pixel.green));
2791 if ((channel & BlueChannel) != 0)
2792 SetPixelBlue(q,ClampToQuantum(pixel.blue));
2793 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2794 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
2795 if (((channel & IndexChannel) != 0) &&
2796 (image->colorspace == CMYKColorspace))
2797 SetPixelIndex(indexes+x,ClampToQuantum(pixel.index));
2800 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2802 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2807 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2811 proceed=SetImageProgress(image,HaldClutImageTag,progress,image->rows);
2812 if (proceed == MagickFalse)
2816 hald_view=DestroyCacheView(hald_view);
2817 image_view=DestroyCacheView(image_view);
2862 MagickExport MagickBooleanType LevelImage(
Image *image,
const char *levels)
2867 white_point = (double) QuantumRange;
2881 if (levels == (
char *) NULL)
2882 return(MagickFalse);
2883 flags=ParseGeometry(levels,&geometry_info);
2884 if ((flags & RhoValue) != 0)
2885 black_point=geometry_info.rho;
2886 if ((flags & SigmaValue) != 0)
2887 white_point=geometry_info.sigma;
2888 if ((flags & XiValue) != 0)
2889 gamma=geometry_info.xi;
2890 if ((flags & PercentValue) != 0)
2892 black_point*=(double) image->columns*image->rows/100.0;
2893 white_point*=(
double) image->columns*image->rows/100.0;
2895 if ((flags & SigmaValue) == 0)
2896 white_point=(
double) QuantumRange-black_point;
2897 if ((flags & AspectValue ) == 0)
2898 status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
2901 status=LevelizeImage(image,black_point,white_point,gamma);
2948 static inline double LevelPixel(
const double black_point,
2949 const double white_point,
const double gamma,
const MagickRealType pixel)
2955 scale=PerceptibleReciprocal(white_point-black_point);
2956 level_pixel=QuantumRange*gamma_pow(scale*((
double) pixel-black_point),
2957 PerceptibleReciprocal(gamma));
2958 return(level_pixel);
2961 MagickExport MagickBooleanType LevelImageChannel(
Image *image,
2962 const ChannelType channel,
const double black_point,
const double white_point,
2965 #define LevelImageTag "Level/Image"
2988 assert(image != (
Image *) NULL);
2989 assert(image->signature == MagickCoreSignature);
2990 if (IsEventLogging() != MagickFalse)
2991 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2992 if (image->storage_class == PseudoClass)
2993 for (i=0; i < (ssize_t) image->colors; i++)
2998 if ((channel & RedChannel) != 0)
2999 image->colormap[i].red=(Quantum) ClampToQuantum(LevelPixel(black_point,
3000 white_point,gamma,(MagickRealType) image->colormap[i].red));
3001 if ((channel & GreenChannel) != 0)
3002 image->colormap[i].green=(Quantum) ClampToQuantum(LevelPixel(
3003 black_point,white_point,gamma,(MagickRealType)
3004 image->colormap[i].green));
3005 if ((channel & BlueChannel) != 0)
3006 image->colormap[i].blue=(Quantum) ClampToQuantum(LevelPixel(black_point,
3007 white_point,gamma,(MagickRealType) image->colormap[i].blue));
3008 if ((channel & OpacityChannel) != 0)
3009 image->colormap[i].opacity=(Quantum) (QuantumRange-(Quantum)
3010 ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3011 (MagickRealType) (QuantumRange-image->colormap[i].opacity))));
3018 exception=(&image->exception);
3019 image_view=AcquireAuthenticCacheView(image,exception);
3020 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3021 #pragma omp parallel for schedule(static) shared(progress,status) \
3022 magick_number_threads(image,image,image->rows,1)
3024 for (y=0; y < (ssize_t) image->rows; y++)
3027 *magick_restrict indexes;
3035 if (status == MagickFalse)
3037 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3043 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3044 for (x=0; x < (ssize_t) image->columns; x++)
3046 if ((channel & RedChannel) != 0)
3047 SetPixelRed(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3048 (MagickRealType) GetPixelRed(q))));
3049 if ((channel & GreenChannel) != 0)
3050 SetPixelGreen(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3051 (MagickRealType) GetPixelGreen(q))));
3052 if ((channel & BlueChannel) != 0)
3053 SetPixelBlue(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3054 (MagickRealType) GetPixelBlue(q))));
3055 if (((channel & OpacityChannel) != 0) &&
3056 (image->matte != MagickFalse))
3057 SetPixelAlpha(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3058 (MagickRealType) GetPixelAlpha(q))));
3059 if (((channel & IndexChannel) != 0) &&
3060 (image->colorspace == CMYKColorspace))
3061 SetPixelIndex(indexes+x,ClampToQuantum(LevelPixel(black_point,
3062 white_point,gamma,(MagickRealType) GetPixelIndex(indexes+x))));
3065 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3067 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3072 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3076 proceed=SetImageProgress(image,LevelImageTag,progress,image->rows);
3077 if (proceed == MagickFalse)
3081 image_view=DestroyCacheView(image_view);
3082 (void) ClampImage(image);
3129 MagickExport MagickBooleanType LevelizeImage(
Image *image,
3130 const double black_point,
const double white_point,
const double gamma)
3135 status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
3140 MagickExport MagickBooleanType LevelizeImageChannel(
Image *image,
3141 const ChannelType channel,
const double black_point,
const double white_point,
3144 #define LevelizeImageTag "Levelize/Image"
3145 #define LevelizeValue(x) ClampToQuantum(((MagickRealType) gamma_pow((double) \
3146 (QuantumScale*(x)),gamma))*(white_point-black_point)+black_point)
3169 assert(image != (
Image *) NULL);
3170 assert(image->signature == MagickCoreSignature);
3171 if (IsEventLogging() != MagickFalse)
3172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3173 if (image->storage_class == PseudoClass)
3174 for (i=0; i < (ssize_t) image->colors; i++)
3179 if ((channel & RedChannel) != 0)
3180 image->colormap[i].red=LevelizeValue(image->colormap[i].red);
3181 if ((channel & GreenChannel) != 0)
3182 image->colormap[i].green=LevelizeValue(image->colormap[i].green);
3183 if ((channel & BlueChannel) != 0)
3184 image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
3185 if ((channel & OpacityChannel) != 0)
3186 image->colormap[i].opacity=(Quantum) (QuantumRange-LevelizeValue(
3187 QuantumRange-image->colormap[i].opacity));
3194 exception=(&image->exception);
3195 image_view=AcquireAuthenticCacheView(image,exception);
3196 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3197 #pragma omp parallel for schedule(static) shared(progress,status) \
3198 magick_number_threads(image,image,image->rows,1)
3200 for (y=0; y < (ssize_t) image->rows; y++)
3203 *magick_restrict indexes;
3211 if (status == MagickFalse)
3213 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3219 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3220 for (x=0; x < (ssize_t) image->columns; x++)
3222 if ((channel & RedChannel) != 0)
3223 SetPixelRed(q,LevelizeValue(GetPixelRed(q)));
3224 if ((channel & GreenChannel) != 0)
3225 SetPixelGreen(q,LevelizeValue(GetPixelGreen(q)));
3226 if ((channel & BlueChannel) != 0)
3227 SetPixelBlue(q,LevelizeValue(GetPixelBlue(q)));
3228 if (((channel & OpacityChannel) != 0) &&
3229 (image->matte != MagickFalse))
3230 SetPixelAlpha(q,LevelizeValue(GetPixelAlpha(q)));
3231 if (((channel & IndexChannel) != 0) &&
3232 (image->colorspace == CMYKColorspace))
3233 SetPixelIndex(indexes+x,LevelizeValue(GetPixelIndex(indexes+x)));
3236 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3238 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3243 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3247 proceed=SetImageProgress(image,LevelizeImageTag,progress,image->rows);
3248 if (proceed == MagickFalse)
3252 image_view=DestroyCacheView(image_view);
3301 MagickExport MagickBooleanType LevelColorsImage(
Image *image,
3303 const MagickBooleanType invert)
3308 status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
3313 MagickExport MagickBooleanType LevelColorsImageChannel(
Image *image,
3323 assert(image != (
Image *) NULL);
3324 assert(image->signature == MagickCoreSignature);
3325 if (IsEventLogging() != MagickFalse)
3326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3327 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3328 ((IsGrayColorspace(black_color->colorspace) != MagickFalse) ||
3329 (IsGrayColorspace(white_color->colorspace) != MagickFalse)))
3330 (
void) SetImageColorspace(image,sRGBColorspace);
3332 if (invert == MagickFalse)
3334 if ((channel & RedChannel) != 0)
3335 status&=LevelImageChannel(image,RedChannel,black_color->red,
3336 white_color->red,(
double) 1.0);
3337 if ((channel & GreenChannel) != 0)
3338 status&=LevelImageChannel(image,GreenChannel,black_color->green,
3339 white_color->green,(
double) 1.0);
3340 if ((channel & BlueChannel) != 0)
3341 status&=LevelImageChannel(image,BlueChannel,black_color->blue,
3342 white_color->blue,(
double) 1.0);
3343 if (((channel & OpacityChannel) != 0) &&
3344 (image->matte != MagickFalse))
3345 status&=LevelImageChannel(image,OpacityChannel,black_color->opacity,
3346 white_color->opacity,(
double) 1.0);
3347 if (((channel & IndexChannel) != 0) &&
3348 (image->colorspace == CMYKColorspace))
3349 status&=LevelImageChannel(image,IndexChannel,black_color->index,
3350 white_color->index,(
double) 1.0);
3354 if ((channel & RedChannel) != 0)
3355 status&=LevelizeImageChannel(image,RedChannel,black_color->red,
3356 white_color->red,(
double) 1.0);
3357 if ((channel & GreenChannel) != 0)
3358 status&=LevelizeImageChannel(image,GreenChannel,black_color->green,
3359 white_color->green,(
double) 1.0);
3360 if ((channel & BlueChannel) != 0)
3361 status&=LevelizeImageChannel(image,BlueChannel,black_color->blue,
3362 white_color->blue,(
double) 1.0);
3363 if (((channel & OpacityChannel) != 0) &&
3364 (image->matte != MagickFalse))
3365 status&=LevelizeImageChannel(image,OpacityChannel,black_color->opacity,
3366 white_color->opacity,(
double) 1.0);
3367 if (((channel & IndexChannel) != 0) &&
3368 (image->colorspace == CMYKColorspace))
3369 status&=LevelizeImageChannel(image,IndexChannel,black_color->index,
3370 white_color->index,(
double) 1.0);
3372 return(status == 0 ? MagickFalse : MagickTrue);
3403 MagickExport MagickBooleanType LinearStretchImage(
Image *image,
3404 const double black_point,
const double white_point)
3406 #define LinearStretchImageTag "LinearStretch/Image"
3426 assert(image != (
Image *) NULL);
3427 assert(image->signature == MagickCoreSignature);
3428 exception=(&image->exception);
3429 histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
3430 sizeof(*histogram));
3431 if (histogram == (MagickRealType *) NULL)
3432 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
3437 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
3438 for (y=0; y < (ssize_t) image->rows; y++)
3446 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3449 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3451 histogram[ScaleQuantumToMap(ClampToQuantum(GetPixelIntensity(image,p)))]++;
3459 for (black=0; black < (ssize_t) MaxMap; black++)
3461 intensity+=histogram[black];
3462 if (intensity >= black_point)
3466 for (white=(ssize_t) MaxMap; white != 0; white--)
3468 intensity+=histogram[white];
3469 if (intensity >= white_point)
3472 histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
3473 status=LevelImageChannel(image,DefaultChannels,(
double)
3474 ScaleMapToQuantum(black),(
double) ScaleMapToQuantum(white),1.0);
3508 static inline void ModulateHCL(
const double percent_hue,
3509 const double percent_chroma,
const double percent_luma,Quantum *red,
3510 Quantum *green,Quantum *blue)
3520 ConvertRGBToHCL(*red,*green,*blue,&hue,&chroma,&luma);
3521 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3522 chroma*=0.01*percent_chroma;
3523 luma*=0.01*percent_luma;
3524 ConvertHCLToRGB(hue,chroma,luma,red,green,blue);
3527 static inline void ModulateHCLp(
const double percent_hue,
3528 const double percent_chroma,
const double percent_luma,Quantum *red,
3529 Quantum *green,Quantum *blue)
3539 ConvertRGBToHCLp(*red,*green,*blue,&hue,&chroma,&luma);
3540 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3541 chroma*=0.01*percent_chroma;
3542 luma*=0.01*percent_luma;
3543 ConvertHCLpToRGB(hue,chroma,luma,red,green,blue);
3546 static inline void ModulateHSB(
const double percent_hue,
3547 const double percent_saturation,
const double percent_brightness,Quantum *red,
3548 Quantum *green,Quantum *blue)
3558 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
3559 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3560 saturation*=0.01*percent_saturation;
3561 brightness*=0.01*percent_brightness;
3562 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
3565 static inline void ModulateHSI(
const double percent_hue,
3566 const double percent_saturation,
const double percent_intensity,Quantum *red,
3567 Quantum *green,Quantum *blue)
3577 ConvertRGBToHSI(*red,*green,*blue,&hue,&saturation,&intensity);
3578 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3579 saturation*=0.01*percent_saturation;
3580 intensity*=0.01*percent_intensity;
3581 ConvertHSIToRGB(hue,saturation,intensity,red,green,blue);
3584 static inline void ModulateHSL(
const double percent_hue,
3585 const double percent_saturation,
const double percent_lightness,Quantum *red,
3586 Quantum *green,Quantum *blue)
3596 ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
3597 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3598 saturation*=0.01*percent_saturation;
3599 lightness*=0.01*percent_lightness;
3600 ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
3603 static inline void ModulateHSV(
const double percent_hue,
3604 const double percent_saturation,
const double percent_value,Quantum *red,
3605 Quantum *green,Quantum *blue)
3615 ConvertRGBToHSV(*red,*green,*blue,&hue,&saturation,&value);
3616 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3617 saturation*=0.01*percent_saturation;
3618 value*=0.01*percent_value;
3619 ConvertHSVToRGB(hue,saturation,value,red,green,blue);
3622 static inline void ModulateHWB(
const double percent_hue,
3623 const double percent_whiteness,
const double percent_blackness,Quantum *red,
3624 Quantum *green,Quantum *blue)
3634 ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
3635 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3636 blackness*=0.01*percent_blackness;
3637 whiteness*=0.01*percent_whiteness;
3638 ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
3641 static inline void ModulateLCHab(
const double percent_luma,
3642 const double percent_chroma,
const double percent_hue,Quantum *red,
3643 Quantum *green,Quantum *blue)
3653 ConvertRGBToLCHab(*red,*green,*blue,&luma,&chroma,&hue);
3654 luma*=0.01*percent_luma;
3655 chroma*=0.01*percent_chroma;
3656 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3657 ConvertLCHabToRGB(luma,chroma,hue,red,green,blue);
3660 static inline void ModulateLCHuv(
const double percent_luma,
3661 const double percent_chroma,
const double percent_hue,Quantum *red,
3662 Quantum *green,Quantum *blue)
3672 ConvertRGBToLCHuv(*red,*green,*blue,&luma,&chroma,&hue);
3673 luma*=0.01*percent_luma;
3674 chroma*=0.01*percent_chroma;
3675 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3676 ConvertLCHuvToRGB(luma,chroma,hue,red,green,blue);
3679 MagickExport MagickBooleanType ModulateImage(
Image *image,
const char *modulate)
3681 #define ModulateImageTag "Modulate/Image"
3693 percent_brightness = 100.0,
3694 percent_hue = 100.0,
3695 percent_saturation = 100.0;
3721 assert(image != (
Image *) NULL);
3722 assert(image->signature == MagickCoreSignature);
3723 if (IsEventLogging() != MagickFalse)
3724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3725 if (modulate == (
char *) NULL)
3726 return(MagickFalse);
3727 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3728 (
void) SetImageColorspace(image,sRGBColorspace);
3729 flags=ParseGeometry(modulate,&geometry_info);
3730 if ((flags & RhoValue) != 0)
3731 percent_brightness=geometry_info.rho;
3732 if ((flags & SigmaValue) != 0)
3733 percent_saturation=geometry_info.sigma;
3734 if ((flags & XiValue) != 0)
3735 percent_hue=geometry_info.xi;
3736 colorspace=UndefinedColorspace;
3737 artifact=GetImageArtifact(image,
"modulate:colorspace");
3738 if (artifact != (
const char *) NULL)
3739 colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
3740 MagickFalse,artifact);
3741 if (image->storage_class == PseudoClass)
3742 for (i=0; i < (ssize_t) image->colors; i++)
3752 red=image->colormap[i].red;
3753 green=image->colormap[i].green;
3754 blue=image->colormap[i].blue;
3759 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3763 case HCLpColorspace:
3765 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3771 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3777 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3784 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3790 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3796 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3800 case LCHabColorspace:
3803 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3807 case LCHuvColorspace:
3809 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3814 image->colormap[i].red=red;
3815 image->colormap[i].green=green;
3816 image->colormap[i].blue=blue;
3824 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3825 status=AccelerateModulateImage(image,percent_brightness,percent_hue,
3826 percent_saturation,colorspace,&image->exception);
3827 if (status != MagickFalse)
3832 exception=(&image->exception);
3833 image_view=AcquireAuthenticCacheView(image,exception);
3834 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3835 #pragma omp parallel for schedule(static) shared(progress,status) \
3836 magick_number_threads(image,image,image->rows,1)
3838 for (y=0; y < (ssize_t) image->rows; y++)
3846 if (status == MagickFalse)
3848 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3854 for (x=0; x < (ssize_t) image->columns; x++)
3862 green=GetPixelGreen(q);
3863 blue=GetPixelBlue(q);
3868 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3872 case HCLpColorspace:
3874 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3880 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3886 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3893 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3899 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3905 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3909 case LCHabColorspace:
3911 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3916 case LCHuvColorspace:
3918 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3924 SetPixelGreen(q,green);
3925 SetPixelBlue(q,blue);
3928 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3930 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3935 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3939 proceed=SetImageProgress(image,ModulateImageTag,progress,image->rows);
3940 if (proceed == MagickFalse)
3944 image_view=DestroyCacheView(image_view);
3979 MagickExport MagickBooleanType NegateImage(
Image *image,
3980 const MagickBooleanType grayscale)
3985 status=NegateImageChannel(image,DefaultChannels,grayscale);
3989 MagickExport MagickBooleanType NegateImageChannel(
Image *image,
3990 const ChannelType channel,
const MagickBooleanType grayscale)
3992 #define NegateImageTag "Negate/Image"
4012 assert(image != (
Image *) NULL);
4013 assert(image->signature == MagickCoreSignature);
4014 if (IsEventLogging() != MagickFalse)
4015 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4016 if (image->storage_class == PseudoClass)
4021 for (i=0; i < (ssize_t) image->colors; i++)
4023 if (grayscale != MagickFalse)
4024 if ((image->colormap[i].red != image->colormap[i].green) ||
4025 (image->colormap[i].green != image->colormap[i].blue))
4027 if ((channel & RedChannel) != 0)
4028 image->colormap[i].red=QuantumRange-image->colormap[i].red;
4029 if ((channel & GreenChannel) != 0)
4030 image->colormap[i].green=QuantumRange-image->colormap[i].green;
4031 if ((channel & BlueChannel) != 0)
4032 image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
4040 exception=(&image->exception);
4041 image_view=AcquireAuthenticCacheView(image,exception);
4042 if (grayscale != MagickFalse)
4044 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4045 #pragma omp parallel for schedule(static) shared(progress,status) \
4046 magick_number_threads(image,image,image->rows,1)
4048 for (y=0; y < (ssize_t) image->rows; y++)
4054 *magick_restrict indexes;
4062 if (status == MagickFalse)
4064 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4071 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4072 for (x=0; x < (ssize_t) image->columns; x++)
4074 if ((GetPixelRed(q) != GetPixelGreen(q)) ||
4075 (GetPixelGreen(q) != GetPixelBlue(q)))
4080 if ((channel & RedChannel) != 0)
4081 SetPixelRed(q,QuantumRange-GetPixelRed(q));
4082 if ((channel & GreenChannel) != 0)
4083 SetPixelGreen(q,QuantumRange-GetPixelGreen(q));
4084 if ((channel & BlueChannel) != 0)
4085 SetPixelBlue(q,QuantumRange-GetPixelBlue(q));
4086 if ((channel & OpacityChannel) != 0)
4087 SetPixelOpacity(q,QuantumRange-GetPixelOpacity(q));
4088 if (((channel & IndexChannel) != 0) &&
4089 (image->colorspace == CMYKColorspace))
4090 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4093 sync=SyncCacheViewAuthenticPixels(image_view,exception);
4094 if (sync == MagickFalse)
4096 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4101 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4105 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4106 if (proceed == MagickFalse)
4110 image_view=DestroyCacheView(image_view);
4116 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4117 #pragma omp parallel for schedule(static) shared(progress,status) \
4118 magick_number_threads(image,image,image->rows,1)
4120 for (y=0; y < (ssize_t) image->rows; y++)
4123 *magick_restrict indexes;
4131 if (status == MagickFalse)
4133 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4139 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4140 if (channel == DefaultChannels)
4141 for (x=0; x < (ssize_t) image->columns; x++)
4143 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4144 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4145 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4148 for (x=0; x < (ssize_t) image->columns; x++)
4150 if ((channel & RedChannel) != 0)
4151 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4152 if ((channel & GreenChannel) != 0)
4153 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4154 if ((channel & BlueChannel) != 0)
4155 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4156 if ((channel & OpacityChannel) != 0)
4157 SetPixelOpacity(q+x,QuantumRange-GetPixelOpacity(q+x));
4159 if (((channel & IndexChannel) != 0) &&
4160 (image->colorspace == CMYKColorspace))
4161 for (x=0; x < (ssize_t) image->columns; x++)
4162 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4163 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4165 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4174 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4175 if (proceed == MagickFalse)
4179 image_view=DestroyCacheView(image_view);
4212 MagickExport MagickBooleanType NormalizeImage(
Image *image)
4217 status=NormalizeImageChannel(image,DefaultChannels);
4221 MagickExport MagickBooleanType NormalizeImageChannel(
Image *image,
4222 const ChannelType channel)
4228 black_point=0.02*image->columns*image->rows;
4229 white_point=0.99*image->columns*image->rows;
4230 return(ContrastStretchImageChannel(image,channel,black_point,white_point));
4299 #if defined(MAGICKCORE_HAVE_ATANH)
4300 #define Sigmoidal(a,b,x) ( tanh((0.5*(a))*((x)-(b))) )
4302 #define Sigmoidal(a,b,x) ( 1.0/(1.0+exp((a)*((b)-(x)))) )
4321 #define ScaledSigmoidal(a,b,x) ( \
4322 (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \
4323 (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) )
4333 static inline double InverseScaledSigmoidal(
const double a,
const double b,
4336 const double sig0=Sigmoidal(a,b,0.0);
4337 const double sig1=Sigmoidal(a,b,1.0);
4338 const double argument=(sig1-sig0)*x+sig0;
4339 const double clamped=
4341 #if defined(MAGICKCORE_HAVE_ATANH)
4342 argument < -1+MagickEpsilon
4346 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4348 return(b+(2.0/a)*atanh(clamped));
4350 argument < MagickEpsilon
4354 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4356 return(b-log(1.0/clamped-1.0)/a);
4360 MagickExport MagickBooleanType SigmoidalContrastImage(
Image *image,
4361 const MagickBooleanType sharpen,
const char *levels)
4372 flags=ParseGeometry(levels,&geometry_info);
4373 if ((flags & SigmaValue) == 0)
4374 geometry_info.sigma=1.0*QuantumRange/2.0;
4375 if ((flags & PercentValue) != 0)
4376 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
4377 status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
4378 geometry_info.rho,geometry_info.sigma);
4382 MagickExport MagickBooleanType SigmoidalContrastImageChannel(
Image *image,
4383 const ChannelType channel,
const MagickBooleanType sharpen,
4384 const double contrast,
const double midpoint)
4386 #define SigmoidalContrastImageTag "SigmoidalContrast/Image"
4413 if (contrast < MagickEpsilon)
4418 assert(image != (
Image *) NULL);
4419 assert(image->signature == MagickCoreSignature);
4420 if (IsEventLogging() != MagickFalse)
4421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4422 exception=(&image->exception);
4423 sigmoidal_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
4424 sizeof(*sigmoidal_map));
4425 if (sigmoidal_map == (MagickRealType *) NULL)
4426 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
4428 (void) memset(sigmoidal_map,0,(MaxMap+1)*
sizeof(*sigmoidal_map));
4429 if (sharpen != MagickFalse)
4430 for (i=0; i <= (ssize_t) MaxMap; i++)
4431 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
4432 (MaxMap*ScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4435 for (i=0; i <= (ssize_t) MaxMap; i++)
4436 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType) (
4437 MaxMap*InverseScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4442 if (image->storage_class == PseudoClass)
4443 for (i=0; i < (ssize_t) image->colors; i++)
4445 if ((channel & RedChannel) != 0)
4446 image->colormap[i].red=ClampToQuantum(sigmoidal_map[
4447 ScaleQuantumToMap(image->colormap[i].red)]);
4448 if ((channel & GreenChannel) != 0)
4449 image->colormap[i].green=ClampToQuantum(sigmoidal_map[
4450 ScaleQuantumToMap(image->colormap[i].green)]);
4451 if ((channel & BlueChannel) != 0)
4452 image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
4453 ScaleQuantumToMap(image->colormap[i].blue)]);
4454 if ((channel & OpacityChannel) != 0)
4455 image->colormap[i].opacity=ClampToQuantum(sigmoidal_map[
4456 ScaleQuantumToMap(image->colormap[i].opacity)]);
4463 image_view=AcquireAuthenticCacheView(image,exception);
4464 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4465 #pragma omp parallel for schedule(static) shared(progress,status) \
4466 magick_number_threads(image,image,image->rows,1)
4468 for (y=0; y < (ssize_t) image->rows; y++)
4471 *magick_restrict indexes;
4479 if (status == MagickFalse)
4481 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4487 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4488 for (x=0; x < (ssize_t) image->columns; x++)
4490 if ((channel & RedChannel) != 0)
4491 SetPixelRed(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4493 if ((channel & GreenChannel) != 0)
4494 SetPixelGreen(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4495 GetPixelGreen(q))]));
4496 if ((channel & BlueChannel) != 0)
4497 SetPixelBlue(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4498 GetPixelBlue(q))]));
4499 if ((channel & OpacityChannel) != 0)
4500 SetPixelOpacity(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4501 GetPixelOpacity(q))]));
4502 if (((channel & IndexChannel) != 0) &&
4503 (image->colorspace == CMYKColorspace))
4504 SetPixelIndex(indexes+x,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4505 GetPixelIndex(indexes+x))]));
4508 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4510 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4515 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4519 proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress,
4521 if (proceed == MagickFalse)
4525 image_view=DestroyCacheView(image_view);
4526 sigmoidal_map=(MagickRealType *) RelinquishMagickMemory(sigmoidal_map);