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"
297 assert(image != (
Image *) NULL);
298 assert(image->signature == MagickCoreSignature);
299 if (IsEventLogging() != MagickFalse)
300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
301 slope=100.0*PerceptibleReciprocal(100.0-contrast);
303 slope=0.01*contrast+1.0;
304 intercept=(0.01*brightness-0.5)*slope+0.5;
305 coefficients[0]=slope;
306 coefficients[1]=intercept;
307 status=FunctionImageChannel(image,channel,PolynomialFunction,2,coefficients,
355 MagickExport MagickBooleanType ColorDecisionListImage(
Image *image,
356 const char *color_correction_collection)
358 #define ColorDecisionListCorrectImageTag "ColorDecisionList/Image"
360 typedef struct _Correction
368 typedef struct _ColorCorrection
383 token[MaxTextExtent];
419 assert(image != (
Image *) NULL);
420 assert(image->signature == MagickCoreSignature);
421 if (IsEventLogging() != MagickFalse)
422 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
423 if (color_correction_collection == (
const char *) NULL)
425 exception=(&image->exception);
426 ccc=NewXMLTree((
const char *) color_correction_collection,&image->exception);
429 cc=GetXMLTreeChild(ccc,
"ColorCorrection");
432 ccc=DestroyXMLTree(ccc);
435 color_correction.red.slope=1.0;
436 color_correction.red.offset=0.0;
437 color_correction.red.power=1.0;
438 color_correction.green.slope=1.0;
439 color_correction.green.offset=0.0;
440 color_correction.green.power=1.0;
441 color_correction.blue.slope=1.0;
442 color_correction.blue.offset=0.0;
443 color_correction.blue.power=1.0;
444 color_correction.saturation=0.0;
445 sop=GetXMLTreeChild(cc,
"SOPNode");
453 slope=GetXMLTreeChild(sop,
"Slope");
456 content=GetXMLTreeContent(slope);
457 p=(
const char *) content;
458 for (i=0; (*p !=
'\0') && (i < 3); i++)
460 (void) GetNextToken(p,&p,MaxTextExtent,token);
462 (void) GetNextToken(p,&p,MaxTextExtent,token);
467 color_correction.red.slope=StringToDouble(token,(
char **) NULL);
472 color_correction.green.slope=StringToDouble(token,
478 color_correction.blue.slope=StringToDouble(token,
485 offset=GetXMLTreeChild(sop,
"Offset");
488 content=GetXMLTreeContent(offset);
489 p=(
const char *) content;
490 for (i=0; (*p !=
'\0') && (i < 3); i++)
492 (void) GetNextToken(p,&p,MaxTextExtent,token);
494 (void) GetNextToken(p,&p,MaxTextExtent,token);
499 color_correction.red.offset=StringToDouble(token,
505 color_correction.green.offset=StringToDouble(token,
511 color_correction.blue.offset=StringToDouble(token,
518 power=GetXMLTreeChild(sop,
"Power");
521 content=GetXMLTreeContent(power);
522 p=(
const char *) content;
523 for (i=0; (*p !=
'\0') && (i < 3); i++)
525 (void) GetNextToken(p,&p,MaxTextExtent,token);
527 (void) GetNextToken(p,&p,MaxTextExtent,token);
532 color_correction.red.power=StringToDouble(token,(
char **) NULL);
537 color_correction.green.power=StringToDouble(token,
543 color_correction.blue.power=StringToDouble(token,
551 sat=GetXMLTreeChild(cc,
"SATNode");
557 saturation=GetXMLTreeChild(sat,
"Saturation");
560 content=GetXMLTreeContent(saturation);
561 p=(
const char *) content;
562 (void) GetNextToken(p,&p,MaxTextExtent,token);
563 color_correction.saturation=StringToDouble(token,(
char **) NULL);
566 ccc=DestroyXMLTree(ccc);
567 if (image->debug != MagickFalse)
569 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
570 " Color Correction Collection:");
571 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
572 " color_correction.red.slope: %g",color_correction.red.slope);
573 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
574 " color_correction.red.offset: %g",color_correction.red.offset);
575 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
576 " color_correction.red.power: %g",color_correction.red.power);
577 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
578 " color_correction.green.slope: %g",color_correction.green.slope);
579 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
580 " color_correction.green.offset: %g",color_correction.green.offset);
581 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
582 " color_correction.green.power: %g",color_correction.green.power);
583 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
584 " color_correction.blue.slope: %g",color_correction.blue.slope);
585 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
586 " color_correction.blue.offset: %g",color_correction.blue.offset);
587 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
588 " color_correction.blue.power: %g",color_correction.blue.power);
589 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
590 " color_correction.saturation: %g",color_correction.saturation);
592 cdl_map=(
PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*cdl_map));
594 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
596 for (i=0; i <= (ssize_t) MaxMap; i++)
598 cdl_map[i].red=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
599 MagickRealType) (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
600 color_correction.red.offset,color_correction.red.power)))));
601 cdl_map[i].green=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
602 MagickRealType) (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
603 color_correction.green.offset,color_correction.green.power)))));
604 cdl_map[i].blue=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
605 MagickRealType) (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
606 color_correction.blue.offset,color_correction.blue.power)))));
608 if (image->storage_class == PseudoClass)
613 for (i=0; i < (ssize_t) image->colors; i++)
618 luma=0.212656*image->colormap[i].red+0.715158*image->colormap[i].green+
619 0.072186*image->colormap[i].blue;
620 image->colormap[i].red=ClampToQuantum(luma+color_correction.saturation*
621 cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
622 image->colormap[i].green=ClampToQuantum(luma+
623 color_correction.saturation*cdl_map[ScaleQuantumToMap(
624 image->colormap[i].green)].green-luma);
625 image->colormap[i].blue=ClampToQuantum(luma+color_correction.saturation*
626 cdl_map[ScaleQuantumToMap(image->colormap[i].blue)].blue-luma);
634 image_view=AcquireAuthenticCacheView(image,exception);
635 #if defined(MAGICKCORE_OPENMP_SUPPORT)
636 #pragma omp parallel for schedule(static) shared(progress,status) \
637 magick_number_threads(image,image,image->rows,1)
639 for (y=0; y < (ssize_t) image->rows; y++)
650 if (status == MagickFalse)
652 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
658 for (x=0; x < (ssize_t) image->columns; x++)
660 luma=0.212656*GetPixelRed(q)+0.715158*GetPixelGreen(q)+
661 0.072186*GetPixelBlue(q);
662 SetPixelRed(q,ClampToQuantum(luma+color_correction.saturation*
663 (cdl_map[ScaleQuantumToMap(GetPixelRed(q))].red-luma)));
664 SetPixelGreen(q,ClampToQuantum(luma+color_correction.saturation*
665 (cdl_map[ScaleQuantumToMap(GetPixelGreen(q))].green-luma)));
666 SetPixelBlue(q,ClampToQuantum(luma+color_correction.saturation*
667 (cdl_map[ScaleQuantumToMap(GetPixelBlue(q))].blue-luma)));
670 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
672 if (image->progress_monitor != (MagickProgressMonitor) NULL)
677 #if defined(MAGICKCORE_OPENMP_SUPPORT)
681 proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
682 progress,image->rows);
683 if (proceed == MagickFalse)
687 image_view=DestroyCacheView(image_view);
688 cdl_map=(
PixelPacket *) RelinquishMagickMemory(cdl_map);
737 MagickExport MagickBooleanType ClutImage(
Image *image,
const Image *clut_image)
739 return(ClutImageChannel(image,DefaultChannels,clut_image));
742 MagickExport MagickBooleanType ClutImageChannel(
Image *image,
743 const ChannelType channel,
const Image *clut_image)
745 #define ClutImageTag "Clut/Image"
770 assert(image != (
Image *) NULL);
771 assert(image->signature == MagickCoreSignature);
772 assert(clut_image != (
Image *) NULL);
773 assert(clut_image->signature == MagickCoreSignature);
774 if (IsEventLogging() != MagickFalse)
775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
776 exception=(&image->exception);
777 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
779 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
780 (IsGrayColorspace(clut_image->colorspace) == MagickFalse))
781 (void) SetImageColorspace(image,sRGBColorspace);
785 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
792 adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
793 clut_view=AcquireAuthenticCacheView(clut_image,exception);
794 for (i=0; i <= (ssize_t) MaxMap; i++)
796 GetMagickPixelPacket(clut_image,clut_map+i);
797 status=InterpolateMagickPixelPacket(clut_image,clut_view,
798 UndefinedInterpolatePixel,(
double) i*(clut_image->columns-adjust)/MaxMap,
799 (
double) i*(clut_image->rows-adjust)/MaxMap,clut_map+i,exception);
800 if (status == MagickFalse)
803 clut_view=DestroyCacheView(clut_view);
804 image_view=AcquireAuthenticCacheView(image,exception);
805 #if defined(MAGICKCORE_OPENMP_SUPPORT)
806 #pragma omp parallel for schedule(static) shared(progress,status) \
807 magick_number_threads(image,image,image->rows,1)
809 for (y=0; y < (ssize_t) image->rows; y++)
815 *magick_restrict indexes;
823 if (status == MagickFalse)
825 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
831 indexes=GetCacheViewAuthenticIndexQueue(image_view);
832 GetMagickPixelPacket(image,&pixel);
833 for (x=0; x < (ssize_t) image->columns; x++)
835 SetMagickPixelPacket(image,q,indexes+x,&pixel);
836 if ((channel & RedChannel) != 0)
837 SetPixelRed(q,ClampPixelRed(clut_map+
838 ScaleQuantumToMap(GetPixelRed(q))));
839 if ((channel & GreenChannel) != 0)
840 SetPixelGreen(q,ClampPixelGreen(clut_map+
841 ScaleQuantumToMap(GetPixelGreen(q))));
842 if ((channel & BlueChannel) != 0)
843 SetPixelBlue(q,ClampPixelBlue(clut_map+
844 ScaleQuantumToMap(GetPixelBlue(q))));
845 if ((channel & OpacityChannel) != 0)
847 if (clut_image->matte == MagickFalse)
848 SetPixelAlpha(q,MagickPixelIntensityToQuantum(clut_map+
849 ScaleQuantumToMap((Quantum) GetPixelAlpha(q))));
851 if (image->matte == MagickFalse)
852 SetPixelOpacity(q,ClampPixelOpacity(clut_map+
853 ScaleQuantumToMap((Quantum) MagickPixelIntensity(&pixel))));
855 SetPixelOpacity(q,ClampPixelOpacity(
856 clut_map+ScaleQuantumToMap(GetPixelOpacity(q))));
858 if (((channel & IndexChannel) != 0) &&
859 (image->colorspace == CMYKColorspace))
860 SetPixelIndex(indexes+x,ClampToQuantum((clut_map+(ssize_t)
861 GetPixelIndex(indexes+x))->index));
864 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
866 if (image->progress_monitor != (MagickProgressMonitor) NULL)
871 #if defined(MAGICKCORE_OPENMP_SUPPORT)
875 proceed=SetImageProgress(image,ClutImageTag,progress,image->rows);
876 if (proceed == MagickFalse)
880 image_view=DestroyCacheView(image_view);
882 if ((clut_image->matte != MagickFalse) && ((channel & OpacityChannel) != 0))
883 (
void) SetImageAlphaChannel(image,ActivateAlphaChannel);
915 static inline void Contrast(
const int sign,Quantum *red,Quantum *green,
926 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
927 brightness+=0.5*sign*(0.5*(sin((
double) (MagickPI*(brightness-0.5)))+1.0)-
929 if (brightness > 1.0)
932 if (brightness < 0.0)
934 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
937 MagickExport MagickBooleanType ContrastImage(
Image *image,
938 const MagickBooleanType sharpen)
940 #define ContrastImageTag "Contrast/Image"
962 assert(image != (
Image *) NULL);
963 assert(image->signature == MagickCoreSignature);
964 if (IsEventLogging() != MagickFalse)
965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
966 sign=sharpen != MagickFalse ? 1 : -1;
967 if (image->storage_class == PseudoClass)
972 for (i=0; i < (ssize_t) image->colors; i++)
973 Contrast(sign,&image->colormap[i].red,&image->colormap[i].green,
974 &image->colormap[i].blue);
979 #if defined(MAGICKCORE_OPENCL_SUPPORT)
980 status=AccelerateContrastImage(image,sharpen,&image->exception);
981 if (status != MagickFalse)
986 exception=(&image->exception);
987 image_view=AcquireAuthenticCacheView(image,exception);
988 #if defined(MAGICKCORE_OPENMP_SUPPORT)
989 #pragma omp parallel for schedule(static) shared(progress,status) \
990 magick_number_threads(image,image,image->rows,1)
992 for (y=0; y < (ssize_t) image->rows; y++)
1005 if (status == MagickFalse)
1007 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1013 for (x=0; x < (ssize_t) image->columns; x++)
1016 green=GetPixelGreen(q);
1017 blue=GetPixelBlue(q);
1018 Contrast(sign,&red,&green,&blue);
1020 SetPixelGreen(q,green);
1021 SetPixelBlue(q,blue);
1024 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1026 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1031 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1035 proceed=SetImageProgress(image,ContrastImageTag,progress,image->rows);
1036 if (proceed == MagickFalse)
1040 image_view=DestroyCacheView(image_view);
1085 MagickExport MagickBooleanType ContrastStretchImage(
Image *image,
1090 white_point = (double) image->columns*image->rows;
1104 if (levels == (
char *) NULL)
1105 return(MagickFalse);
1106 flags=ParseGeometry(levels,&geometry_info);
1107 if ((flags & RhoValue) != 0)
1108 black_point=geometry_info.rho;
1109 if ((flags & SigmaValue) != 0)
1110 white_point=geometry_info.sigma;
1111 if ((flags & PercentValue) != 0)
1113 black_point*=(double) QuantumRange/100.0;
1114 white_point*=(double) QuantumRange/100.0;
1116 if ((flags & SigmaValue) == 0)
1117 white_point=(
double) image->columns*image->rows-black_point;
1118 status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
1123 MagickExport MagickBooleanType ContrastStretchImageChannel(
Image *image,
1124 const ChannelType channel,
const double black_point,
const double white_point)
1126 #define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
1127 #define ContrastStretchImageTag "ContrastStretch/Image"
1161 assert(image != (
Image *) NULL);
1162 assert(image->signature == MagickCoreSignature);
1163 if (IsEventLogging() != MagickFalse)
1164 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1165 exception=(&image->exception);
1167 #if defined(MAGICKCORE_OPENCL_SUPPORT) && 0
1169 status=AccelerateContrastStretchImageChannel(image,channel,black_point,
1170 white_point,&image->exception);
1171 if (status != MagickFalse)
1175 sizeof(*histogram));
1177 sizeof(*stretch_map));
1185 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1191 if (SetImageGray(image,exception) != MagickFalse)
1192 (void) SetImageColorspace(image,GRAYColorspace);
1194 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1195 image_view=AcquireAuthenticCacheView(image,exception);
1196 for (y=0; y < (ssize_t) image->rows; y++)
1202 *magick_restrict indexes;
1207 if (status == MagickFalse)
1209 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1215 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1216 if ((channel & SyncChannels) != 0)
1217 for (x=0; x < (ssize_t) image->columns; x++)
1222 intensity=ClampToQuantum(GetPixelIntensity(image,p));
1223 histogram[ScaleQuantumToMap(intensity)].red++;
1224 histogram[ScaleQuantumToMap(intensity)].green++;
1225 histogram[ScaleQuantumToMap(intensity)].blue++;
1226 histogram[ScaleQuantumToMap(intensity)].index++;
1230 for (x=0; x < (ssize_t) image->columns; x++)
1232 if ((channel & RedChannel) != 0)
1233 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1234 if ((channel & GreenChannel) != 0)
1235 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1236 if ((channel & BlueChannel) != 0)
1237 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1238 if ((channel & OpacityChannel) != 0)
1239 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1240 if (((channel & IndexChannel) != 0) &&
1241 (image->colorspace == CMYKColorspace))
1242 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1250 white.red=MaxRange(QuantumRange);
1251 if ((channel & RedChannel) != 0)
1254 for (i=0; i <= (ssize_t) MaxMap; i++)
1256 intensity+=histogram[i].red;
1257 if (intensity > black_point)
1260 black.red=(MagickRealType) i;
1262 for (i=(ssize_t) MaxMap; i != 0; i--)
1264 intensity+=histogram[i].red;
1265 if (intensity > ((
double) image->columns*image->rows-white_point))
1268 white.red=(MagickRealType) i;
1271 white.green=MaxRange(QuantumRange);
1272 if ((channel & GreenChannel) != 0)
1275 for (i=0; i <= (ssize_t) MaxMap; i++)
1277 intensity+=histogram[i].green;
1278 if (intensity > black_point)
1281 black.green=(MagickRealType) i;
1283 for (i=(ssize_t) MaxMap; i != 0; i--)
1285 intensity+=histogram[i].green;
1286 if (intensity > ((
double) image->columns*image->rows-white_point))
1289 white.green=(MagickRealType) i;
1292 white.blue=MaxRange(QuantumRange);
1293 if ((channel & BlueChannel) != 0)
1296 for (i=0; i <= (ssize_t) MaxMap; i++)
1298 intensity+=histogram[i].blue;
1299 if (intensity > black_point)
1302 black.blue=(MagickRealType) i;
1304 for (i=(ssize_t) MaxMap; i != 0; i--)
1306 intensity+=histogram[i].blue;
1307 if (intensity > ((
double) image->columns*image->rows-white_point))
1310 white.blue=(MagickRealType) i;
1313 white.opacity=MaxRange(QuantumRange);
1314 if ((channel & OpacityChannel) != 0)
1317 for (i=0; i <= (ssize_t) MaxMap; i++)
1319 intensity+=histogram[i].opacity;
1320 if (intensity > black_point)
1323 black.opacity=(MagickRealType) i;
1325 for (i=(ssize_t) MaxMap; i != 0; i--)
1327 intensity+=histogram[i].opacity;
1328 if (intensity > ((
double) image->columns*image->rows-white_point))
1331 white.opacity=(MagickRealType) i;
1334 white.index=MaxRange(QuantumRange);
1335 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1338 for (i=0; i <= (ssize_t) MaxMap; i++)
1340 intensity+=histogram[i].index;
1341 if (intensity > black_point)
1344 black.index=(MagickRealType) i;
1346 for (i=(ssize_t) MaxMap; i != 0; i--)
1348 intensity+=histogram[i].index;
1349 if (intensity > ((
double) image->columns*image->rows-white_point))
1352 white.index=(MagickRealType) i;
1358 (void) memset(stretch_map,0,(MaxMap+1)*
sizeof(*stretch_map));
1359 for (i=0; i <= (ssize_t) MaxMap; i++)
1361 if ((channel & RedChannel) != 0)
1363 if (i < (ssize_t) black.red)
1364 stretch_map[i].red=(Quantum) 0;
1366 if (i > (ssize_t) white.red)
1367 stretch_map[i].red=QuantumRange;
1369 if (black.red != white.red)
1370 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
1371 (i-black.red)/(white.red-black.red)));
1373 if ((channel & GreenChannel) != 0)
1375 if (i < (ssize_t) black.green)
1376 stretch_map[i].green=0;
1378 if (i > (ssize_t) white.green)
1379 stretch_map[i].green=QuantumRange;
1381 if (black.green != white.green)
1382 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
1383 (i-black.green)/(white.green-black.green)));
1385 if ((channel & BlueChannel) != 0)
1387 if (i < (ssize_t) black.blue)
1388 stretch_map[i].blue=0;
1390 if (i > (ssize_t) white.blue)
1391 stretch_map[i].blue= QuantumRange;
1393 if (black.blue != white.blue)
1394 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
1395 (i-black.blue)/(white.blue-black.blue)));
1397 if ((channel & OpacityChannel) != 0)
1399 if (i < (ssize_t) black.opacity)
1400 stretch_map[i].opacity=0;
1402 if (i > (ssize_t) white.opacity)
1403 stretch_map[i].opacity=QuantumRange;
1405 if (black.opacity != white.opacity)
1406 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
1407 (i-black.opacity)/(white.opacity-black.opacity)));
1409 if (((channel & IndexChannel) != 0) &&
1410 (image->colorspace == CMYKColorspace))
1412 if (i < (ssize_t) black.index)
1413 stretch_map[i].index=0;
1415 if (i > (ssize_t) white.index)
1416 stretch_map[i].index=QuantumRange;
1418 if (black.index != white.index)
1419 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
1420 (i-black.index)/(white.index-black.index)));
1426 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
1427 (image->colorspace == CMYKColorspace)))
1428 image->storage_class=DirectClass;
1429 if (image->storage_class == PseudoClass)
1434 for (i=0; i < (ssize_t) image->colors; i++)
1436 if ((channel & RedChannel) != 0)
1438 if (black.red != white.red)
1439 image->colormap[i].red=stretch_map[
1440 ScaleQuantumToMap(image->colormap[i].red)].red;
1442 if ((channel & GreenChannel) != 0)
1444 if (black.green != white.green)
1445 image->colormap[i].green=stretch_map[
1446 ScaleQuantumToMap(image->colormap[i].green)].green;
1448 if ((channel & BlueChannel) != 0)
1450 if (black.blue != white.blue)
1451 image->colormap[i].blue=stretch_map[
1452 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1454 if ((channel & OpacityChannel) != 0)
1456 if (black.opacity != white.opacity)
1457 image->colormap[i].opacity=stretch_map[
1458 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1467 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1468 #pragma omp parallel for schedule(static) shared(progress,status) \
1469 magick_number_threads(image,image,image->rows,1)
1471 for (y=0; y < (ssize_t) image->rows; y++)
1474 *magick_restrict indexes;
1482 if (status == MagickFalse)
1484 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1490 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1491 for (x=0; x < (ssize_t) image->columns; x++)
1493 if ((channel & RedChannel) != 0)
1495 if (black.red != white.red)
1496 SetPixelRed(q,stretch_map[
1497 ScaleQuantumToMap(GetPixelRed(q))].red);
1499 if ((channel & GreenChannel) != 0)
1501 if (black.green != white.green)
1502 SetPixelGreen(q,stretch_map[
1503 ScaleQuantumToMap(GetPixelGreen(q))].green);
1505 if ((channel & BlueChannel) != 0)
1507 if (black.blue != white.blue)
1508 SetPixelBlue(q,stretch_map[
1509 ScaleQuantumToMap(GetPixelBlue(q))].blue);
1511 if ((channel & OpacityChannel) != 0)
1513 if (black.opacity != white.opacity)
1514 SetPixelOpacity(q,stretch_map[
1515 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
1517 if (((channel & IndexChannel) != 0) &&
1518 (image->colorspace == CMYKColorspace))
1520 if (black.index != white.index)
1521 SetPixelIndex(indexes+x,stretch_map[
1522 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
1526 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1528 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1533 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1537 proceed=SetImageProgress(image,ContrastStretchImageTag,progress,
1539 if (proceed == MagickFalse)
1543 image_view=DestroyCacheView(image_view);
1575 #define EnhancePixel(weight) \
1576 mean=QuantumScale*((double) GetPixelRed(r)+pixel.red)/2.0; \
1577 distance=QuantumScale*((double) GetPixelRed(r)-pixel.red); \
1578 distance_squared=(4.0+mean)*distance*distance; \
1579 mean=QuantumScale*((double) GetPixelGreen(r)+pixel.green)/2.0; \
1580 distance=QuantumScale*((double) GetPixelGreen(r)-pixel.green); \
1581 distance_squared+=(7.0-mean)*distance*distance; \
1582 mean=QuantumScale*((double) GetPixelBlue(r)+pixel.blue)/2.0; \
1583 distance=QuantumScale*((double) GetPixelBlue(r)-pixel.blue); \
1584 distance_squared+=(5.0-mean)*distance*distance; \
1585 mean=QuantumScale*((double) GetPixelOpacity(r)+pixel.opacity)/2.0; \
1586 distance=QuantumScale*((double) GetPixelOpacity(r)-pixel.opacity); \
1587 distance_squared+=(5.0-mean)*distance*distance; \
1588 if (distance_squared < 0.069) \
1590 aggregate.red+=(weight)*GetPixelRed(r); \
1591 aggregate.green+=(weight)*GetPixelGreen(r); \
1592 aggregate.blue+=(weight)*GetPixelBlue(r); \
1593 aggregate.opacity+=(weight)*GetPixelOpacity(r); \
1594 total_weight+=(weight); \
1597 #define EnhanceImageTag "Enhance/Image"
1621 assert(image != (
const Image *) NULL);
1622 assert(image->signature == MagickCoreSignature);
1623 if (IsEventLogging() != MagickFalse)
1624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1626 assert(exception->signature == MagickCoreSignature);
1627 if ((image->columns < 5) || (image->rows < 5))
1628 return((
Image *) NULL);
1629 enhance_image=CloneImage(image,0,0,MagickTrue,exception);
1630 if (enhance_image == (
Image *) NULL)
1631 return((
Image *) NULL);
1632 if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
1634 InheritException(exception,&enhance_image->exception);
1635 enhance_image=DestroyImage(enhance_image);
1636 return((
Image *) NULL);
1643 (void) memset(&zero,0,
sizeof(zero));
1644 image_view=AcquireAuthenticCacheView(image,exception);
1645 enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
1646 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1647 #pragma omp parallel for schedule(static) shared(progress,status) \
1648 magick_number_threads(image,enhance_image,image->rows,1)
1650 for (y=0; y < (ssize_t) image->rows; y++)
1664 if (status == MagickFalse)
1666 p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
1667 q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
1674 for (x=0; x < (ssize_t) image->columns; x++)
1696 r=p+2*(image->columns+4)+2;
1699 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1700 EnhancePixel(8.0); EnhancePixel(5.0);
1701 r=p+(image->columns+4);
1702 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1703 EnhancePixel(20.0); EnhancePixel(8.0);
1704 r=p+2*(image->columns+4);
1705 EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
1706 EnhancePixel(40.0); EnhancePixel(10.0);
1707 r=p+3*(image->columns+4);
1708 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1709 EnhancePixel(20.0); EnhancePixel(8.0);
1710 r=p+4*(image->columns+4);
1711 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1712 EnhancePixel(8.0); EnhancePixel(5.0);
1713 if (total_weight > MagickEpsilon)
1715 SetPixelRed(q,(aggregate.red+(total_weight/2)-1)/total_weight);
1716 SetPixelGreen(q,(aggregate.green+(total_weight/2)-1)/total_weight);
1717 SetPixelBlue(q,(aggregate.blue+(total_weight/2)-1)/total_weight);
1718 SetPixelOpacity(q,(aggregate.opacity+(total_weight/2)-1)/
1724 if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
1726 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1731 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1735 proceed=SetImageProgress(image,EnhanceImageTag,progress,image->rows);
1736 if (proceed == MagickFalse)
1740 enhance_view=DestroyCacheView(enhance_view);
1741 image_view=DestroyCacheView(image_view);
1742 if (status == MagickFalse)
1743 enhance_image=DestroyImage(enhance_image);
1744 return(enhance_image);
1774 MagickExport MagickBooleanType EqualizeImage(
Image *image)
1776 return(EqualizeImageChannel(image,DefaultChannels));
1779 MagickExport MagickBooleanType EqualizeImageChannel(
Image *image,
1780 const ChannelType channel)
1782 #define EqualizeImageTag "Equalize/Image"
1812 assert(image != (
Image *) NULL);
1813 assert(image->signature == MagickCoreSignature);
1814 if (IsEventLogging() != MagickFalse)
1815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1816 exception=(&image->exception);
1818 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1820 status=AccelerateEqualizeImage(image,channel,&image->exception);
1821 if (status != MagickFalse)
1828 sizeof(*equalize_map));
1830 sizeof(*histogram));
1843 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1849 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1850 image_view=AcquireVirtualCacheView(image,exception);
1851 for (y=0; y < (ssize_t) image->rows; y++)
1854 *magick_restrict indexes;
1862 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1865 indexes=GetCacheViewVirtualIndexQueue(image_view);
1866 if ((channel & SyncChannels) != 0)
1867 for (x=0; x < (ssize_t) image->columns; x++)
1869 MagickRealType intensity=GetPixelIntensity(image,p);
1870 histogram[ScaleQuantumToMap(ClampToQuantum(intensity))].red++;
1874 for (x=0; x < (ssize_t) image->columns; x++)
1876 if ((channel & RedChannel) != 0)
1877 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1878 if ((channel & GreenChannel) != 0)
1879 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1880 if ((channel & BlueChannel) != 0)
1881 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1882 if ((channel & OpacityChannel) != 0)
1883 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1884 if (((channel & IndexChannel) != 0) &&
1885 (image->colorspace == CMYKColorspace))
1886 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1890 image_view=DestroyCacheView(image_view);
1894 (void) memset(&intensity,0,
sizeof(intensity));
1895 for (i=0; i <= (ssize_t) MaxMap; i++)
1897 if ((channel & SyncChannels) != 0)
1899 intensity.red+=histogram[i].red;
1903 if ((channel & RedChannel) != 0)
1904 intensity.red+=histogram[i].red;
1905 if ((channel & GreenChannel) != 0)
1906 intensity.green+=histogram[i].green;
1907 if ((channel & BlueChannel) != 0)
1908 intensity.blue+=histogram[i].blue;
1909 if ((channel & OpacityChannel) != 0)
1910 intensity.opacity+=histogram[i].opacity;
1911 if (((channel & IndexChannel) != 0) &&
1912 (image->colorspace == CMYKColorspace))
1913 intensity.index+=histogram[i].index;
1917 white=map[(int) MaxMap];
1918 (void) memset(equalize_map,0,(MaxMap+1)*
sizeof(*equalize_map));
1919 for (i=0; i <= (ssize_t) MaxMap; i++)
1921 if ((channel & SyncChannels) != 0)
1923 if (white.red != black.red)
1924 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1925 (map[i].red-black.red))/(white.red-black.red)));
1928 if (((channel & RedChannel) != 0) && (white.red != black.red))
1929 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1930 (map[i].red-black.red))/(white.red-black.red)));
1931 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1932 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1933 (map[i].green-black.green))/(white.green-black.green)));
1934 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1935 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1936 (map[i].blue-black.blue))/(white.blue-black.blue)));
1937 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
1938 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1939 (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
1940 if ((((channel & IndexChannel) != 0) &&
1941 (image->colorspace == CMYKColorspace)) &&
1942 (white.index != black.index))
1943 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1944 (map[i].index-black.index))/(white.index-black.index)));
1948 if (image->storage_class == PseudoClass)
1953 for (i=0; i < (ssize_t) image->colors; i++)
1955 if ((channel & SyncChannels) != 0)
1957 if (white.red != black.red)
1959 image->colormap[i].red=equalize_map[
1960 ScaleQuantumToMap(image->colormap[i].red)].red;
1961 image->colormap[i].green=equalize_map[
1962 ScaleQuantumToMap(image->colormap[i].green)].red;
1963 image->colormap[i].blue=equalize_map[
1964 ScaleQuantumToMap(image->colormap[i].blue)].red;
1965 image->colormap[i].opacity=equalize_map[
1966 ScaleQuantumToMap(image->colormap[i].opacity)].red;
1970 if (((channel & RedChannel) != 0) && (white.red != black.red))
1971 image->colormap[i].red=equalize_map[
1972 ScaleQuantumToMap(image->colormap[i].red)].red;
1973 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1974 image->colormap[i].green=equalize_map[
1975 ScaleQuantumToMap(image->colormap[i].green)].green;
1976 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1977 image->colormap[i].blue=equalize_map[
1978 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1979 if (((channel & OpacityChannel) != 0) &&
1980 (white.opacity != black.opacity))
1981 image->colormap[i].opacity=equalize_map[
1982 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1990 image_view=AcquireAuthenticCacheView(image,exception);
1991 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1992 #pragma omp parallel for schedule(static) shared(progress,status) \
1993 magick_number_threads(image,image,image->rows,1)
1995 for (y=0; y < (ssize_t) image->rows; y++)
1998 *magick_restrict indexes;
2006 if (status == MagickFalse)
2008 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2014 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2015 for (x=0; x < (ssize_t) image->columns; x++)
2017 if ((channel & SyncChannels) != 0)
2019 if (white.red != black.red)
2021 SetPixelRed(q,equalize_map[
2022 ScaleQuantumToMap(GetPixelRed(q))].red);
2023 SetPixelGreen(q,equalize_map[
2024 ScaleQuantumToMap(GetPixelGreen(q))].red);
2025 SetPixelBlue(q,equalize_map[
2026 ScaleQuantumToMap(GetPixelBlue(q))].red);
2027 SetPixelOpacity(q,equalize_map[
2028 ScaleQuantumToMap(GetPixelOpacity(q))].red);
2029 if (image->colorspace == CMYKColorspace)
2030 SetPixelIndex(indexes+x,equalize_map[
2031 ScaleQuantumToMap(GetPixelIndex(indexes+x))].red);
2036 if (((channel & RedChannel) != 0) && (white.red != black.red))
2037 SetPixelRed(q,equalize_map[
2038 ScaleQuantumToMap(GetPixelRed(q))].red);
2039 if (((channel & GreenChannel) != 0) && (white.green != black.green))
2040 SetPixelGreen(q,equalize_map[
2041 ScaleQuantumToMap(GetPixelGreen(q))].green);
2042 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
2043 SetPixelBlue(q,equalize_map[
2044 ScaleQuantumToMap(GetPixelBlue(q))].blue);
2045 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
2046 SetPixelOpacity(q,equalize_map[
2047 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
2048 if ((((channel & IndexChannel) != 0) &&
2049 (image->colorspace == CMYKColorspace)) &&
2050 (white.index != black.index))
2051 SetPixelIndex(indexes+x,equalize_map[
2052 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
2055 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2057 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2062 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2066 proceed=SetImageProgress(image,EqualizeImageTag,progress,image->rows);
2067 if (proceed == MagickFalse)
2071 image_view=DestroyCacheView(image_view);
2114 static inline double gamma_pow(
const double value,
const double gamma)
2116 return(value < 0.0 ? value : pow(value,gamma));
2119 MagickExport MagickBooleanType GammaImage(
Image *image,
const char *level)
2131 assert(image != (
Image *) NULL);
2132 assert(image->signature == MagickCoreSignature);
2133 if (IsEventLogging() != MagickFalse)
2134 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2135 if (level == (
char *) NULL)
2136 return(MagickFalse);
2138 flags=ParseGeometry(level,&geometry_info);
2139 if ((flags & RhoValue) != 0)
2140 gamma.red=geometry_info.rho;
2141 gamma.green=gamma.red;
2142 if ((flags & SigmaValue) != 0)
2143 gamma.green=geometry_info.sigma;
2144 gamma.blue=gamma.red;
2145 if ((flags & XiValue) != 0)
2146 gamma.blue=geometry_info.xi;
2147 if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
2149 if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
2150 status=GammaImageChannel(image,(ChannelType) (RedChannel | GreenChannel |
2151 BlueChannel),(
double) gamma.red);
2154 status=GammaImageChannel(image,RedChannel,(
double) gamma.red);
2155 status&=GammaImageChannel(image,GreenChannel,(
double) gamma.green);
2156 status&=GammaImageChannel(image,BlueChannel,(
double) gamma.blue);
2158 return(status != 0 ? MagickTrue : MagickFalse);
2161 MagickExport MagickBooleanType GammaImageChannel(
Image *image,
2162 const ChannelType channel,
const double gamma)
2164 #define GammaImageTag "Gamma/Image"
2190 assert(image != (
Image *) NULL);
2191 assert(image->signature == MagickCoreSignature);
2192 if (IsEventLogging() != MagickFalse)
2193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2194 exception=(&image->exception);
2197 gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*gamma_map));
2198 if (gamma_map == (Quantum *) NULL)
2199 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2201 (void) memset(gamma_map,0,(MaxMap+1)*
sizeof(*gamma_map));
2203 for (i=0; i <= (ssize_t) MaxMap; i++)
2204 gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
2205 MagickRealType) (MaxMap*pow((
double) i/MaxMap,
2206 PerceptibleReciprocal(gamma)))));
2207 if (image->storage_class == PseudoClass)
2212 for (i=0; i < (ssize_t) image->colors; i++)
2214 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2215 if ((channel & RedChannel) != 0)
2216 image->colormap[i].red=gamma_map[ScaleQuantumToMap(
2217 image->colormap[i].red)];
2218 if ((channel & GreenChannel) != 0)
2219 image->colormap[i].green=gamma_map[ScaleQuantumToMap(
2220 image->colormap[i].green)];
2221 if ((channel & BlueChannel) != 0)
2222 image->colormap[i].blue=gamma_map[ScaleQuantumToMap(
2223 image->colormap[i].blue)];
2224 if ((channel & OpacityChannel) != 0)
2226 if (image->matte == MagickFalse)
2227 image->colormap[i].opacity=gamma_map[ScaleQuantumToMap(
2228 image->colormap[i].opacity)];
2230 image->colormap[i].opacity=QuantumRange-gamma_map[
2231 ScaleQuantumToMap((Quantum) (QuantumRange-
2232 image->colormap[i].opacity))];
2235 if ((channel & RedChannel) != 0)
2236 image->colormap[i].red=QuantumRange*gamma_pow(QuantumScale*
2237 image->colormap[i].red,PerceptibleReciprocal(gamma));
2238 if ((channel & GreenChannel) != 0)
2239 image->colormap[i].green=QuantumRange*gamma_pow(QuantumScale*
2240 image->colormap[i].green,PerceptibleReciprocal(gamma));
2241 if ((channel & BlueChannel) != 0)
2242 image->colormap[i].blue=QuantumRange*gamma_pow(QuantumScale*
2243 image->colormap[i].blue,PerceptibleReciprocal(gamma));
2244 if ((channel & OpacityChannel) != 0)
2246 if (image->matte == MagickFalse)
2247 image->colormap[i].opacity=QuantumRange*gamma_pow(QuantumScale*
2248 image->colormap[i].opacity,PerceptibleReciprocal(gamma));
2250 image->colormap[i].opacity=QuantumRange-QuantumRange*gamma_pow(
2251 QuantumScale*(QuantumRange-image->colormap[i].opacity),1.0/
2262 image_view=AcquireAuthenticCacheView(image,exception);
2263 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2264 #pragma omp parallel for schedule(static) shared(progress,status) \
2265 magick_number_threads(image,image,image->rows,1)
2267 for (y=0; y < (ssize_t) image->rows; y++)
2270 *magick_restrict indexes;
2278 if (status == MagickFalse)
2280 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2286 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2287 for (x=0; x < (ssize_t) image->columns; x++)
2289 #if !defined(MAGICKCORE_HDRI_SUPPORT)
2290 if ((channel & SyncChannels) != 0)
2292 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2293 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2294 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2298 if ((channel & RedChannel) != 0)
2299 SetPixelRed(q,gamma_map[ScaleQuantumToMap(GetPixelRed(q))]);
2300 if ((channel & GreenChannel) != 0)
2301 SetPixelGreen(q,gamma_map[ScaleQuantumToMap(GetPixelGreen(q))]);
2302 if ((channel & BlueChannel) != 0)
2303 SetPixelBlue(q,gamma_map[ScaleQuantumToMap(GetPixelBlue(q))]);
2304 if ((channel & OpacityChannel) != 0)
2306 if (image->matte == MagickFalse)
2307 SetPixelOpacity(q,gamma_map[ScaleQuantumToMap(
2308 GetPixelOpacity(q))]);
2310 SetPixelAlpha(q,gamma_map[ScaleQuantumToMap((Quantum)
2311 GetPixelAlpha(q))]);
2315 if ((channel & SyncChannels) != 0)
2317 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2318 PerceptibleReciprocal(gamma)));
2319 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*GetPixelGreen(q),
2320 PerceptibleReciprocal(gamma)));
2321 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2322 PerceptibleReciprocal(gamma)));
2326 if ((channel & RedChannel) != 0)
2327 SetPixelRed(q,QuantumRange*gamma_pow(QuantumScale*GetPixelRed(q),
2328 PerceptibleReciprocal(gamma)));
2329 if ((channel & GreenChannel) != 0)
2330 SetPixelGreen(q,QuantumRange*gamma_pow(QuantumScale*
2331 GetPixelGreen(q),PerceptibleReciprocal(gamma)));
2332 if ((channel & BlueChannel) != 0)
2333 SetPixelBlue(q,QuantumRange*gamma_pow(QuantumScale*GetPixelBlue(q),
2334 PerceptibleReciprocal(gamma)));
2335 if ((channel & OpacityChannel) != 0)
2337 if (image->matte == MagickFalse)
2338 SetPixelOpacity(q,QuantumRange*gamma_pow(QuantumScale*
2339 GetPixelOpacity(q),PerceptibleReciprocal(gamma)));
2341 SetPixelAlpha(q,QuantumRange*gamma_pow(QuantumScale*
2342 GetPixelAlpha(q),PerceptibleReciprocal(gamma)));
2348 if (((channel & IndexChannel) != 0) &&
2349 (image->colorspace == CMYKColorspace))
2350 for (x=0; x < (ssize_t) image->columns; x++)
2351 SetPixelIndex(indexes+x,gamma_map[ScaleQuantumToMap(
2352 GetPixelIndex(indexes+x))]);
2353 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2355 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2360 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2364 proceed=SetImageProgress(image,GammaImageTag,progress,image->rows);
2365 if (proceed == MagickFalse)
2369 image_view=DestroyCacheView(image_view);
2370 gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
2371 if (image->gamma != 0.0)
2372 image->gamma*=gamma;
2401 MagickExport MagickBooleanType GrayscaleImage(
Image *image,
2402 const PixelIntensityMethod method)
2404 #define GrayscaleImageTag "Grayscale/Image"
2421 assert(image != (
Image *) NULL);
2422 assert(image->signature == MagickCoreSignature);
2423 if (IsEventLogging() != MagickFalse)
2424 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2425 if (image->storage_class == PseudoClass)
2427 if (SyncImage(image) == MagickFalse)
2428 return(MagickFalse);
2429 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2430 return(MagickFalse);
2438 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2439 if (AccelerateGrayscaleImage(image,method,&image->exception) != MagickFalse)
2441 image->intensity=method;
2442 image->type=GrayscaleType;
2443 if ((method == Rec601LuminancePixelIntensityMethod) ||
2444 (method == Rec709LuminancePixelIntensityMethod))
2445 return(SetImageColorspace(image,LinearGRAYColorspace));
2446 return(SetImageColorspace(image,GRAYColorspace));
2451 exception=(&image->exception);
2452 image_view=AcquireAuthenticCacheView(image,exception);
2453 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2454 #pragma omp parallel for schedule(static) shared(progress,status) \
2455 magick_number_threads(image,image,image->rows,1)
2457 for (y=0; y < (ssize_t) image->rows; y++)
2465 if (status == MagickFalse)
2467 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2473 for (x=0; x < (ssize_t) image->columns; x++)
2481 red=(MagickRealType) q->red;
2482 green=(MagickRealType) q->green;
2483 blue=(MagickRealType) q->blue;
2487 case AveragePixelIntensityMethod:
2489 intensity=(red+green+blue)/3.0;
2492 case BrightnessPixelIntensityMethod:
2494 intensity=MagickMax(MagickMax(red,green),blue);
2497 case LightnessPixelIntensityMethod:
2499 intensity=(MagickMin(MagickMin(red,green),blue)+
2500 MagickMax(MagickMax(red,green),blue))/2.0;
2503 case MSPixelIntensityMethod:
2505 intensity=(MagickRealType) (((
double) red*red+green*green+
2506 blue*blue)/(3.0*QuantumRange));
2509 case Rec601LumaPixelIntensityMethod:
2511 if (image->colorspace == RGBColorspace)
2513 red=EncodePixelGamma(red);
2514 green=EncodePixelGamma(green);
2515 blue=EncodePixelGamma(blue);
2517 intensity=0.298839*red+0.586811*green+0.114350*blue;
2520 case Rec601LuminancePixelIntensityMethod:
2522 if (image->colorspace == sRGBColorspace)
2524 red=DecodePixelGamma(red);
2525 green=DecodePixelGamma(green);
2526 blue=DecodePixelGamma(blue);
2528 intensity=0.298839*red+0.586811*green+0.114350*blue;
2531 case Rec709LumaPixelIntensityMethod:
2534 if (image->colorspace == RGBColorspace)
2536 red=EncodePixelGamma(red);
2537 green=EncodePixelGamma(green);
2538 blue=EncodePixelGamma(blue);
2540 intensity=0.212656*red+0.715158*green+0.072186*blue;
2543 case Rec709LuminancePixelIntensityMethod:
2545 if (image->colorspace == sRGBColorspace)
2547 red=DecodePixelGamma(red);
2548 green=DecodePixelGamma(green);
2549 blue=DecodePixelGamma(blue);
2551 intensity=0.212656*red+0.715158*green+0.072186*blue;
2554 case RMSPixelIntensityMethod:
2556 intensity=(MagickRealType) (sqrt((
double) red*red+green*green+
2557 blue*blue)/sqrt(3.0));
2561 SetPixelGray(q,ClampToQuantum(intensity));
2564 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2566 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2571 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2575 proceed=SetImageProgress(image,GrayscaleImageTag,progress,image->rows);
2576 if (proceed == MagickFalse)
2580 image_view=DestroyCacheView(image_view);
2581 image->intensity=method;
2582 image->type=GrayscaleType;
2583 if ((method == Rec601LuminancePixelIntensityMethod) ||
2584 (method == Rec709LuminancePixelIntensityMethod))
2585 return(SetImageColorspace(image,LinearGRAYColorspace));
2586 return(SetImageColorspace(image,GRAYColorspace));
2622 MagickExport MagickBooleanType HaldClutImage(
Image *image,
2623 const Image *hald_image)
2625 return(HaldClutImageChannel(image,DefaultChannels,hald_image));
2628 MagickExport MagickBooleanType HaldClutImageChannel(
Image *image,
2629 const ChannelType channel,
const Image *hald_image)
2631 #define HaldClutImageTag "Clut/Image"
2633 typedef struct _HaldInfo
2668 assert(image != (
Image *) NULL);
2669 assert(image->signature == MagickCoreSignature);
2670 if (IsEventLogging() != MagickFalse)
2671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2672 assert(hald_image != (
Image *) NULL);
2673 assert(hald_image->signature == MagickCoreSignature);
2674 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2675 return(MagickFalse);
2676 if (IsGrayColorspace(image->colorspace) != MagickFalse)
2677 (void) SetImageColorspace(image,sRGBColorspace);
2678 if (image->matte == MagickFalse)
2679 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
2685 length=(size_t) MagickMin((MagickRealType) hald_image->columns,
2686 (MagickRealType) hald_image->rows);
2687 for (level=2; (level*level*level) < length; level++) ;
2689 cube_size=level*level;
2690 width=(double) hald_image->columns;
2691 GetMagickPixelPacket(hald_image,&zero);
2692 exception=(&image->exception);
2693 image_view=AcquireAuthenticCacheView(image,exception);
2694 hald_view=AcquireAuthenticCacheView(hald_image,exception);
2695 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2696 #pragma omp parallel for schedule(static) shared(progress,status) \
2697 magick_number_threads(image,hald_image,image->rows,1)
2699 for (y=0; y < (ssize_t) image->rows; y++)
2716 *magick_restrict indexes;
2724 if (status == MagickFalse)
2726 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2732 indexes=GetCacheViewAuthenticIndexQueue(hald_view);
2738 for (x=0; x < (ssize_t) image->columns; x++)
2740 point.x=QuantumScale*(level-1.0)*GetPixelRed(q);
2741 point.y=QuantumScale*(level-1.0)*GetPixelGreen(q);
2742 point.z=QuantumScale*(level-1.0)*GetPixelBlue(q);
2743 offset=(double) (point.x+level*floor(point.y)+cube_size*floor(point.z));
2744 point.x-=floor(point.x);
2745 point.y-=floor(point.y);
2746 point.z-=floor(point.z);
2747 status=InterpolateMagickPixelPacket(image,hald_view,
2748 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2750 if (status == MagickFalse)
2752 status=InterpolateMagickPixelPacket(image,hald_view,
2753 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2754 width),&pixel2,exception);
2755 if (status == MagickFalse)
2758 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2759 area=(point.y < 0.5) ? 0.0 : 1.0;
2760 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2761 pixel2.opacity,area,&pixel3);
2763 status=InterpolateMagickPixelPacket(image,hald_view,
2764 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2766 if (status == MagickFalse)
2768 status=InterpolateMagickPixelPacket(image,hald_view,
2769 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2770 width),&pixel2,exception);
2771 if (status == MagickFalse)
2773 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2774 pixel2.opacity,area,&pixel4);
2776 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2777 area=(point.z < 0.5)? 0.0 : 1.0;
2778 MagickPixelCompositeAreaBlend(&pixel3,pixel3.opacity,&pixel4,
2779 pixel4.opacity,area,&pixel);
2780 if ((channel & RedChannel) != 0)
2781 SetPixelRed(q,ClampToQuantum(pixel.red));
2782 if ((channel & GreenChannel) != 0)
2783 SetPixelGreen(q,ClampToQuantum(pixel.green));
2784 if ((channel & BlueChannel) != 0)
2785 SetPixelBlue(q,ClampToQuantum(pixel.blue));
2786 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2787 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
2788 if (((channel & IndexChannel) != 0) &&
2789 (image->colorspace == CMYKColorspace))
2790 SetPixelIndex(indexes+x,ClampToQuantum(pixel.index));
2793 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2795 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2800 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2804 proceed=SetImageProgress(image,HaldClutImageTag,progress,image->rows);
2805 if (proceed == MagickFalse)
2809 hald_view=DestroyCacheView(hald_view);
2810 image_view=DestroyCacheView(image_view);
2855 MagickExport MagickBooleanType LevelImage(
Image *image,
const char *levels)
2860 white_point = (double) QuantumRange;
2874 if (levels == (
char *) NULL)
2875 return(MagickFalse);
2876 flags=ParseGeometry(levels,&geometry_info);
2877 if ((flags & RhoValue) != 0)
2878 black_point=geometry_info.rho;
2879 if ((flags & SigmaValue) != 0)
2880 white_point=geometry_info.sigma;
2881 if ((flags & XiValue) != 0)
2882 gamma=geometry_info.xi;
2883 if ((flags & PercentValue) != 0)
2885 black_point*=(double) image->columns*image->rows/100.0;
2886 white_point*=(
double) image->columns*image->rows/100.0;
2888 if ((flags & SigmaValue) == 0)
2889 white_point=(
double) QuantumRange-black_point;
2890 if ((flags & AspectValue ) == 0)
2891 status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
2894 status=LevelizeImage(image,black_point,white_point,gamma);
2941 static inline double LevelPixel(
const double black_point,
2942 const double white_point,
const double gamma,
const MagickRealType pixel)
2948 scale=PerceptibleReciprocal(white_point-black_point);
2949 level_pixel=QuantumRange*gamma_pow(scale*((
double) pixel-black_point),
2950 PerceptibleReciprocal(gamma));
2951 return(level_pixel);
2954 MagickExport MagickBooleanType LevelImageChannel(
Image *image,
2955 const ChannelType channel,
const double black_point,
const double white_point,
2958 #define LevelImageTag "Level/Image"
2981 assert(image != (
Image *) NULL);
2982 assert(image->signature == MagickCoreSignature);
2983 if (IsEventLogging() != MagickFalse)
2984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2985 if (image->storage_class == PseudoClass)
2986 for (i=0; i < (ssize_t) image->colors; i++)
2991 if ((channel & RedChannel) != 0)
2992 image->colormap[i].red=(Quantum) ClampToQuantum(LevelPixel(black_point,
2993 white_point,gamma,(MagickRealType) image->colormap[i].red));
2994 if ((channel & GreenChannel) != 0)
2995 image->colormap[i].green=(Quantum) ClampToQuantum(LevelPixel(
2996 black_point,white_point,gamma,(MagickRealType)
2997 image->colormap[i].green));
2998 if ((channel & BlueChannel) != 0)
2999 image->colormap[i].blue=(Quantum) ClampToQuantum(LevelPixel(black_point,
3000 white_point,gamma,(MagickRealType) image->colormap[i].blue));
3001 if ((channel & OpacityChannel) != 0)
3002 image->colormap[i].opacity=(Quantum) (QuantumRange-(Quantum)
3003 ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3004 (MagickRealType) (QuantumRange-image->colormap[i].opacity))));
3011 exception=(&image->exception);
3012 image_view=AcquireAuthenticCacheView(image,exception);
3013 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3014 #pragma omp parallel for schedule(static) shared(progress,status) \
3015 magick_number_threads(image,image,image->rows,1)
3017 for (y=0; y < (ssize_t) image->rows; y++)
3020 *magick_restrict indexes;
3028 if (status == MagickFalse)
3030 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3036 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3037 for (x=0; x < (ssize_t) image->columns; x++)
3039 if ((channel & RedChannel) != 0)
3040 SetPixelRed(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3041 (MagickRealType) GetPixelRed(q))));
3042 if ((channel & GreenChannel) != 0)
3043 SetPixelGreen(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3044 (MagickRealType) GetPixelGreen(q))));
3045 if ((channel & BlueChannel) != 0)
3046 SetPixelBlue(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3047 (MagickRealType) GetPixelBlue(q))));
3048 if (((channel & OpacityChannel) != 0) &&
3049 (image->matte != MagickFalse))
3050 SetPixelAlpha(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3051 (MagickRealType) GetPixelAlpha(q))));
3052 if (((channel & IndexChannel) != 0) &&
3053 (image->colorspace == CMYKColorspace))
3054 SetPixelIndex(indexes+x,ClampToQuantum(LevelPixel(black_point,
3055 white_point,gamma,(MagickRealType) GetPixelIndex(indexes+x))));
3058 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3060 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3065 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3069 proceed=SetImageProgress(image,LevelImageTag,progress,image->rows);
3070 if (proceed == MagickFalse)
3074 image_view=DestroyCacheView(image_view);
3075 (void) ClampImage(image);
3122 MagickExport MagickBooleanType LevelizeImage(
Image *image,
3123 const double black_point,
const double white_point,
const double gamma)
3128 status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
3133 MagickExport MagickBooleanType LevelizeImageChannel(
Image *image,
3134 const ChannelType channel,
const double black_point,
const double white_point,
3137 #define LevelizeImageTag "Levelize/Image"
3138 #define LevelizeValue(x) ClampToQuantum(((MagickRealType) gamma_pow((double) \
3139 (QuantumScale*(x)),gamma))*(white_point-black_point)+black_point)
3162 assert(image != (
Image *) NULL);
3163 assert(image->signature == MagickCoreSignature);
3164 if (IsEventLogging() != MagickFalse)
3165 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3166 if (image->storage_class == PseudoClass)
3167 for (i=0; i < (ssize_t) image->colors; i++)
3172 if ((channel & RedChannel) != 0)
3173 image->colormap[i].red=LevelizeValue(image->colormap[i].red);
3174 if ((channel & GreenChannel) != 0)
3175 image->colormap[i].green=LevelizeValue(image->colormap[i].green);
3176 if ((channel & BlueChannel) != 0)
3177 image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
3178 if ((channel & OpacityChannel) != 0)
3179 image->colormap[i].opacity=(Quantum) (QuantumRange-LevelizeValue(
3180 QuantumRange-image->colormap[i].opacity));
3187 exception=(&image->exception);
3188 image_view=AcquireAuthenticCacheView(image,exception);
3189 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3190 #pragma omp parallel for schedule(static) shared(progress,status) \
3191 magick_number_threads(image,image,image->rows,1)
3193 for (y=0; y < (ssize_t) image->rows; y++)
3196 *magick_restrict indexes;
3204 if (status == MagickFalse)
3206 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3212 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3213 for (x=0; x < (ssize_t) image->columns; x++)
3215 if ((channel & RedChannel) != 0)
3216 SetPixelRed(q,LevelizeValue(GetPixelRed(q)));
3217 if ((channel & GreenChannel) != 0)
3218 SetPixelGreen(q,LevelizeValue(GetPixelGreen(q)));
3219 if ((channel & BlueChannel) != 0)
3220 SetPixelBlue(q,LevelizeValue(GetPixelBlue(q)));
3221 if (((channel & OpacityChannel) != 0) &&
3222 (image->matte != MagickFalse))
3223 SetPixelAlpha(q,LevelizeValue(GetPixelAlpha(q)));
3224 if (((channel & IndexChannel) != 0) &&
3225 (image->colorspace == CMYKColorspace))
3226 SetPixelIndex(indexes+x,LevelizeValue(GetPixelIndex(indexes+x)));
3229 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3231 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3236 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3240 proceed=SetImageProgress(image,LevelizeImageTag,progress,image->rows);
3241 if (proceed == MagickFalse)
3245 image_view=DestroyCacheView(image_view);
3294 MagickExport MagickBooleanType LevelColorsImage(
Image *image,
3296 const MagickBooleanType invert)
3301 status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
3306 MagickExport MagickBooleanType LevelColorsImageChannel(
Image *image,
3316 assert(image != (
Image *) NULL);
3317 assert(image->signature == MagickCoreSignature);
3318 if (IsEventLogging() != MagickFalse)
3319 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3320 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3321 ((IsGrayColorspace(black_color->colorspace) != MagickFalse) ||
3322 (IsGrayColorspace(white_color->colorspace) != MagickFalse)))
3323 (
void) SetImageColorspace(image,sRGBColorspace);
3325 if (invert == MagickFalse)
3327 if ((channel & RedChannel) != 0)
3328 status&=LevelImageChannel(image,RedChannel,black_color->red,
3329 white_color->red,(
double) 1.0);
3330 if ((channel & GreenChannel) != 0)
3331 status&=LevelImageChannel(image,GreenChannel,black_color->green,
3332 white_color->green,(
double) 1.0);
3333 if ((channel & BlueChannel) != 0)
3334 status&=LevelImageChannel(image,BlueChannel,black_color->blue,
3335 white_color->blue,(
double) 1.0);
3336 if (((channel & OpacityChannel) != 0) &&
3337 (image->matte != MagickFalse))
3338 status&=LevelImageChannel(image,OpacityChannel,black_color->opacity,
3339 white_color->opacity,(
double) 1.0);
3340 if (((channel & IndexChannel) != 0) &&
3341 (image->colorspace == CMYKColorspace))
3342 status&=LevelImageChannel(image,IndexChannel,black_color->index,
3343 white_color->index,(
double) 1.0);
3347 if ((channel & RedChannel) != 0)
3348 status&=LevelizeImageChannel(image,RedChannel,black_color->red,
3349 white_color->red,(
double) 1.0);
3350 if ((channel & GreenChannel) != 0)
3351 status&=LevelizeImageChannel(image,GreenChannel,black_color->green,
3352 white_color->green,(
double) 1.0);
3353 if ((channel & BlueChannel) != 0)
3354 status&=LevelizeImageChannel(image,BlueChannel,black_color->blue,
3355 white_color->blue,(
double) 1.0);
3356 if (((channel & OpacityChannel) != 0) &&
3357 (image->matte != MagickFalse))
3358 status&=LevelizeImageChannel(image,OpacityChannel,black_color->opacity,
3359 white_color->opacity,(
double) 1.0);
3360 if (((channel & IndexChannel) != 0) &&
3361 (image->colorspace == CMYKColorspace))
3362 status&=LevelizeImageChannel(image,IndexChannel,black_color->index,
3363 white_color->index,(
double) 1.0);
3365 return(status == 0 ? MagickFalse : MagickTrue);
3396 MagickExport MagickBooleanType LinearStretchImage(
Image *image,
3397 const double black_point,
const double white_point)
3399 #define LinearStretchImageTag "LinearStretch/Image"
3419 assert(image != (
Image *) NULL);
3420 assert(image->signature == MagickCoreSignature);
3421 exception=(&image->exception);
3422 histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
3423 sizeof(*histogram));
3424 if (histogram == (MagickRealType *) NULL)
3425 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
3430 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
3431 for (y=0; y < (ssize_t) image->rows; y++)
3439 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3442 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3444 histogram[ScaleQuantumToMap(ClampToQuantum(GetPixelIntensity(image,p)))]++;
3452 for (black=0; black < (ssize_t) MaxMap; black++)
3454 intensity+=histogram[black];
3455 if (intensity >= black_point)
3459 for (white=(ssize_t) MaxMap; white != 0; white--)
3461 intensity+=histogram[white];
3462 if (intensity >= white_point)
3465 histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
3466 status=LevelImageChannel(image,DefaultChannels,(
double)
3467 ScaleMapToQuantum(black),(
double) ScaleMapToQuantum(white),1.0);
3501 static inline void ModulateHCL(
const double percent_hue,
3502 const double percent_chroma,
const double percent_luma,Quantum *red,
3503 Quantum *green,Quantum *blue)
3513 ConvertRGBToHCL(*red,*green,*blue,&hue,&chroma,&luma);
3514 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3515 chroma*=0.01*percent_chroma;
3516 luma*=0.01*percent_luma;
3517 ConvertHCLToRGB(hue,chroma,luma,red,green,blue);
3520 static inline void ModulateHCLp(
const double percent_hue,
3521 const double percent_chroma,
const double percent_luma,Quantum *red,
3522 Quantum *green,Quantum *blue)
3532 ConvertRGBToHCLp(*red,*green,*blue,&hue,&chroma,&luma);
3533 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3534 chroma*=0.01*percent_chroma;
3535 luma*=0.01*percent_luma;
3536 ConvertHCLpToRGB(hue,chroma,luma,red,green,blue);
3539 static inline void ModulateHSB(
const double percent_hue,
3540 const double percent_saturation,
const double percent_brightness,Quantum *red,
3541 Quantum *green,Quantum *blue)
3551 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
3552 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3553 saturation*=0.01*percent_saturation;
3554 brightness*=0.01*percent_brightness;
3555 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
3558 static inline void ModulateHSI(
const double percent_hue,
3559 const double percent_saturation,
const double percent_intensity,Quantum *red,
3560 Quantum *green,Quantum *blue)
3570 ConvertRGBToHSI(*red,*green,*blue,&hue,&saturation,&intensity);
3571 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3572 saturation*=0.01*percent_saturation;
3573 intensity*=0.01*percent_intensity;
3574 ConvertHSIToRGB(hue,saturation,intensity,red,green,blue);
3577 static inline void ModulateHSL(
const double percent_hue,
3578 const double percent_saturation,
const double percent_lightness,Quantum *red,
3579 Quantum *green,Quantum *blue)
3589 ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
3590 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3591 saturation*=0.01*percent_saturation;
3592 lightness*=0.01*percent_lightness;
3593 ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
3596 static inline void ModulateHSV(
const double percent_hue,
3597 const double percent_saturation,
const double percent_value,Quantum *red,
3598 Quantum *green,Quantum *blue)
3608 ConvertRGBToHSV(*red,*green,*blue,&hue,&saturation,&value);
3609 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3610 saturation*=0.01*percent_saturation;
3611 value*=0.01*percent_value;
3612 ConvertHSVToRGB(hue,saturation,value,red,green,blue);
3615 static inline void ModulateHWB(
const double percent_hue,
3616 const double percent_whiteness,
const double percent_blackness,Quantum *red,
3617 Quantum *green,Quantum *blue)
3627 ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
3628 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3629 blackness*=0.01*percent_blackness;
3630 whiteness*=0.01*percent_whiteness;
3631 ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
3634 static inline void ModulateLCHab(
const double percent_luma,
3635 const double percent_chroma,
const double percent_hue,Quantum *red,
3636 Quantum *green,Quantum *blue)
3646 ConvertRGBToLCHab(*red,*green,*blue,&luma,&chroma,&hue);
3647 luma*=0.01*percent_luma;
3648 chroma*=0.01*percent_chroma;
3649 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3650 ConvertLCHabToRGB(luma,chroma,hue,red,green,blue);
3653 static inline void ModulateLCHuv(
const double percent_luma,
3654 const double percent_chroma,
const double percent_hue,Quantum *red,
3655 Quantum *green,Quantum *blue)
3665 ConvertRGBToLCHuv(*red,*green,*blue,&luma,&chroma,&hue);
3666 luma*=0.01*percent_luma;
3667 chroma*=0.01*percent_chroma;
3668 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3669 ConvertLCHuvToRGB(luma,chroma,hue,red,green,blue);
3672 MagickExport MagickBooleanType ModulateImage(
Image *image,
const char *modulate)
3674 #define ModulateImageTag "Modulate/Image"
3686 percent_brightness = 100.0,
3687 percent_hue = 100.0,
3688 percent_saturation = 100.0;
3714 assert(image != (
Image *) NULL);
3715 assert(image->signature == MagickCoreSignature);
3716 if (IsEventLogging() != MagickFalse)
3717 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3718 if (modulate == (
char *) NULL)
3719 return(MagickFalse);
3720 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3721 (
void) SetImageColorspace(image,sRGBColorspace);
3722 flags=ParseGeometry(modulate,&geometry_info);
3723 if ((flags & RhoValue) != 0)
3724 percent_brightness=geometry_info.rho;
3725 if ((flags & SigmaValue) != 0)
3726 percent_saturation=geometry_info.sigma;
3727 if ((flags & XiValue) != 0)
3728 percent_hue=geometry_info.xi;
3729 colorspace=UndefinedColorspace;
3730 artifact=GetImageArtifact(image,
"modulate:colorspace");
3731 if (artifact != (
const char *) NULL)
3732 colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
3733 MagickFalse,artifact);
3734 if (image->storage_class == PseudoClass)
3735 for (i=0; i < (ssize_t) image->colors; i++)
3745 red=image->colormap[i].red;
3746 green=image->colormap[i].green;
3747 blue=image->colormap[i].blue;
3752 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3756 case HCLpColorspace:
3758 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3764 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3770 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3777 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3783 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3789 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3793 case LCHabColorspace:
3796 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3800 case LCHuvColorspace:
3802 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3807 image->colormap[i].red=red;
3808 image->colormap[i].green=green;
3809 image->colormap[i].blue=blue;
3817 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3818 status=AccelerateModulateImage(image,percent_brightness,percent_hue,
3819 percent_saturation,colorspace,&image->exception);
3820 if (status != MagickFalse)
3825 exception=(&image->exception);
3826 image_view=AcquireAuthenticCacheView(image,exception);
3827 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3828 #pragma omp parallel for schedule(static) shared(progress,status) \
3829 magick_number_threads(image,image,image->rows,1)
3831 for (y=0; y < (ssize_t) image->rows; y++)
3839 if (status == MagickFalse)
3841 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3847 for (x=0; x < (ssize_t) image->columns; x++)
3855 green=GetPixelGreen(q);
3856 blue=GetPixelBlue(q);
3861 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3865 case HCLpColorspace:
3867 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3873 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3879 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3886 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3892 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3898 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3902 case LCHabColorspace:
3904 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3909 case LCHuvColorspace:
3911 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3917 SetPixelGreen(q,green);
3918 SetPixelBlue(q,blue);
3921 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3923 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3928 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3932 proceed=SetImageProgress(image,ModulateImageTag,progress,image->rows);
3933 if (proceed == MagickFalse)
3937 image_view=DestroyCacheView(image_view);
3972 MagickExport MagickBooleanType NegateImage(
Image *image,
3973 const MagickBooleanType grayscale)
3978 status=NegateImageChannel(image,DefaultChannels,grayscale);
3982 MagickExport MagickBooleanType NegateImageChannel(
Image *image,
3983 const ChannelType channel,
const MagickBooleanType grayscale)
3985 #define NegateImageTag "Negate/Image"
4005 assert(image != (
Image *) NULL);
4006 assert(image->signature == MagickCoreSignature);
4007 if (IsEventLogging() != MagickFalse)
4008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4009 if (image->storage_class == PseudoClass)
4014 for (i=0; i < (ssize_t) image->colors; i++)
4016 if (grayscale != MagickFalse)
4017 if ((image->colormap[i].red != image->colormap[i].green) ||
4018 (image->colormap[i].green != image->colormap[i].blue))
4020 if ((channel & RedChannel) != 0)
4021 image->colormap[i].red=QuantumRange-image->colormap[i].red;
4022 if ((channel & GreenChannel) != 0)
4023 image->colormap[i].green=QuantumRange-image->colormap[i].green;
4024 if ((channel & BlueChannel) != 0)
4025 image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
4033 exception=(&image->exception);
4034 image_view=AcquireAuthenticCacheView(image,exception);
4035 if (grayscale != MagickFalse)
4037 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4038 #pragma omp parallel for schedule(static) shared(progress,status) \
4039 magick_number_threads(image,image,image->rows,1)
4041 for (y=0; y < (ssize_t) image->rows; y++)
4047 *magick_restrict indexes;
4055 if (status == MagickFalse)
4057 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4064 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4065 for (x=0; x < (ssize_t) image->columns; x++)
4067 if ((GetPixelRed(q) != GetPixelGreen(q)) ||
4068 (GetPixelGreen(q) != GetPixelBlue(q)))
4073 if ((channel & RedChannel) != 0)
4074 SetPixelRed(q,QuantumRange-GetPixelRed(q));
4075 if ((channel & GreenChannel) != 0)
4076 SetPixelGreen(q,QuantumRange-GetPixelGreen(q));
4077 if ((channel & BlueChannel) != 0)
4078 SetPixelBlue(q,QuantumRange-GetPixelBlue(q));
4079 if ((channel & OpacityChannel) != 0)
4080 SetPixelOpacity(q,QuantumRange-GetPixelOpacity(q));
4081 if (((channel & IndexChannel) != 0) &&
4082 (image->colorspace == CMYKColorspace))
4083 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4086 sync=SyncCacheViewAuthenticPixels(image_view,exception);
4087 if (sync == MagickFalse)
4089 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4094 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4098 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4099 if (proceed == MagickFalse)
4103 image_view=DestroyCacheView(image_view);
4109 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4110 #pragma omp parallel for schedule(static) shared(progress,status) \
4111 magick_number_threads(image,image,image->rows,1)
4113 for (y=0; y < (ssize_t) image->rows; y++)
4116 *magick_restrict indexes;
4124 if (status == MagickFalse)
4126 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4132 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4133 if (channel == DefaultChannels)
4134 for (x=0; x < (ssize_t) image->columns; x++)
4136 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4137 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4138 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4141 for (x=0; x < (ssize_t) image->columns; x++)
4143 if ((channel & RedChannel) != 0)
4144 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4145 if ((channel & GreenChannel) != 0)
4146 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4147 if ((channel & BlueChannel) != 0)
4148 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4149 if ((channel & OpacityChannel) != 0)
4150 SetPixelOpacity(q+x,QuantumRange-GetPixelOpacity(q+x));
4152 if (((channel & IndexChannel) != 0) &&
4153 (image->colorspace == CMYKColorspace))
4154 for (x=0; x < (ssize_t) image->columns; x++)
4155 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4156 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4158 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4163 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4167 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4168 if (proceed == MagickFalse)
4172 image_view=DestroyCacheView(image_view);
4205 MagickExport MagickBooleanType NormalizeImage(
Image *image)
4210 status=NormalizeImageChannel(image,DefaultChannels);
4214 MagickExport MagickBooleanType NormalizeImageChannel(
Image *image,
4215 const ChannelType channel)
4221 black_point=0.02*image->columns*image->rows;
4222 white_point=0.99*image->columns*image->rows;
4223 return(ContrastStretchImageChannel(image,channel,black_point,white_point));
4292 #if defined(MAGICKCORE_HAVE_ATANH)
4293 #define Sigmoidal(a,b,x) ( tanh((0.5*(a))*((x)-(b))) )
4295 #define Sigmoidal(a,b,x) ( 1.0/(1.0+exp((a)*((b)-(x)))) )
4314 #define ScaledSigmoidal(a,b,x) ( \
4315 (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \
4316 (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) )
4326 static inline double InverseScaledSigmoidal(
const double a,
const double b,
4329 const double sig0=Sigmoidal(a,b,0.0);
4330 const double sig1=Sigmoidal(a,b,1.0);
4331 const double argument=(sig1-sig0)*x+sig0;
4332 const double clamped=
4334 #if defined(MAGICKCORE_HAVE_ATANH)
4335 argument < -1+MagickEpsilon
4339 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4341 return(b+(2.0/a)*atanh(clamped));
4343 argument < MagickEpsilon
4347 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4349 return(b-log(1.0/clamped-1.0)/a);
4353 MagickExport MagickBooleanType SigmoidalContrastImage(
Image *image,
4354 const MagickBooleanType sharpen,
const char *levels)
4365 flags=ParseGeometry(levels,&geometry_info);
4366 if ((flags & SigmaValue) == 0)
4367 geometry_info.sigma=1.0*QuantumRange/2.0;
4368 if ((flags & PercentValue) != 0)
4369 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
4370 status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
4371 geometry_info.rho,geometry_info.sigma);
4375 MagickExport MagickBooleanType SigmoidalContrastImageChannel(
Image *image,
4376 const ChannelType channel,
const MagickBooleanType sharpen,
4377 const double contrast,
const double midpoint)
4379 #define SigmoidalContrastImageTag "SigmoidalContrast/Image"
4406 if (contrast < MagickEpsilon)
4411 assert(image != (
Image *) NULL);
4412 assert(image->signature == MagickCoreSignature);
4413 if (IsEventLogging() != MagickFalse)
4414 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4415 exception=(&image->exception);
4416 sigmoidal_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
4417 sizeof(*sigmoidal_map));
4418 if (sigmoidal_map == (MagickRealType *) NULL)
4419 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
4421 (void) memset(sigmoidal_map,0,(MaxMap+1)*
sizeof(*sigmoidal_map));
4422 if (sharpen != MagickFalse)
4423 for (i=0; i <= (ssize_t) MaxMap; i++)
4424 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
4425 (MaxMap*ScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4428 for (i=0; i <= (ssize_t) MaxMap; i++)
4429 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType) (
4430 MaxMap*InverseScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4435 if (image->storage_class == PseudoClass)
4436 for (i=0; i < (ssize_t) image->colors; i++)
4438 if ((channel & RedChannel) != 0)
4439 image->colormap[i].red=ClampToQuantum(sigmoidal_map[
4440 ScaleQuantumToMap(image->colormap[i].red)]);
4441 if ((channel & GreenChannel) != 0)
4442 image->colormap[i].green=ClampToQuantum(sigmoidal_map[
4443 ScaleQuantumToMap(image->colormap[i].green)]);
4444 if ((channel & BlueChannel) != 0)
4445 image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
4446 ScaleQuantumToMap(image->colormap[i].blue)]);
4447 if ((channel & OpacityChannel) != 0)
4448 image->colormap[i].opacity=ClampToQuantum(sigmoidal_map[
4449 ScaleQuantumToMap(image->colormap[i].opacity)]);
4456 image_view=AcquireAuthenticCacheView(image,exception);
4457 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4458 #pragma omp parallel for schedule(static) shared(progress,status) \
4459 magick_number_threads(image,image,image->rows,1)
4461 for (y=0; y < (ssize_t) image->rows; y++)
4464 *magick_restrict indexes;
4472 if (status == MagickFalse)
4474 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4480 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4481 for (x=0; x < (ssize_t) image->columns; x++)
4483 if ((channel & RedChannel) != 0)
4484 SetPixelRed(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4486 if ((channel & GreenChannel) != 0)
4487 SetPixelGreen(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4488 GetPixelGreen(q))]));
4489 if ((channel & BlueChannel) != 0)
4490 SetPixelBlue(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4491 GetPixelBlue(q))]));
4492 if ((channel & OpacityChannel) != 0)
4493 SetPixelOpacity(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4494 GetPixelOpacity(q))]));
4495 if (((channel & IndexChannel) != 0) &&
4496 (image->colorspace == CMYKColorspace))
4497 SetPixelIndex(indexes+x,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4498 GetPixelIndex(indexes+x))]));
4501 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4503 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4508 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4512 proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress,
4514 if (proceed == MagickFalse)
4518 image_view=DestroyCacheView(image_view);
4519 sigmoidal_map=(MagickRealType *) RelinquishMagickMemory(sigmoidal_map);