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 BrightnessContrastImageTag "BrightnessContrast/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 inline Contrast(
const int sign,Quantum *red,Quantum *green,
928 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
929 brightness+=0.5*sign*(0.5*(sin((
double) (MagickPI*(brightness-0.5)))+1.0)-
931 if (brightness > 1.0)
934 if (brightness < 0.0)
936 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
939 MagickExport MagickBooleanType ContrastImage(
Image *image,
940 const MagickBooleanType sharpen)
942 #define ContrastImageTag "Contrast/Image"
964 assert(image != (
Image *) NULL);
965 assert(image->signature == MagickCoreSignature);
966 if (IsEventLogging() != MagickFalse)
967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
968 sign=sharpen != MagickFalse ? 1 : -1;
969 if (image->storage_class == PseudoClass)
974 for (i=0; i < (ssize_t) image->colors; i++)
975 Contrast(sign,&image->colormap[i].red,&image->colormap[i].green,
976 &image->colormap[i].blue);
981 #if defined(MAGICKCORE_OPENCL_SUPPORT)
982 status=AccelerateContrastImage(image,sharpen,&image->exception);
983 if (status != MagickFalse)
988 exception=(&image->exception);
989 image_view=AcquireAuthenticCacheView(image,exception);
990 #if defined(MAGICKCORE_OPENMP_SUPPORT)
991 #pragma omp parallel for schedule(static) shared(progress,status) \
992 magick_number_threads(image,image,image->rows,1)
994 for (y=0; y < (ssize_t) image->rows; y++)
1007 if (status == MagickFalse)
1009 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1015 for (x=0; x < (ssize_t) image->columns; x++)
1018 green=GetPixelGreen(q);
1019 blue=GetPixelBlue(q);
1020 Contrast(sign,&red,&green,&blue);
1022 SetPixelGreen(q,green);
1023 SetPixelBlue(q,blue);
1026 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1028 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1033 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1037 proceed=SetImageProgress(image,ContrastImageTag,progress,image->rows);
1038 if (proceed == MagickFalse)
1042 image_view=DestroyCacheView(image_view);
1087 MagickExport MagickBooleanType ContrastStretchImage(
Image *image,
1092 white_point = (double) image->columns*image->rows;
1106 if (levels == (
char *) NULL)
1107 return(MagickFalse);
1108 flags=ParseGeometry(levels,&geometry_info);
1109 if ((flags & RhoValue) != 0)
1110 black_point=geometry_info.rho;
1111 if ((flags & SigmaValue) != 0)
1112 white_point=geometry_info.sigma;
1113 if ((flags & PercentValue) != 0)
1115 black_point*=(double) QuantumRange/100.0;
1116 white_point*=(double) QuantumRange/100.0;
1118 if ((flags & SigmaValue) == 0)
1119 white_point=(
double) image->columns*image->rows-black_point;
1120 status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
1125 MagickExport MagickBooleanType ContrastStretchImageChannel(
Image *image,
1126 const ChannelType channel,
const double black_point,
const double white_point)
1128 #define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
1129 #define ContrastStretchImageTag "ContrastStretch/Image"
1163 assert(image != (
Image *) NULL);
1164 assert(image->signature == MagickCoreSignature);
1165 if (IsEventLogging() != MagickFalse)
1166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1167 exception=(&image->exception);
1169 #if defined(MAGICKCORE_OPENCL_SUPPORT) && 0
1171 status=AccelerateContrastStretchImageChannel(image,channel,black_point,
1172 white_point,&image->exception);
1173 if (status != MagickFalse)
1177 sizeof(*histogram));
1179 sizeof(*stretch_map));
1187 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1193 if (SetImageGray(image,exception) != MagickFalse)
1194 (void) SetImageColorspace(image,GRAYColorspace);
1196 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1197 image_view=AcquireAuthenticCacheView(image,exception);
1198 for (y=0; y < (ssize_t) image->rows; y++)
1204 *magick_restrict indexes;
1209 if (status == MagickFalse)
1211 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1217 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1218 if ((channel & SyncChannels) != 0)
1219 for (x=0; x < (ssize_t) image->columns; x++)
1224 intensity=ClampToQuantum(GetPixelIntensity(image,p));
1225 histogram[ScaleQuantumToMap(intensity)].red++;
1226 histogram[ScaleQuantumToMap(intensity)].green++;
1227 histogram[ScaleQuantumToMap(intensity)].blue++;
1228 histogram[ScaleQuantumToMap(intensity)].index++;
1232 for (x=0; x < (ssize_t) image->columns; x++)
1234 if ((channel & RedChannel) != 0)
1235 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1236 if ((channel & GreenChannel) != 0)
1237 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1238 if ((channel & BlueChannel) != 0)
1239 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1240 if ((channel & OpacityChannel) != 0)
1241 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1242 if (((channel & IndexChannel) != 0) &&
1243 (image->colorspace == CMYKColorspace))
1244 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1252 white.red=MaxRange(QuantumRange);
1253 if ((channel & RedChannel) != 0)
1256 for (i=0; i <= (ssize_t) MaxMap; i++)
1258 intensity+=histogram[i].red;
1259 if (intensity > black_point)
1262 black.red=(MagickRealType) i;
1264 for (i=(ssize_t) MaxMap; i != 0; i--)
1266 intensity+=histogram[i].red;
1267 if (intensity > ((
double) image->columns*image->rows-white_point))
1270 white.red=(MagickRealType) i;
1273 white.green=MaxRange(QuantumRange);
1274 if ((channel & GreenChannel) != 0)
1277 for (i=0; i <= (ssize_t) MaxMap; i++)
1279 intensity+=histogram[i].green;
1280 if (intensity > black_point)
1283 black.green=(MagickRealType) i;
1285 for (i=(ssize_t) MaxMap; i != 0; i--)
1287 intensity+=histogram[i].green;
1288 if (intensity > ((
double) image->columns*image->rows-white_point))
1291 white.green=(MagickRealType) i;
1294 white.blue=MaxRange(QuantumRange);
1295 if ((channel & BlueChannel) != 0)
1298 for (i=0; i <= (ssize_t) MaxMap; i++)
1300 intensity+=histogram[i].blue;
1301 if (intensity > black_point)
1304 black.blue=(MagickRealType) i;
1306 for (i=(ssize_t) MaxMap; i != 0; i--)
1308 intensity+=histogram[i].blue;
1309 if (intensity > ((
double) image->columns*image->rows-white_point))
1312 white.blue=(MagickRealType) i;
1315 white.opacity=MaxRange(QuantumRange);
1316 if ((channel & OpacityChannel) != 0)
1319 for (i=0; i <= (ssize_t) MaxMap; i++)
1321 intensity+=histogram[i].opacity;
1322 if (intensity > black_point)
1325 black.opacity=(MagickRealType) i;
1327 for (i=(ssize_t) MaxMap; i != 0; i--)
1329 intensity+=histogram[i].opacity;
1330 if (intensity > ((
double) image->columns*image->rows-white_point))
1333 white.opacity=(MagickRealType) i;
1336 white.index=MaxRange(QuantumRange);
1337 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1340 for (i=0; i <= (ssize_t) MaxMap; i++)
1342 intensity+=histogram[i].index;
1343 if (intensity > black_point)
1346 black.index=(MagickRealType) i;
1348 for (i=(ssize_t) MaxMap; i != 0; i--)
1350 intensity+=histogram[i].index;
1351 if (intensity > ((
double) image->columns*image->rows-white_point))
1354 white.index=(MagickRealType) i;
1360 (void) memset(stretch_map,0,(MaxMap+1)*
sizeof(*stretch_map));
1361 for (i=0; i <= (ssize_t) MaxMap; i++)
1363 if ((channel & RedChannel) != 0)
1365 if (i < (ssize_t) black.red)
1366 stretch_map[i].red=(Quantum) 0;
1368 if (i > (ssize_t) white.red)
1369 stretch_map[i].red=QuantumRange;
1371 if (black.red != white.red)
1372 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
1373 (i-black.red)/(white.red-black.red)));
1375 if ((channel & GreenChannel) != 0)
1377 if (i < (ssize_t) black.green)
1378 stretch_map[i].green=0;
1380 if (i > (ssize_t) white.green)
1381 stretch_map[i].green=QuantumRange;
1383 if (black.green != white.green)
1384 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
1385 (i-black.green)/(white.green-black.green)));
1387 if ((channel & BlueChannel) != 0)
1389 if (i < (ssize_t) black.blue)
1390 stretch_map[i].blue=0;
1392 if (i > (ssize_t) white.blue)
1393 stretch_map[i].blue= QuantumRange;
1395 if (black.blue != white.blue)
1396 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
1397 (i-black.blue)/(white.blue-black.blue)));
1399 if ((channel & OpacityChannel) != 0)
1401 if (i < (ssize_t) black.opacity)
1402 stretch_map[i].opacity=0;
1404 if (i > (ssize_t) white.opacity)
1405 stretch_map[i].opacity=QuantumRange;
1407 if (black.opacity != white.opacity)
1408 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
1409 (i-black.opacity)/(white.opacity-black.opacity)));
1411 if (((channel & IndexChannel) != 0) &&
1412 (image->colorspace == CMYKColorspace))
1414 if (i < (ssize_t) black.index)
1415 stretch_map[i].index=0;
1417 if (i > (ssize_t) white.index)
1418 stretch_map[i].index=QuantumRange;
1420 if (black.index != white.index)
1421 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
1422 (i-black.index)/(white.index-black.index)));
1428 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
1429 (image->colorspace == CMYKColorspace)))
1430 image->storage_class=DirectClass;
1431 if (image->storage_class == PseudoClass)
1436 for (i=0; i < (ssize_t) image->colors; i++)
1438 if ((channel & RedChannel) != 0)
1440 if (black.red != white.red)
1441 image->colormap[i].red=stretch_map[
1442 ScaleQuantumToMap(image->colormap[i].red)].red;
1444 if ((channel & GreenChannel) != 0)
1446 if (black.green != white.green)
1447 image->colormap[i].green=stretch_map[
1448 ScaleQuantumToMap(image->colormap[i].green)].green;
1450 if ((channel & BlueChannel) != 0)
1452 if (black.blue != white.blue)
1453 image->colormap[i].blue=stretch_map[
1454 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1456 if ((channel & OpacityChannel) != 0)
1458 if (black.opacity != white.opacity)
1459 image->colormap[i].opacity=stretch_map[
1460 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1469 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1470 #pragma omp parallel for schedule(static) shared(progress,status) \
1471 magick_number_threads(image,image,image->rows,1)
1473 for (y=0; y < (ssize_t) image->rows; y++)
1476 *magick_restrict indexes;
1484 if (status == MagickFalse)
1486 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1492 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1493 for (x=0; x < (ssize_t) image->columns; x++)
1495 if ((channel & RedChannel) != 0)
1497 if (black.red != white.red)
1498 SetPixelRed(q,stretch_map[
1499 ScaleQuantumToMap(GetPixelRed(q))].red);
1501 if ((channel & GreenChannel) != 0)
1503 if (black.green != white.green)
1504 SetPixelGreen(q,stretch_map[
1505 ScaleQuantumToMap(GetPixelGreen(q))].green);
1507 if ((channel & BlueChannel) != 0)
1509 if (black.blue != white.blue)
1510 SetPixelBlue(q,stretch_map[
1511 ScaleQuantumToMap(GetPixelBlue(q))].blue);
1513 if ((channel & OpacityChannel) != 0)
1515 if (black.opacity != white.opacity)
1516 SetPixelOpacity(q,stretch_map[
1517 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
1519 if (((channel & IndexChannel) != 0) &&
1520 (image->colorspace == CMYKColorspace))
1522 if (black.index != white.index)
1523 SetPixelIndex(indexes+x,stretch_map[
1524 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
1528 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1530 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1535 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1539 proceed=SetImageProgress(image,ContrastStretchImageTag,progress,
1541 if (proceed == MagickFalse)
1545 image_view=DestroyCacheView(image_view);
1577 #define EnhancePixel(weight) \
1578 mean=QuantumScale*((double) GetPixelRed(r)+pixel.red)/2.0; \
1579 distance=QuantumScale*((double) GetPixelRed(r)-pixel.red); \
1580 distance_squared=(4.0+mean)*distance*distance; \
1581 mean=QuantumScale*((double) GetPixelGreen(r)+pixel.green)/2.0; \
1582 distance=QuantumScale*((double) GetPixelGreen(r)-pixel.green); \
1583 distance_squared+=(7.0-mean)*distance*distance; \
1584 mean=QuantumScale*((double) GetPixelBlue(r)+pixel.blue)/2.0; \
1585 distance=QuantumScale*((double) GetPixelBlue(r)-pixel.blue); \
1586 distance_squared+=(5.0-mean)*distance*distance; \
1587 mean=QuantumScale*((double) GetPixelOpacity(r)+pixel.opacity)/2.0; \
1588 distance=QuantumScale*((double) GetPixelOpacity(r)-pixel.opacity); \
1589 distance_squared+=(5.0-mean)*distance*distance; \
1590 if (distance_squared < 0.069) \
1592 aggregate.red+=(weight)*GetPixelRed(r); \
1593 aggregate.green+=(weight)*GetPixelGreen(r); \
1594 aggregate.blue+=(weight)*GetPixelBlue(r); \
1595 aggregate.opacity+=(weight)*GetPixelOpacity(r); \
1596 total_weight+=(weight); \
1599 #define EnhanceImageTag "Enhance/Image"
1623 assert(image != (
const Image *) NULL);
1624 assert(image->signature == MagickCoreSignature);
1625 if (IsEventLogging() != MagickFalse)
1626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1628 assert(exception->signature == MagickCoreSignature);
1629 if ((image->columns < 5) || (image->rows < 5))
1630 return((
Image *) NULL);
1631 enhance_image=CloneImage(image,0,0,MagickTrue,exception);
1632 if (enhance_image == (
Image *) NULL)
1633 return((
Image *) NULL);
1634 if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
1636 InheritException(exception,&enhance_image->exception);
1637 enhance_image=DestroyImage(enhance_image);
1638 return((
Image *) NULL);
1645 (void) memset(&zero,0,
sizeof(zero));
1646 image_view=AcquireAuthenticCacheView(image,exception);
1647 enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
1648 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1649 #pragma omp parallel for schedule(static) shared(progress,status) \
1650 magick_number_threads(image,enhance_image,image->rows,1)
1652 for (y=0; y < (ssize_t) image->rows; y++)
1666 if (status == MagickFalse)
1668 p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
1669 q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
1676 for (x=0; x < (ssize_t) image->columns; x++)
1698 r=p+2*(image->columns+4)+2;
1701 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1702 EnhancePixel(8.0); EnhancePixel(5.0);
1703 r=p+(image->columns+4);
1704 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1705 EnhancePixel(20.0); EnhancePixel(8.0);
1706 r=p+2*(image->columns+4);
1707 EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
1708 EnhancePixel(40.0); EnhancePixel(10.0);
1709 r=p+3*(image->columns+4);
1710 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1711 EnhancePixel(20.0); EnhancePixel(8.0);
1712 r=p+4*(image->columns+4);
1713 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1714 EnhancePixel(8.0); EnhancePixel(5.0);
1715 if (total_weight > MagickEpsilon)
1717 SetPixelRed(q,(aggregate.red+(total_weight/2)-1)/total_weight);
1718 SetPixelGreen(q,(aggregate.green+(total_weight/2)-1)/total_weight);
1719 SetPixelBlue(q,(aggregate.blue+(total_weight/2)-1)/total_weight);
1720 SetPixelOpacity(q,(aggregate.opacity+(total_weight/2)-1)/
1726 if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
1728 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1733 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1737 proceed=SetImageProgress(image,EnhanceImageTag,progress,image->rows);
1738 if (proceed == MagickFalse)
1742 enhance_view=DestroyCacheView(enhance_view);
1743 image_view=DestroyCacheView(image_view);
1744 if (status == MagickFalse)
1745 enhance_image=DestroyImage(enhance_image);
1746 return(enhance_image);
1776 MagickExport MagickBooleanType EqualizeImage(
Image *image)
1778 return(EqualizeImageChannel(image,DefaultChannels));
1781 MagickExport MagickBooleanType EqualizeImageChannel(
Image *image,
1782 const ChannelType channel)
1784 #define EqualizeImageTag "Equalize/Image"
1814 assert(image != (
Image *) NULL);
1815 assert(image->signature == MagickCoreSignature);
1816 if (IsEventLogging() != MagickFalse)
1817 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1818 exception=(&image->exception);
1820 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1822 status=AccelerateEqualizeImage(image,channel,&image->exception);
1823 if (status != MagickFalse)
1830 sizeof(*equalize_map));
1832 sizeof(*histogram));
1845 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1851 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1852 image_view=AcquireVirtualCacheView(image,exception);
1853 for (y=0; y < (ssize_t) image->rows; y++)
1856 *magick_restrict indexes;
1864 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1867 indexes=GetCacheViewVirtualIndexQueue(image_view);
1868 if ((channel & SyncChannels) != 0)
1869 for (x=0; x < (ssize_t) image->columns; x++)
1871 MagickRealType intensity=GetPixelIntensity(image,p);
1872 histogram[ScaleQuantumToMap(ClampToQuantum(intensity))].red++;
1876 for (x=0; x < (ssize_t) image->columns; x++)
1878 if ((channel & RedChannel) != 0)
1879 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1880 if ((channel & GreenChannel) != 0)
1881 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1882 if ((channel & BlueChannel) != 0)
1883 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1884 if ((channel & OpacityChannel) != 0)
1885 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1886 if (((channel & IndexChannel) != 0) &&
1887 (image->colorspace == CMYKColorspace))
1888 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1892 image_view=DestroyCacheView(image_view);
1896 (void) memset(&intensity,0,
sizeof(intensity));
1897 for (i=0; i <= (ssize_t) MaxMap; i++)
1899 if ((channel & SyncChannels) != 0)
1901 intensity.red+=histogram[i].red;
1905 if ((channel & RedChannel) != 0)
1906 intensity.red+=histogram[i].red;
1907 if ((channel & GreenChannel) != 0)
1908 intensity.green+=histogram[i].green;
1909 if ((channel & BlueChannel) != 0)
1910 intensity.blue+=histogram[i].blue;
1911 if ((channel & OpacityChannel) != 0)
1912 intensity.opacity+=histogram[i].opacity;
1913 if (((channel & IndexChannel) != 0) &&
1914 (image->colorspace == CMYKColorspace))
1915 intensity.index+=histogram[i].index;
1919 white=map[(int) MaxMap];
1920 (void) memset(equalize_map,0,(MaxMap+1)*
sizeof(*equalize_map));
1921 for (i=0; i <= (ssize_t) MaxMap; i++)
1923 if ((channel & SyncChannels) != 0)
1925 if (white.red != black.red)
1926 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1927 (map[i].red-black.red))/(white.red-black.red)));
1930 if (((channel & RedChannel) != 0) && (white.red != black.red))
1931 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1932 (map[i].red-black.red))/(white.red-black.red)));
1933 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1934 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1935 (map[i].green-black.green))/(white.green-black.green)));
1936 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1937 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1938 (map[i].blue-black.blue))/(white.blue-black.blue)));
1939 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
1940 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1941 (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
1942 if ((((channel & IndexChannel) != 0) &&
1943 (image->colorspace == CMYKColorspace)) &&
1944 (white.index != black.index))
1945 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1946 (map[i].index-black.index))/(white.index-black.index)));
1950 if (image->storage_class == PseudoClass)
1955 for (i=0; i < (ssize_t) image->colors; i++)
1957 if ((channel & SyncChannels) != 0)
1959 if (white.red != black.red)
1961 image->colormap[i].red=equalize_map[
1962 ScaleQuantumToMap(image->colormap[i].red)].red;
1963 image->colormap[i].green=equalize_map[
1964 ScaleQuantumToMap(image->colormap[i].green)].red;
1965 image->colormap[i].blue=equalize_map[
1966 ScaleQuantumToMap(image->colormap[i].blue)].red;
1967 image->colormap[i].opacity=equalize_map[
1968 ScaleQuantumToMap(image->colormap[i].opacity)].red;
1972 if (((channel & RedChannel) != 0) && (white.red != black.red))
1973 image->colormap[i].red=equalize_map[
1974 ScaleQuantumToMap(image->colormap[i].red)].red;
1975 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1976 image->colormap[i].green=equalize_map[
1977 ScaleQuantumToMap(image->colormap[i].green)].green;
1978 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1979 image->colormap[i].blue=equalize_map[
1980 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1981 if (((channel & OpacityChannel) != 0) &&
1982 (white.opacity != black.opacity))
1983 image->colormap[i].opacity=equalize_map[
1984 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1992 image_view=AcquireAuthenticCacheView(image,exception);
1993 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1994 #pragma omp parallel for schedule(static) shared(progress,status) \
1995 magick_number_threads(image,image,image->rows,1)
1997 for (y=0; y < (ssize_t) image->rows; y++)
2000 *magick_restrict indexes;
2008 if (status == MagickFalse)
2010 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2016 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2017 for (x=0; x < (ssize_t) image->columns; x++)
2019 if ((channel & SyncChannels) != 0)
2021 if (white.red != black.red)
2023 SetPixelRed(q,equalize_map[
2024 ScaleQuantumToMap(GetPixelRed(q))].red);
2025 SetPixelGreen(q,equalize_map[
2026 ScaleQuantumToMap(GetPixelGreen(q))].red);
2027 SetPixelBlue(q,equalize_map[
2028 ScaleQuantumToMap(GetPixelBlue(q))].red);
2029 SetPixelOpacity(q,equalize_map[
2030 ScaleQuantumToMap(GetPixelOpacity(q))].red);
2031 if (image->colorspace == CMYKColorspace)
2032 SetPixelIndex(indexes+x,equalize_map[
2033 ScaleQuantumToMap(GetPixelIndex(indexes+x))].red);
2038 if (((channel & RedChannel) != 0) && (white.red != black.red))
2039 SetPixelRed(q,equalize_map[
2040 ScaleQuantumToMap(GetPixelRed(q))].red);
2041 if (((channel & GreenChannel) != 0) && (white.green != black.green))
2042 SetPixelGreen(q,equalize_map[
2043 ScaleQuantumToMap(GetPixelGreen(q))].green);
2044 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
2045 SetPixelBlue(q,equalize_map[
2046 ScaleQuantumToMap(GetPixelBlue(q))].blue);
2047 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
2048 SetPixelOpacity(q,equalize_map[
2049 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
2050 if ((((channel & IndexChannel) != 0) &&
2051 (image->colorspace == CMYKColorspace)) &&
2052 (white.index != black.index))
2053 SetPixelIndex(indexes+x,equalize_map[
2054 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
2057 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2059 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2064 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2068 proceed=SetImageProgress(image,EqualizeImageTag,progress,image->rows);
2069 if (proceed == MagickFalse)
2073 image_view=DestroyCacheView(image_view);
2116 static inline double gamma_pow(
const double value,
const double gamma)
2118 return(value < 0.0 ? value : pow(value,gamma));
2121 MagickExport MagickBooleanType GammaImage(
Image *image,
const char *level)
2133 assert(image != (
Image *) NULL);
2134 assert(image->signature == MagickCoreSignature);
2135 if (IsEventLogging() != MagickFalse)
2136 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2137 if (level == (
char *) NULL)
2138 return(MagickFalse);
2140 flags=ParseGeometry(level,&geometry_info);
2141 if ((flags & RhoValue) != 0)
2142 gamma.red=geometry_info.rho;
2143 gamma.green=gamma.red;
2144 if ((flags & SigmaValue) != 0)
2145 gamma.green=geometry_info.sigma;
2146 gamma.blue=gamma.red;
2147 if ((flags & XiValue) != 0)
2148 gamma.blue=geometry_info.xi;
2149 if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
2151 if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
2152 status=GammaImageChannel(image,(ChannelType) (RedChannel | GreenChannel |
2153 BlueChannel),(
double) gamma.red);
2156 status=GammaImageChannel(image,RedChannel,(
double) gamma.red);
2157 status&=GammaImageChannel(image,GreenChannel,(
double) gamma.green);
2158 status&=GammaImageChannel(image,BlueChannel,(
double) gamma.blue);
2160 return(status != 0 ? MagickTrue : MagickFalse);
2163 MagickExport MagickBooleanType GammaImageChannel(
Image *image,
2164 const ChannelType channel,
const double gamma)
2166 #define GammaImageTag "Gamma/Image"
2192 assert(image != (
Image *) NULL);
2193 assert(image->signature == MagickCoreSignature);
2194 if (IsEventLogging() != MagickFalse)
2195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2196 exception=(&image->exception);
2199 gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*gamma_map));
2200 if (gamma_map == (Quantum *) NULL)
2201 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2203 (void) memset(gamma_map,0,(MaxMap+1)*
sizeof(*gamma_map));
2205 for (i=0; i <= (ssize_t) MaxMap; i++)
2206 gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
2207 MagickRealType) (MaxMap*pow((
double) i/MaxMap,
2208 PerceptibleReciprocal(gamma)))));
2209 if (image->storage_class == PseudoClass)
2214 for (i=0; i < (ssize_t) image->colors; i++)
2216 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2217 if ((channel & RedChannel) != 0)
2218 image->colormap[i].red=gamma_map[ScaleQuantumToMap(
2219 image->colormap[i].red)];
2220 if ((channel & GreenChannel) != 0)
2221 image->colormap[i].green=gamma_map[ScaleQuantumToMap(
2222 image->colormap[i].green)];
2223 if ((channel & BlueChannel) != 0)
2224 image->colormap[i].blue=gamma_map[ScaleQuantumToMap(
2225 image->colormap[i].blue)];
2226 if ((channel & OpacityChannel) != 0)
2228 if (image->matte == MagickFalse)
2229 image->colormap[i].opacity=gamma_map[ScaleQuantumToMap(
2230 image->colormap[i].opacity)];
2232 image->colormap[i].opacity=QuantumRange-gamma_map[
2233 ScaleQuantumToMap((Quantum) (QuantumRange-
2234 image->colormap[i].opacity))];
2237 if ((channel & RedChannel) != 0)
2238 image->colormap[i].red=QuantumRange*gamma_pow(QuantumScale*
2239 image->colormap[i].red,PerceptibleReciprocal(gamma));
2240 if ((channel & GreenChannel) != 0)
2241 image->colormap[i].green=QuantumRange*gamma_pow(QuantumScale*
2242 image->colormap[i].green,PerceptibleReciprocal(gamma));
2243 if ((channel & BlueChannel) != 0)
2244 image->colormap[i].blue=QuantumRange*gamma_pow(QuantumScale*
2245 image->colormap[i].blue,PerceptibleReciprocal(gamma));
2246 if ((channel & OpacityChannel) != 0)
2248 if (image->matte == MagickFalse)
2249 image->colormap[i].opacity=QuantumRange*gamma_pow(QuantumScale*
2250 image->colormap[i].opacity,PerceptibleReciprocal(gamma));
2252 image->colormap[i].opacity=QuantumRange-QuantumRange*gamma_pow(
2253 QuantumScale*(QuantumRange-image->colormap[i].opacity),1.0/
2264 image_view=AcquireAuthenticCacheView(image,exception);
2265 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2266 #pragma omp parallel for schedule(static) shared(progress,status) \
2267 magick_number_threads(image,image,image->rows,1)
2269 for (y=0; y < (ssize_t) image->rows; y++)
2272 *magick_restrict indexes;
2280 if (status == MagickFalse)
2282 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2288 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2289 for (x=0; x < (ssize_t) image->columns; x++)
2291 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2292 if ((channel & SyncChannels) != 0)
2294 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2295 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2296 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2300 if ((channel & RedChannel) != 0)
2301 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2302 if ((channel & GreenChannel) != 0)
2303 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2304 if ((channel & BlueChannel) != 0)
2305 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2306 if ((channel & OpacityChannel) != 0)
2308 if (image->matte == MagickFalse)
2309 SetPixelOpacity(q,gamma_map[ScaleQuantumToMap(
2310 GetPixelOpacity(q))]);
2312 SetPixelAlpha(q,gamma_map[ScaleQuantumToMap((Quantum)
2313 GetPixelAlpha(q))]);
2317 if ((channel & SyncChannels) != 0)
2319 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2320 PerceptibleReciprocal(gamma)));
2321 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*GetPixelGreen(q),
2322 PerceptibleReciprocal(gamma)));
2323 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2324 PerceptibleReciprocal(gamma)));
2328 if ((channel & RedChannel) != 0)
2329 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2330 PerceptibleReciprocal(gamma)));
2331 if ((channel & GreenChannel) != 0)
2332 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*
2333 GetPixelGreen(q),PerceptibleReciprocal(gamma)));
2334 if ((channel & BlueChannel) != 0)
2335 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2336 PerceptibleReciprocal(gamma)));
2337 if ((channel & OpacityChannel) != 0)
2339 if (image->matte == MagickFalse)
2340 SetPixelOpacity(q,QuantumRange*gamma_pow(QuantumScale*
2341 GetPixelOpacity(q),PerceptibleReciprocal(gamma)));
2343 SetPixelAlpha(q,QuantumRange*gamma_pow(QuantumScale*
2344 GetPixelAlpha(q),PerceptibleReciprocal(gamma)));
2350 if (((channel & IndexChannel) != 0) &&
2351 (image->colorspace == CMYKColorspace))
2352 for (x=0; x < (ssize_t) image->columns; x++)
2353 SetPixelIndex(indexes+x,gamma_map[ScaleQuantumToMap(
2354 GetPixelIndex(indexes+x))]);
2355 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2357 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2362 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2366 proceed=SetImageProgress(image,GammaImageTag,progress,image->rows);
2367 if (proceed == MagickFalse)
2371 image_view=DestroyCacheView(image_view);
2372 gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
2373 if (image->gamma != 0.0)
2374 image->gamma*=gamma;
2403 MagickExport MagickBooleanType GrayscaleImage(
Image *image,
2404 const PixelIntensityMethod method)
2406 #define GrayscaleImageTag "Grayscale/Image"
2423 assert(image != (
Image *) NULL);
2424 assert(image->signature == MagickCoreSignature);
2425 if (IsEventLogging() != MagickFalse)
2426 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2427 if (image->storage_class == PseudoClass)
2429 if (SyncImage(image) == MagickFalse)
2430 return(MagickFalse);
2431 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2432 return(MagickFalse);
2440 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2441 if (AccelerateGrayscaleImage(image,method,&image->exception) != MagickFalse)
2443 image->intensity=method;
2444 image->type=GrayscaleType;
2445 if ((method == Rec601LuminancePixelIntensityMethod) ||
2446 (method == Rec709LuminancePixelIntensityMethod))
2447 return(SetImageColorspace(image,LinearGRAYColorspace));
2448 return(SetImageColorspace(image,GRAYColorspace));
2453 exception=(&image->exception);
2454 image_view=AcquireAuthenticCacheView(image,exception);
2455 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2456 #pragma omp parallel for schedule(static) shared(progress,status) \
2457 magick_number_threads(image,image,image->rows,1)
2459 for (y=0; y < (ssize_t) image->rows; y++)
2467 if (status == MagickFalse)
2469 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2475 for (x=0; x < (ssize_t) image->columns; x++)
2483 red=(MagickRealType) q->red;
2484 green=(MagickRealType) q->green;
2485 blue=(MagickRealType) q->blue;
2489 case AveragePixelIntensityMethod:
2491 intensity=(red+green+blue)/3.0;
2494 case BrightnessPixelIntensityMethod:
2496 intensity=MagickMax(MagickMax(red,green),blue);
2499 case LightnessPixelIntensityMethod:
2501 intensity=(MagickMin(MagickMin(red,green),blue)+
2502 MagickMax(MagickMax(red,green),blue))/2.0;
2505 case MSPixelIntensityMethod:
2507 intensity=(MagickRealType) (((
double) red*red+green*green+
2508 blue*blue)/(3.0*QuantumRange));
2511 case Rec601LumaPixelIntensityMethod:
2513 if (image->colorspace == RGBColorspace)
2515 red=EncodePixelGamma(red);
2516 green=EncodePixelGamma(green);
2517 blue=EncodePixelGamma(blue);
2519 intensity=0.298839*red+0.586811*green+0.114350*blue;
2522 case Rec601LuminancePixelIntensityMethod:
2524 if (image->colorspace == sRGBColorspace)
2526 red=DecodePixelGamma(red);
2527 green=DecodePixelGamma(green);
2528 blue=DecodePixelGamma(blue);
2530 intensity=0.298839*red+0.586811*green+0.114350*blue;
2533 case Rec709LumaPixelIntensityMethod:
2536 if (image->colorspace == RGBColorspace)
2538 red=EncodePixelGamma(red);
2539 green=EncodePixelGamma(green);
2540 blue=EncodePixelGamma(blue);
2542 intensity=0.212656*red+0.715158*green+0.072186*blue;
2545 case Rec709LuminancePixelIntensityMethod:
2547 if (image->colorspace == sRGBColorspace)
2549 red=DecodePixelGamma(red);
2550 green=DecodePixelGamma(green);
2551 blue=DecodePixelGamma(blue);
2553 intensity=0.212656*red+0.715158*green+0.072186*blue;
2556 case RMSPixelIntensityMethod:
2558 intensity=(MagickRealType) (sqrt((
double) red*red+green*green+
2559 blue*blue)/sqrt(3.0));
2563 SetPixelGray(q,ClampToQuantum(intensity));
2566 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2568 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2573 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2577 proceed=SetImageProgress(image,GrayscaleImageTag,progress,image->rows);
2578 if (proceed == MagickFalse)
2582 image_view=DestroyCacheView(image_view);
2583 image->intensity=method;
2584 image->type=GrayscaleType;
2585 if ((method == Rec601LuminancePixelIntensityMethod) ||
2586 (method == Rec709LuminancePixelIntensityMethod))
2587 return(SetImageColorspace(image,LinearGRAYColorspace));
2588 return(SetImageColorspace(image,GRAYColorspace));
2624 MagickExport MagickBooleanType HaldClutImage(
Image *image,
2625 const Image *hald_image)
2627 return(HaldClutImageChannel(image,DefaultChannels,hald_image));
2630 MagickExport MagickBooleanType HaldClutImageChannel(
Image *image,
2631 const ChannelType channel,
const Image *hald_image)
2633 #define HaldClutImageTag "Clut/Image"
2635 typedef struct _HaldInfo
2670 assert(image != (
Image *) NULL);
2671 assert(image->signature == MagickCoreSignature);
2672 if (IsEventLogging() != MagickFalse)
2673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2674 assert(hald_image != (
Image *) NULL);
2675 assert(hald_image->signature == MagickCoreSignature);
2676 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2677 return(MagickFalse);
2678 if (IsGrayColorspace(image->colorspace) != MagickFalse)
2679 (void) SetImageColorspace(image,sRGBColorspace);
2680 if (image->matte == MagickFalse)
2681 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
2687 length=(size_t) MagickMin((MagickRealType) hald_image->columns,
2688 (MagickRealType) hald_image->rows);
2689 for (level=2; (level*level*level) < length; level++) ;
2691 cube_size=level*level;
2692 width=(double) hald_image->columns;
2693 GetMagickPixelPacket(hald_image,&zero);
2694 exception=(&image->exception);
2695 image_view=AcquireAuthenticCacheView(image,exception);
2696 hald_view=AcquireAuthenticCacheView(hald_image,exception);
2697 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2698 #pragma omp parallel for schedule(static) shared(progress,status) \
2699 magick_number_threads(image,hald_image,image->rows,1)
2701 for (y=0; y < (ssize_t) image->rows; y++)
2718 *magick_restrict indexes;
2726 if (status == MagickFalse)
2728 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2734 indexes=GetCacheViewAuthenticIndexQueue(hald_view);
2740 for (x=0; x < (ssize_t) image->columns; x++)
2742 point.x=QuantumScale*(level-1.0)*GetPixelRed(q);
2743 point.y=QuantumScale*(level-1.0)*GetPixelGreen(q);
2744 point.z=QuantumScale*(level-1.0)*GetPixelBlue(q);
2745 offset=(double) (point.x+level*floor(point.y)+cube_size*floor(point.z));
2746 point.x-=floor(point.x);
2747 point.y-=floor(point.y);
2748 point.z-=floor(point.z);
2749 status=InterpolateMagickPixelPacket(image,hald_view,
2750 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2752 if (status == MagickFalse)
2754 status=InterpolateMagickPixelPacket(image,hald_view,
2755 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2756 width),&pixel2,exception);
2757 if (status == MagickFalse)
2760 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2761 area=(point.y < 0.5) ? 0.0 : 1.0;
2762 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2763 pixel2.opacity,area,&pixel3);
2765 status=InterpolateMagickPixelPacket(image,hald_view,
2766 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2768 if (status == MagickFalse)
2770 status=InterpolateMagickPixelPacket(image,hald_view,
2771 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2772 width),&pixel2,exception);
2773 if (status == MagickFalse)
2775 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2776 pixel2.opacity,area,&pixel4);
2778 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2779 area=(point.z < 0.5)? 0.0 : 1.0;
2780 MagickPixelCompositeAreaBlend(&pixel3,pixel3.opacity,&pixel4,
2781 pixel4.opacity,area,&pixel);
2782 if ((channel & RedChannel) != 0)
2783 SetPixelRed(q,ClampToQuantum(pixel.red));
2784 if ((channel & GreenChannel) != 0)
2785 SetPixelGreen(q,ClampToQuantum(pixel.green));
2786 if ((channel & BlueChannel) != 0)
2787 SetPixelBlue(q,ClampToQuantum(pixel.blue));
2788 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2789 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
2790 if (((channel & IndexChannel) != 0) &&
2791 (image->colorspace == CMYKColorspace))
2792 SetPixelIndex(indexes+x,ClampToQuantum(pixel.index));
2795 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2797 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2802 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2806 proceed=SetImageProgress(image,HaldClutImageTag,progress,image->rows);
2807 if (proceed == MagickFalse)
2811 hald_view=DestroyCacheView(hald_view);
2812 image_view=DestroyCacheView(image_view);
2857 MagickExport MagickBooleanType LevelImage(
Image *image,
const char *levels)
2862 white_point = (double) QuantumRange;
2876 if (levels == (
char *) NULL)
2877 return(MagickFalse);
2878 flags=ParseGeometry(levels,&geometry_info);
2879 if ((flags & RhoValue) != 0)
2880 black_point=geometry_info.rho;
2881 if ((flags & SigmaValue) != 0)
2882 white_point=geometry_info.sigma;
2883 if ((flags & XiValue) != 0)
2884 gamma=geometry_info.xi;
2885 if ((flags & PercentValue) != 0)
2887 black_point*=(double) image->columns*image->rows/100.0;
2888 white_point*=(
double) image->columns*image->rows/100.0;
2890 if ((flags & SigmaValue) == 0)
2891 white_point=(
double) QuantumRange-black_point;
2892 if ((flags & AspectValue ) == 0)
2893 status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
2896 status=LevelizeImage(image,black_point,white_point,gamma);
2943 static inline double LevelPixel(
const double black_point,
2944 const double white_point,
const double gamma,
const MagickRealType pixel)
2950 scale=PerceptibleReciprocal(white_point-black_point);
2951 level_pixel=QuantumRange*gamma_pow(scale*((
double) pixel-black_point),
2952 PerceptibleReciprocal(gamma));
2953 return(level_pixel);
2956 MagickExport MagickBooleanType LevelImageChannel(
Image *image,
2957 const ChannelType channel,
const double black_point,
const double white_point,
2960 #define LevelImageTag "Level/Image"
2983 assert(image != (
Image *) NULL);
2984 assert(image->signature == MagickCoreSignature);
2985 if (IsEventLogging() != MagickFalse)
2986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2987 if (image->storage_class == PseudoClass)
2988 for (i=0; i < (ssize_t) image->colors; i++)
2993 if ((channel & RedChannel) != 0)
2994 image->colormap[i].red=(Quantum) ClampToQuantum(LevelPixel(black_point,
2995 white_point,gamma,(MagickRealType) image->colormap[i].red));
2996 if ((channel & GreenChannel) != 0)
2997 image->colormap[i].green=(Quantum) ClampToQuantum(LevelPixel(
2998 black_point,white_point,gamma,(MagickRealType)
2999 image->colormap[i].green));
3000 if ((channel & BlueChannel) != 0)
3001 image->colormap[i].blue=(Quantum) ClampToQuantum(LevelPixel(black_point,
3002 white_point,gamma,(MagickRealType) image->colormap[i].blue));
3003 if ((channel & OpacityChannel) != 0)
3004 image->colormap[i].opacity=(Quantum) (QuantumRange-(Quantum)
3005 ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3006 (MagickRealType) (QuantumRange-image->colormap[i].opacity))));
3013 exception=(&image->exception);
3014 image_view=AcquireAuthenticCacheView(image,exception);
3015 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3016 #pragma omp parallel for schedule(static) shared(progress,status) \
3017 magick_number_threads(image,image,image->rows,1)
3019 for (y=0; y < (ssize_t) image->rows; y++)
3022 *magick_restrict indexes;
3030 if (status == MagickFalse)
3032 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3038 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3039 for (x=0; x < (ssize_t) image->columns; x++)
3041 if ((channel & RedChannel) != 0)
3042 SetPixelRed(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3043 (MagickRealType) GetPixelRed(q))));
3044 if ((channel & GreenChannel) != 0)
3045 SetPixelGreen(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3046 (MagickRealType) GetPixelGreen(q))));
3047 if ((channel & BlueChannel) != 0)
3048 SetPixelBlue(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3049 (MagickRealType) GetPixelBlue(q))));
3050 if (((channel & OpacityChannel) != 0) &&
3051 (image->matte != MagickFalse))
3052 SetPixelAlpha(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3053 (MagickRealType) GetPixelAlpha(q))));
3054 if (((channel & IndexChannel) != 0) &&
3055 (image->colorspace == CMYKColorspace))
3056 SetPixelIndex(indexes+x,ClampToQuantum(LevelPixel(black_point,
3057 white_point,gamma,(MagickRealType) GetPixelIndex(indexes+x))));
3060 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3062 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3067 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3071 proceed=SetImageProgress(image,LevelImageTag,progress,image->rows);
3072 if (proceed == MagickFalse)
3076 image_view=DestroyCacheView(image_view);
3077 (void) ClampImage(image);
3124 MagickExport MagickBooleanType LevelizeImage(
Image *image,
3125 const double black_point,
const double white_point,
const double gamma)
3130 status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
3135 MagickExport MagickBooleanType LevelizeImageChannel(
Image *image,
3136 const ChannelType channel,
const double black_point,
const double white_point,
3139 #define LevelizeImageTag "Levelize/Image"
3140 #define LevelizeValue(x) ClampToQuantum(((MagickRealType) gamma_pow((double) \
3141 (QuantumScale*(x)),gamma))*(white_point-black_point)+black_point)
3164 assert(image != (
Image *) NULL);
3165 assert(image->signature == MagickCoreSignature);
3166 if (IsEventLogging() != MagickFalse)
3167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3168 if (image->storage_class == PseudoClass)
3169 for (i=0; i < (ssize_t) image->colors; i++)
3174 if ((channel & RedChannel) != 0)
3175 image->colormap[i].red=LevelizeValue(image->colormap[i].red);
3176 if ((channel & GreenChannel) != 0)
3177 image->colormap[i].green=LevelizeValue(image->colormap[i].green);
3178 if ((channel & BlueChannel) != 0)
3179 image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
3180 if ((channel & OpacityChannel) != 0)
3181 image->colormap[i].opacity=(Quantum) (QuantumRange-LevelizeValue(
3182 QuantumRange-image->colormap[i].opacity));
3189 exception=(&image->exception);
3190 image_view=AcquireAuthenticCacheView(image,exception);
3191 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3192 #pragma omp parallel for schedule(static) shared(progress,status) \
3193 magick_number_threads(image,image,image->rows,1)
3195 for (y=0; y < (ssize_t) image->rows; y++)
3198 *magick_restrict indexes;
3206 if (status == MagickFalse)
3208 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3214 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3215 for (x=0; x < (ssize_t) image->columns; x++)
3217 if ((channel & RedChannel) != 0)
3218 SetPixelRed(q,LevelizeValue(GetPixelRed(q)));
3219 if ((channel & GreenChannel) != 0)
3220 SetPixelGreen(q,LevelizeValue(GetPixelGreen(q)));
3221 if ((channel & BlueChannel) != 0)
3222 SetPixelBlue(q,LevelizeValue(GetPixelBlue(q)));
3223 if (((channel & OpacityChannel) != 0) &&
3224 (image->matte != MagickFalse))
3225 SetPixelAlpha(q,LevelizeValue(GetPixelAlpha(q)));
3226 if (((channel & IndexChannel) != 0) &&
3227 (image->colorspace == CMYKColorspace))
3228 SetPixelIndex(indexes+x,LevelizeValue(GetPixelIndex(indexes+x)));
3231 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3233 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3238 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3242 proceed=SetImageProgress(image,LevelizeImageTag,progress,image->rows);
3243 if (proceed == MagickFalse)
3247 image_view=DestroyCacheView(image_view);
3296 MagickExport MagickBooleanType LevelColorsImage(
Image *image,
3298 const MagickBooleanType invert)
3303 status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
3308 MagickExport MagickBooleanType LevelColorsImageChannel(
Image *image,
3318 assert(image != (
Image *) NULL);
3319 assert(image->signature == MagickCoreSignature);
3320 if (IsEventLogging() != MagickFalse)
3321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3322 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3323 ((IsGrayColorspace(black_color->colorspace) != MagickFalse) ||
3324 (IsGrayColorspace(white_color->colorspace) != MagickFalse)))
3325 (
void) SetImageColorspace(image,sRGBColorspace);
3327 if (invert == MagickFalse)
3329 if ((channel & RedChannel) != 0)
3330 status&=LevelImageChannel(image,RedChannel,black_color->red,
3331 white_color->red,(
double) 1.0);
3332 if ((channel & GreenChannel) != 0)
3333 status&=LevelImageChannel(image,GreenChannel,black_color->green,
3334 white_color->green,(
double) 1.0);
3335 if ((channel & BlueChannel) != 0)
3336 status&=LevelImageChannel(image,BlueChannel,black_color->blue,
3337 white_color->blue,(
double) 1.0);
3338 if (((channel & OpacityChannel) != 0) &&
3339 (image->matte != MagickFalse))
3340 status&=LevelImageChannel(image,OpacityChannel,black_color->opacity,
3341 white_color->opacity,(
double) 1.0);
3342 if (((channel & IndexChannel) != 0) &&
3343 (image->colorspace == CMYKColorspace))
3344 status&=LevelImageChannel(image,IndexChannel,black_color->index,
3345 white_color->index,(
double) 1.0);
3349 if ((channel & RedChannel) != 0)
3350 status&=LevelizeImageChannel(image,RedChannel,black_color->red,
3351 white_color->red,(
double) 1.0);
3352 if ((channel & GreenChannel) != 0)
3353 status&=LevelizeImageChannel(image,GreenChannel,black_color->green,
3354 white_color->green,(
double) 1.0);
3355 if ((channel & BlueChannel) != 0)
3356 status&=LevelizeImageChannel(image,BlueChannel,black_color->blue,
3357 white_color->blue,(
double) 1.0);
3358 if (((channel & OpacityChannel) != 0) &&
3359 (image->matte != MagickFalse))
3360 status&=LevelizeImageChannel(image,OpacityChannel,black_color->opacity,
3361 white_color->opacity,(
double) 1.0);
3362 if (((channel & IndexChannel) != 0) &&
3363 (image->colorspace == CMYKColorspace))
3364 status&=LevelizeImageChannel(image,IndexChannel,black_color->index,
3365 white_color->index,(
double) 1.0);
3367 return(status == 0 ? MagickFalse : MagickTrue);
3398 MagickExport MagickBooleanType LinearStretchImage(
Image *image,
3399 const double black_point,
const double white_point)
3401 #define LinearStretchImageTag "LinearStretch/Image"
3421 assert(image != (
Image *) NULL);
3422 assert(image->signature == MagickCoreSignature);
3423 exception=(&image->exception);
3424 histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
3425 sizeof(*histogram));
3426 if (histogram == (MagickRealType *) NULL)
3427 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
3432 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
3433 for (y=0; y < (ssize_t) image->rows; y++)
3441 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3444 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3446 histogram[ScaleQuantumToMap(ClampToQuantum(GetPixelIntensity(image,p)))]++;
3454 for (black=0; black < (ssize_t) MaxMap; black++)
3456 intensity+=histogram[black];
3457 if (intensity >= black_point)
3461 for (white=(ssize_t) MaxMap; white != 0; white--)
3463 intensity+=histogram[white];
3464 if (intensity >= white_point)
3467 histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
3468 status=LevelImageChannel(image,DefaultChannels,(
double)
3469 ScaleMapToQuantum(black),(
double) ScaleMapToQuantum(white),1.0);
3503 static inline void ModulateHCL(
const double percent_hue,
3504 const double percent_chroma,
const double percent_luma,Quantum *red,
3505 Quantum *green,Quantum *blue)
3515 ConvertRGBToHCL(*red,*green,*blue,&hue,&chroma,&luma);
3516 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3517 chroma*=0.01*percent_chroma;
3518 luma*=0.01*percent_luma;
3519 ConvertHCLToRGB(hue,chroma,luma,red,green,blue);
3522 static inline void ModulateHCLp(
const double percent_hue,
3523 const double percent_chroma,
const double percent_luma,Quantum *red,
3524 Quantum *green,Quantum *blue)
3534 ConvertRGBToHCLp(*red,*green,*blue,&hue,&chroma,&luma);
3535 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3536 chroma*=0.01*percent_chroma;
3537 luma*=0.01*percent_luma;
3538 ConvertHCLpToRGB(hue,chroma,luma,red,green,blue);
3541 static inline void ModulateHSB(
const double percent_hue,
3542 const double percent_saturation,
const double percent_brightness,Quantum *red,
3543 Quantum *green,Quantum *blue)
3553 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
3554 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3555 saturation*=0.01*percent_saturation;
3556 brightness*=0.01*percent_brightness;
3557 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
3560 static inline void ModulateHSI(
const double percent_hue,
3561 const double percent_saturation,
const double percent_intensity,Quantum *red,
3562 Quantum *green,Quantum *blue)
3572 ConvertRGBToHSI(*red,*green,*blue,&hue,&saturation,&intensity);
3573 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3574 saturation*=0.01*percent_saturation;
3575 intensity*=0.01*percent_intensity;
3576 ConvertHSIToRGB(hue,saturation,intensity,red,green,blue);
3579 static inline void ModulateHSL(
const double percent_hue,
3580 const double percent_saturation,
const double percent_lightness,Quantum *red,
3581 Quantum *green,Quantum *blue)
3591 ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
3592 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3593 saturation*=0.01*percent_saturation;
3594 lightness*=0.01*percent_lightness;
3595 ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
3598 static inline void ModulateHSV(
const double percent_hue,
3599 const double percent_saturation,
const double percent_value,Quantum *red,
3600 Quantum *green,Quantum *blue)
3610 ConvertRGBToHSV(*red,*green,*blue,&hue,&saturation,&value);
3611 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3612 saturation*=0.01*percent_saturation;
3613 value*=0.01*percent_value;
3614 ConvertHSVToRGB(hue,saturation,value,red,green,blue);
3617 static inline void ModulateHWB(
const double percent_hue,
3618 const double percent_whiteness,
const double percent_blackness,Quantum *red,
3619 Quantum *green,Quantum *blue)
3629 ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
3630 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3631 blackness*=0.01*percent_blackness;
3632 whiteness*=0.01*percent_whiteness;
3633 ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
3636 static inline void ModulateLCHab(
const double percent_luma,
3637 const double percent_chroma,
const double percent_hue,Quantum *red,
3638 Quantum *green,Quantum *blue)
3648 ConvertRGBToLCHab(*red,*green,*blue,&luma,&chroma,&hue);
3649 luma*=0.01*percent_luma;
3650 chroma*=0.01*percent_chroma;
3651 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3652 ConvertLCHabToRGB(luma,chroma,hue,red,green,blue);
3655 static inline void ModulateLCHuv(
const double percent_luma,
3656 const double percent_chroma,
const double percent_hue,Quantum *red,
3657 Quantum *green,Quantum *blue)
3667 ConvertRGBToLCHuv(*red,*green,*blue,&luma,&chroma,&hue);
3668 luma*=0.01*percent_luma;
3669 chroma*=0.01*percent_chroma;
3670 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3671 ConvertLCHuvToRGB(luma,chroma,hue,red,green,blue);
3674 MagickExport MagickBooleanType ModulateImage(
Image *image,
const char *modulate)
3676 #define ModulateImageTag "Modulate/Image"
3688 percent_brightness = 100.0,
3689 percent_hue = 100.0,
3690 percent_saturation = 100.0;
3716 assert(image != (
Image *) NULL);
3717 assert(image->signature == MagickCoreSignature);
3718 if (IsEventLogging() != MagickFalse)
3719 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3720 if (modulate == (
char *) NULL)
3721 return(MagickFalse);
3722 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3723 (
void) SetImageColorspace(image,sRGBColorspace);
3724 flags=ParseGeometry(modulate,&geometry_info);
3725 if ((flags & RhoValue) != 0)
3726 percent_brightness=geometry_info.rho;
3727 if ((flags & SigmaValue) != 0)
3728 percent_saturation=geometry_info.sigma;
3729 if ((flags & XiValue) != 0)
3730 percent_hue=geometry_info.xi;
3731 colorspace=UndefinedColorspace;
3732 artifact=GetImageArtifact(image,
"modulate:colorspace");
3733 if (artifact != (
const char *) NULL)
3734 colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
3735 MagickFalse,artifact);
3736 if (image->storage_class == PseudoClass)
3737 for (i=0; i < (ssize_t) image->colors; i++)
3747 red=image->colormap[i].red;
3748 green=image->colormap[i].green;
3749 blue=image->colormap[i].blue;
3754 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3758 case HCLpColorspace:
3760 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3766 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3772 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3779 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3785 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3791 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3795 case LCHabColorspace:
3798 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3802 case LCHuvColorspace:
3804 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3809 image->colormap[i].red=red;
3810 image->colormap[i].green=green;
3811 image->colormap[i].blue=blue;
3819 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3820 status=AccelerateModulateImage(image,percent_brightness,percent_hue,
3821 percent_saturation,colorspace,&image->exception);
3822 if (status != MagickFalse)
3827 exception=(&image->exception);
3828 image_view=AcquireAuthenticCacheView(image,exception);
3829 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3830 #pragma omp parallel for schedule(static) shared(progress,status) \
3831 magick_number_threads(image,image,image->rows,1)
3833 for (y=0; y < (ssize_t) image->rows; y++)
3841 if (status == MagickFalse)
3843 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3849 for (x=0; x < (ssize_t) image->columns; x++)
3857 green=GetPixelGreen(q);
3858 blue=GetPixelBlue(q);
3863 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3867 case HCLpColorspace:
3869 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3875 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3881 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3888 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3894 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3900 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3904 case LCHabColorspace:
3906 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3911 case LCHuvColorspace:
3913 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3919 SetPixelGreen(q,green);
3920 SetPixelBlue(q,blue);
3923 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3925 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3930 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3934 proceed=SetImageProgress(image,ModulateImageTag,progress,image->rows);
3935 if (proceed == MagickFalse)
3939 image_view=DestroyCacheView(image_view);
3974 MagickExport MagickBooleanType NegateImage(
Image *image,
3975 const MagickBooleanType grayscale)
3980 status=NegateImageChannel(image,DefaultChannels,grayscale);
3984 MagickExport MagickBooleanType NegateImageChannel(
Image *image,
3985 const ChannelType channel,
const MagickBooleanType grayscale)
3987 #define NegateImageTag "Negate/Image"
4007 assert(image != (
Image *) NULL);
4008 assert(image->signature == MagickCoreSignature);
4009 if (IsEventLogging() != MagickFalse)
4010 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4011 if (image->storage_class == PseudoClass)
4016 for (i=0; i < (ssize_t) image->colors; i++)
4018 if (grayscale != MagickFalse)
4019 if ((image->colormap[i].red != image->colormap[i].green) ||
4020 (image->colormap[i].green != image->colormap[i].blue))
4022 if ((channel & RedChannel) != 0)
4023 image->colormap[i].red=QuantumRange-image->colormap[i].red;
4024 if ((channel & GreenChannel) != 0)
4025 image->colormap[i].green=QuantumRange-image->colormap[i].green;
4026 if ((channel & BlueChannel) != 0)
4027 image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
4035 exception=(&image->exception);
4036 image_view=AcquireAuthenticCacheView(image,exception);
4037 if (grayscale != MagickFalse)
4039 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4040 #pragma omp parallel for schedule(static) shared(progress,status) \
4041 magick_number_threads(image,image,image->rows,1)
4043 for (y=0; y < (ssize_t) image->rows; y++)
4049 *magick_restrict indexes;
4057 if (status == MagickFalse)
4059 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4066 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4067 for (x=0; x < (ssize_t) image->columns; x++)
4069 if ((GetPixelRed(q) != GetPixelGreen(q)) ||
4070 (GetPixelGreen(q) != GetPixelBlue(q)))
4075 if ((channel & RedChannel) != 0)
4076 SetPixelRed(q,QuantumRange-GetPixelRed(q));
4077 if ((channel & GreenChannel) != 0)
4078 SetPixelGreen(q,QuantumRange-GetPixelGreen(q));
4079 if ((channel & BlueChannel) != 0)
4080 SetPixelBlue(q,QuantumRange-GetPixelBlue(q));
4081 if ((channel & OpacityChannel) != 0)
4082 SetPixelOpacity(q,QuantumRange-GetPixelOpacity(q));
4083 if (((channel & IndexChannel) != 0) &&
4084 (image->colorspace == CMYKColorspace))
4085 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4088 sync=SyncCacheViewAuthenticPixels(image_view,exception);
4089 if (sync == MagickFalse)
4091 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4096 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4100 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4101 if (proceed == MagickFalse)
4105 image_view=DestroyCacheView(image_view);
4111 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4112 #pragma omp parallel for schedule(static) shared(progress,status) \
4113 magick_number_threads(image,image,image->rows,1)
4115 for (y=0; y < (ssize_t) image->rows; y++)
4118 *magick_restrict indexes;
4126 if (status == MagickFalse)
4128 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4134 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4135 if (channel == DefaultChannels)
4136 for (x=0; x < (ssize_t) image->columns; x++)
4138 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4139 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4140 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4143 for (x=0; x < (ssize_t) image->columns; x++)
4145 if ((channel & RedChannel) != 0)
4146 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4147 if ((channel & GreenChannel) != 0)
4148 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4149 if ((channel & BlueChannel) != 0)
4150 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4151 if ((channel & OpacityChannel) != 0)
4152 SetPixelOpacity(q+x,QuantumRange-GetPixelOpacity(q+x));
4154 if (((channel & IndexChannel) != 0) &&
4155 (image->colorspace == CMYKColorspace))
4156 for (x=0; x < (ssize_t) image->columns; x++)
4157 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4158 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4160 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4165 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4169 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4170 if (proceed == MagickFalse)
4174 image_view=DestroyCacheView(image_view);
4207 MagickExport MagickBooleanType NormalizeImage(
Image *image)
4212 status=NormalizeImageChannel(image,DefaultChannels);
4216 MagickExport MagickBooleanType NormalizeImageChannel(
Image *image,
4217 const ChannelType channel)
4223 black_point=0.02*image->columns*image->rows;
4224 white_point=0.99*image->columns*image->rows;
4225 return(ContrastStretchImageChannel(image,channel,black_point,white_point));
4294 #if defined(MAGICKCORE_HAVE_ATANH)
4295 #define Sigmoidal(a,b,x) ( tanh((0.5*(a))*((x)-(b))) )
4297 #define Sigmoidal(a,b,x) ( 1.0/(1.0+exp((a)*((b)-(x)))) )
4316 #define ScaledSigmoidal(a,b,x) ( \
4317 (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \
4318 (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) )
4328 static inline double InverseScaledSigmoidal(
const double a,
const double b,
4331 const double sig0=Sigmoidal(a,b,0.0);
4332 const double sig1=Sigmoidal(a,b,1.0);
4333 const double argument=(sig1-sig0)*x+sig0;
4334 const double clamped=
4336 #if defined(MAGICKCORE_HAVE_ATANH)
4337 argument < -1+MagickEpsilon
4341 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4343 return(b+(2.0/a)*atanh(clamped));
4345 argument < MagickEpsilon
4349 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4351 return(b-log(1.0/clamped-1.0)/a);
4355 MagickExport MagickBooleanType SigmoidalContrastImage(
Image *image,
4356 const MagickBooleanType sharpen,
const char *levels)
4367 flags=ParseGeometry(levels,&geometry_info);
4368 if ((flags & SigmaValue) == 0)
4369 geometry_info.sigma=1.0*QuantumRange/2.0;
4370 if ((flags & PercentValue) != 0)
4371 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
4372 status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
4373 geometry_info.rho,geometry_info.sigma);
4377 MagickExport MagickBooleanType SigmoidalContrastImageChannel(
Image *image,
4378 const ChannelType channel,
const MagickBooleanType sharpen,
4379 const double contrast,
const double midpoint)
4381 #define SigmoidalContrastImageTag "SigmoidalContrast/Image"
4408 if (contrast < MagickEpsilon)
4413 assert(image != (
Image *) NULL);
4414 assert(image->signature == MagickCoreSignature);
4415 if (IsEventLogging() != MagickFalse)
4416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4417 exception=(&image->exception);
4418 sigmoidal_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
4419 sizeof(*sigmoidal_map));
4420 if (sigmoidal_map == (MagickRealType *) NULL)
4421 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
4423 (void) memset(sigmoidal_map,0,(MaxMap+1)*
sizeof(*sigmoidal_map));
4424 if (sharpen != MagickFalse)
4425 for (i=0; i <= (ssize_t) MaxMap; i++)
4426 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
4427 (MaxMap*ScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4430 for (i=0; i <= (ssize_t) MaxMap; i++)
4431 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType) (
4432 MaxMap*InverseScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4437 if (image->storage_class == PseudoClass)
4438 for (i=0; i < (ssize_t) image->colors; i++)
4440 if ((channel & RedChannel) != 0)
4441 image->colormap[i].red=ClampToQuantum(sigmoidal_map[
4442 ScaleQuantumToMap(image->colormap[i].red)]);
4443 if ((channel & GreenChannel) != 0)
4444 image->colormap[i].green=ClampToQuantum(sigmoidal_map[
4445 ScaleQuantumToMap(image->colormap[i].green)]);
4446 if ((channel & BlueChannel) != 0)
4447 image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
4448 ScaleQuantumToMap(image->colormap[i].blue)]);
4449 if ((channel & OpacityChannel) != 0)
4450 image->colormap[i].opacity=ClampToQuantum(sigmoidal_map[
4451 ScaleQuantumToMap(image->colormap[i].opacity)]);
4458 image_view=AcquireAuthenticCacheView(image,exception);
4459 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4460 #pragma omp parallel for schedule(static) shared(progress,status) \
4461 magick_number_threads(image,image,image->rows,1)
4463 for (y=0; y < (ssize_t) image->rows; y++)
4466 *magick_restrict indexes;
4474 if (status == MagickFalse)
4476 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4482 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4483 for (x=0; x < (ssize_t) image->columns; x++)
4485 if ((channel & RedChannel) != 0)
4486 SetPixelRed(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4488 if ((channel & GreenChannel) != 0)
4489 SetPixelGreen(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4490 GetPixelGreen(q))]));
4491 if ((channel & BlueChannel) != 0)
4492 SetPixelBlue(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4493 GetPixelBlue(q))]));
4494 if ((channel & OpacityChannel) != 0)
4495 SetPixelOpacity(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4496 GetPixelOpacity(q))]));
4497 if (((channel & IndexChannel) != 0) &&
4498 (image->colorspace == CMYKColorspace))
4499 SetPixelIndex(indexes+x,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4500 GetPixelIndex(indexes+x))]));
4503 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4505 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4510 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4514 proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress,
4516 if (proceed == MagickFalse)
4520 image_view=DestroyCacheView(image_view);
4521 sigmoidal_map=(MagickRealType *) RelinquishMagickMemory(sigmoidal_map);