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"
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"
115MagickExport MagickBooleanType AutoGammaImage(
Image *image)
117 return(AutoGammaImageChannel(image,DefaultChannels));
120MagickExport 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);
221MagickExport MagickBooleanType AutoLevelImage(
Image *image)
223 return(AutoLevelImageChannel(image,DefaultChannels));
226MagickExport MagickBooleanType AutoLevelImageChannel(
Image *image,
227 const ChannelType channel)
232 return(MinMaxStretchImage(image,channel,0.0,0.0));
270MagickExport MagickBooleanType BrightnessContrastImage(
Image *image,
271 const double brightness,
const double contrast)
276 status=BrightnessContrastImageChannel(image,DefaultChannels,brightness,
281MagickExport 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,
355MagickExport 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*(double) image->colormap[i].red+0.715158*(
double)
619 image->colormap[i].green+0.072186*(double) image->colormap[i].blue;
620 image->colormap[i].red=ClampToQuantum(luma+color_correction.saturation*
621 (
double) cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
622 image->colormap[i].green=ClampToQuantum(luma+
623 color_correction.saturation*(
double) cdl_map[ScaleQuantumToMap(
624 image->colormap[i].green)].green-luma);
625 image->colormap[i].blue=ClampToQuantum(luma+color_correction.saturation*
626 (
double) cdl_map[ScaleQuantumToMap(image->colormap[i].blue)].blue-
635 image_view=AcquireAuthenticCacheView(image,exception);
636#if defined(MAGICKCORE_OPENMP_SUPPORT)
637 #pragma omp parallel for schedule(static) shared(progress,status) \
638 magick_number_threads(image,image,image->rows,1)
640 for (y=0; y < (ssize_t) image->rows; y++)
651 if (status == MagickFalse)
653 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
659 for (x=0; x < (ssize_t) image->columns; x++)
661 luma=0.212656*(double) GetPixelRed(q)+0.715158*(double) GetPixelGreen(q)+
662 0.072186*(double) GetPixelBlue(q);
663 SetPixelRed(q,ClampToQuantum(luma+color_correction.saturation*
664 ((
double) cdl_map[ScaleQuantumToMap(GetPixelRed(q))].red-luma)));
665 SetPixelGreen(q,ClampToQuantum(luma+color_correction.saturation*
666 ((
double) cdl_map[ScaleQuantumToMap(GetPixelGreen(q))].green-luma)));
667 SetPixelBlue(q,ClampToQuantum(luma+color_correction.saturation*
668 ((
double) cdl_map[ScaleQuantumToMap(GetPixelBlue(q))].blue-luma)));
671 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
673 if (image->progress_monitor != (MagickProgressMonitor) NULL)
678#if defined(MAGICKCORE_OPENMP_SUPPORT)
682 proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
683 progress,image->rows);
684 if (proceed == MagickFalse)
688 image_view=DestroyCacheView(image_view);
689 cdl_map=(
PixelPacket *) RelinquishMagickMemory(cdl_map);
738MagickExport MagickBooleanType ClutImage(
Image *image,
const Image *clut_image)
740 return(ClutImageChannel(image,DefaultChannels,clut_image));
743MagickExport MagickBooleanType ClutImageChannel(
Image *image,
744 const ChannelType channel,
const Image *clut_image)
746#define ClutImageTag "Clut/Image"
771 assert(image != (
Image *) NULL);
772 assert(image->signature == MagickCoreSignature);
773 assert(clut_image != (
Image *) NULL);
774 assert(clut_image->signature == MagickCoreSignature);
775 if (IsEventLogging() != MagickFalse)
776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
777 exception=(&image->exception);
778 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
780 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
781 (IsGrayColorspace(clut_image->colorspace) == MagickFalse))
782 (void) SetImageColorspace(image,sRGBColorspace);
786 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
793 adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
794 clut_view=AcquireAuthenticCacheView(clut_image,exception);
795 for (i=0; i <= (ssize_t) MaxMap; i++)
797 GetMagickPixelPacket(clut_image,clut_map+i);
798 status=InterpolateMagickPixelPacket(clut_image,clut_view,
799 UndefinedInterpolatePixel,(
double) i*(clut_image->columns-adjust)/MaxMap,
800 (
double) i*(clut_image->rows-adjust)/MaxMap,clut_map+i,exception);
801 if (status == MagickFalse)
804 clut_view=DestroyCacheView(clut_view);
805 image_view=AcquireAuthenticCacheView(image,exception);
806#if defined(MAGICKCORE_OPENMP_SUPPORT)
807 #pragma omp parallel for schedule(static) shared(progress,status) \
808 magick_number_threads(image,image,image->rows,1)
810 for (y=0; y < (ssize_t) image->rows; y++)
816 *magick_restrict indexes;
824 if (status == MagickFalse)
826 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
832 indexes=GetCacheViewAuthenticIndexQueue(image_view);
833 GetMagickPixelPacket(image,&pixel);
834 for (x=0; x < (ssize_t) image->columns; x++)
836 SetMagickPixelPacket(image,q,indexes+x,&pixel);
837 if ((channel & RedChannel) != 0)
838 SetPixelRed(q,ClampPixelRed(clut_map+
839 ScaleQuantumToMap(GetPixelRed(q))));
840 if ((channel & GreenChannel) != 0)
841 SetPixelGreen(q,ClampPixelGreen(clut_map+
842 ScaleQuantumToMap(GetPixelGreen(q))));
843 if ((channel & BlueChannel) != 0)
844 SetPixelBlue(q,ClampPixelBlue(clut_map+
845 ScaleQuantumToMap(GetPixelBlue(q))));
846 if ((channel & OpacityChannel) != 0)
848 if (clut_image->matte == MagickFalse)
849 SetPixelAlpha(q,MagickPixelIntensityToQuantum(clut_map+
850 ScaleQuantumToMap((Quantum) GetPixelAlpha(q))));
852 if (image->matte == MagickFalse)
853 SetPixelOpacity(q,ClampPixelOpacity(clut_map+
854 ScaleQuantumToMap((Quantum) MagickPixelIntensity(&pixel))));
856 SetPixelOpacity(q,ClampPixelOpacity(
857 clut_map+ScaleQuantumToMap(GetPixelOpacity(q))));
859 if (((channel & IndexChannel) != 0) &&
860 (image->colorspace == CMYKColorspace))
861 SetPixelIndex(indexes+x,ClampToQuantum((clut_map+(ssize_t)
862 GetPixelIndex(indexes+x))->index));
865 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
867 if (image->progress_monitor != (MagickProgressMonitor) NULL)
872#if defined(MAGICKCORE_OPENMP_SUPPORT)
876 proceed=SetImageProgress(image,ClutImageTag,progress,image->rows);
877 if (proceed == MagickFalse)
881 image_view=DestroyCacheView(image_view);
883 if ((clut_image->matte != MagickFalse) && ((channel & OpacityChannel) != 0))
884 (void) SetImageAlphaChannel(image,ActivateAlphaChannel);
916static inline void Contrast(
const int sign,Quantum *red,Quantum *green,
927 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
928 brightness+=0.5*sign*(0.5*(sin((
double) (MagickPI*(brightness-0.5)))+1.0)-
930 if (brightness > 1.0)
933 if (brightness < 0.0)
935 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
938MagickExport MagickBooleanType ContrastImage(
Image *image,
939 const MagickBooleanType sharpen)
941#define ContrastImageTag "Contrast/Image"
963 assert(image != (
Image *) NULL);
964 assert(image->signature == MagickCoreSignature);
965 if (IsEventLogging() != MagickFalse)
966 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
967 sign=sharpen != MagickFalse ? 1 : -1;
968 if (image->storage_class == PseudoClass)
973 for (i=0; i < (ssize_t) image->colors; i++)
974 Contrast(sign,&image->colormap[i].red,&image->colormap[i].green,
975 &image->colormap[i].blue);
980#if defined(MAGICKCORE_OPENCL_SUPPORT)
981 status=AccelerateContrastImage(image,sharpen,&image->exception);
982 if (status != MagickFalse)
987 exception=(&image->exception);
988 image_view=AcquireAuthenticCacheView(image,exception);
989#if defined(MAGICKCORE_OPENMP_SUPPORT)
990 #pragma omp parallel for schedule(static) shared(progress,status) \
991 magick_number_threads(image,image,image->rows,1)
993 for (y=0; y < (ssize_t) image->rows; y++)
1006 if (status == MagickFalse)
1008 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1014 for (x=0; x < (ssize_t) image->columns; x++)
1017 green=GetPixelGreen(q);
1018 blue=GetPixelBlue(q);
1019 Contrast(sign,&red,&green,&blue);
1021 SetPixelGreen(q,green);
1022 SetPixelBlue(q,blue);
1025 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1027 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1032#if defined(MAGICKCORE_OPENMP_SUPPORT)
1036 proceed=SetImageProgress(image,ContrastImageTag,progress,image->rows);
1037 if (proceed == MagickFalse)
1041 image_view=DestroyCacheView(image_view);
1086MagickExport MagickBooleanType ContrastStretchImage(
Image *image,
1091 white_point = (double) image->columns*image->rows;
1105 if (levels == (
char *) NULL)
1106 return(MagickFalse);
1107 flags=ParseGeometry(levels,&geometry_info);
1108 if ((flags & RhoValue) != 0)
1109 black_point=geometry_info.rho;
1110 if ((flags & SigmaValue) != 0)
1111 white_point=geometry_info.sigma;
1112 if ((flags & PercentValue) != 0)
1114 black_point*=(double) QuantumRange/100.0;
1115 white_point*=(double) QuantumRange/100.0;
1117 if ((flags & SigmaValue) == 0)
1118 white_point=(double) image->columns*image->rows-black_point;
1119 status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
1124MagickExport MagickBooleanType ContrastStretchImageChannel(
Image *image,
1125 const ChannelType channel,
const double black_point,
const double white_point)
1127#define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
1128#define ContrastStretchImageTag "ContrastStretch/Image"
1162 assert(image != (
Image *) NULL);
1163 assert(image->signature == MagickCoreSignature);
1164 if (IsEventLogging() != MagickFalse)
1165 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1166 exception=(&image->exception);
1168#if defined(MAGICKCORE_OPENCL_SUPPORT) && 0
1170 status=AccelerateContrastStretchImageChannel(image,channel,black_point,
1171 white_point,&image->exception);
1172 if (status != MagickFalse)
1176 sizeof(*histogram));
1178 sizeof(*stretch_map));
1186 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1192 if (SetImageGray(image,exception) != MagickFalse)
1193 (void) SetImageColorspace(image,GRAYColorspace);
1195 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1196 image_view=AcquireAuthenticCacheView(image,exception);
1197 for (y=0; y < (ssize_t) image->rows; y++)
1203 *magick_restrict indexes;
1208 if (status == MagickFalse)
1210 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1216 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1217 if ((channel & SyncChannels) != 0)
1218 for (x=0; x < (ssize_t) image->columns; x++)
1223 intensity=ClampToQuantum(GetPixelIntensity(image,p));
1224 histogram[ScaleQuantumToMap(intensity)].red++;
1225 histogram[ScaleQuantumToMap(intensity)].green++;
1226 histogram[ScaleQuantumToMap(intensity)].blue++;
1227 histogram[ScaleQuantumToMap(intensity)].index++;
1231 for (x=0; x < (ssize_t) image->columns; x++)
1233 if ((channel & RedChannel) != 0)
1234 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1235 if ((channel & GreenChannel) != 0)
1236 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1237 if ((channel & BlueChannel) != 0)
1238 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1239 if ((channel & OpacityChannel) != 0)
1240 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1241 if (((channel & IndexChannel) != 0) &&
1242 (image->colorspace == CMYKColorspace))
1243 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1251 white.red=MaxRange(QuantumRange);
1252 if ((channel & RedChannel) != 0)
1255 for (i=0; i <= (ssize_t) MaxMap; i++)
1257 intensity+=histogram[i].red;
1258 if (intensity > black_point)
1261 black.red=(MagickRealType) i;
1263 for (i=(ssize_t) MaxMap; i != 0; i--)
1265 intensity+=histogram[i].red;
1266 if (intensity > ((
double) image->columns*image->rows-white_point))
1269 white.red=(MagickRealType) i;
1272 white.green=MaxRange(QuantumRange);
1273 if ((channel & GreenChannel) != 0)
1276 for (i=0; i <= (ssize_t) MaxMap; i++)
1278 intensity+=histogram[i].green;
1279 if (intensity > black_point)
1282 black.green=(MagickRealType) i;
1284 for (i=(ssize_t) MaxMap; i != 0; i--)
1286 intensity+=histogram[i].green;
1287 if (intensity > ((
double) image->columns*image->rows-white_point))
1290 white.green=(MagickRealType) i;
1293 white.blue=MaxRange(QuantumRange);
1294 if ((channel & BlueChannel) != 0)
1297 for (i=0; i <= (ssize_t) MaxMap; i++)
1299 intensity+=histogram[i].blue;
1300 if (intensity > black_point)
1303 black.blue=(MagickRealType) i;
1305 for (i=(ssize_t) MaxMap; i != 0; i--)
1307 intensity+=histogram[i].blue;
1308 if (intensity > ((
double) image->columns*image->rows-white_point))
1311 white.blue=(MagickRealType) i;
1314 white.opacity=MaxRange(QuantumRange);
1315 if ((channel & OpacityChannel) != 0)
1318 for (i=0; i <= (ssize_t) MaxMap; i++)
1320 intensity+=histogram[i].opacity;
1321 if (intensity > black_point)
1324 black.opacity=(MagickRealType) i;
1326 for (i=(ssize_t) MaxMap; i != 0; i--)
1328 intensity+=histogram[i].opacity;
1329 if (intensity > ((
double) image->columns*image->rows-white_point))
1332 white.opacity=(MagickRealType) i;
1335 white.index=MaxRange(QuantumRange);
1336 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1339 for (i=0; i <= (ssize_t) MaxMap; i++)
1341 intensity+=histogram[i].index;
1342 if (intensity > black_point)
1345 black.index=(MagickRealType) i;
1347 for (i=(ssize_t) MaxMap; i != 0; i--)
1349 intensity+=histogram[i].index;
1350 if (intensity > ((
double) image->columns*image->rows-white_point))
1353 white.index=(MagickRealType) i;
1359 (void) memset(stretch_map,0,(MaxMap+1)*
sizeof(*stretch_map));
1360 for (i=0; i <= (ssize_t) MaxMap; i++)
1362 if ((channel & RedChannel) != 0)
1364 if (i < (ssize_t) black.red)
1365 stretch_map[i].red=(Quantum) 0;
1367 if (i > (ssize_t) white.red)
1368 stretch_map[i].red=QuantumRange;
1370 if (black.red != white.red)
1371 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
1372 (i-black.red)/(white.red-black.red)));
1374 if ((channel & GreenChannel) != 0)
1376 if (i < (ssize_t) black.green)
1377 stretch_map[i].green=0;
1379 if (i > (ssize_t) white.green)
1380 stretch_map[i].green=QuantumRange;
1382 if (black.green != white.green)
1383 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
1384 (i-black.green)/(white.green-black.green)));
1386 if ((channel & BlueChannel) != 0)
1388 if (i < (ssize_t) black.blue)
1389 stretch_map[i].blue=0;
1391 if (i > (ssize_t) white.blue)
1392 stretch_map[i].blue= QuantumRange;
1394 if (black.blue != white.blue)
1395 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
1396 (i-black.blue)/(white.blue-black.blue)));
1398 if ((channel & OpacityChannel) != 0)
1400 if (i < (ssize_t) black.opacity)
1401 stretch_map[i].opacity=0;
1403 if (i > (ssize_t) white.opacity)
1404 stretch_map[i].opacity=QuantumRange;
1406 if (black.opacity != white.opacity)
1407 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
1408 (i-black.opacity)/(white.opacity-black.opacity)));
1410 if (((channel & IndexChannel) != 0) &&
1411 (image->colorspace == CMYKColorspace))
1413 if (i < (ssize_t) black.index)
1414 stretch_map[i].index=0;
1416 if (i > (ssize_t) white.index)
1417 stretch_map[i].index=QuantumRange;
1419 if (black.index != white.index)
1420 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
1421 (i-black.index)/(white.index-black.index)));
1427 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
1428 (image->colorspace == CMYKColorspace)))
1429 image->storage_class=DirectClass;
1430 if (image->storage_class == PseudoClass)
1435 for (i=0; i < (ssize_t) image->colors; i++)
1437 if ((channel & RedChannel) != 0)
1439 if (black.red != white.red)
1440 image->colormap[i].red=stretch_map[
1441 ScaleQuantumToMap(image->colormap[i].red)].red;
1443 if ((channel & GreenChannel) != 0)
1445 if (black.green != white.green)
1446 image->colormap[i].green=stretch_map[
1447 ScaleQuantumToMap(image->colormap[i].green)].green;
1449 if ((channel & BlueChannel) != 0)
1451 if (black.blue != white.blue)
1452 image->colormap[i].blue=stretch_map[
1453 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1455 if ((channel & OpacityChannel) != 0)
1457 if (black.opacity != white.opacity)
1458 image->colormap[i].opacity=stretch_map[
1459 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1468#if defined(MAGICKCORE_OPENMP_SUPPORT)
1469 #pragma omp parallel for schedule(static) shared(progress,status) \
1470 magick_number_threads(image,image,image->rows,1)
1472 for (y=0; y < (ssize_t) image->rows; y++)
1475 *magick_restrict indexes;
1483 if (status == MagickFalse)
1485 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1491 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1492 for (x=0; x < (ssize_t) image->columns; x++)
1494 if ((channel & RedChannel) != 0)
1496 if (black.red != white.red)
1497 SetPixelRed(q,stretch_map[
1498 ScaleQuantumToMap(GetPixelRed(q))].red);
1500 if ((channel & GreenChannel) != 0)
1502 if (black.green != white.green)
1503 SetPixelGreen(q,stretch_map[
1504 ScaleQuantumToMap(GetPixelGreen(q))].green);
1506 if ((channel & BlueChannel) != 0)
1508 if (black.blue != white.blue)
1509 SetPixelBlue(q,stretch_map[
1510 ScaleQuantumToMap(GetPixelBlue(q))].blue);
1512 if ((channel & OpacityChannel) != 0)
1514 if (black.opacity != white.opacity)
1515 SetPixelOpacity(q,stretch_map[
1516 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
1518 if (((channel & IndexChannel) != 0) &&
1519 (image->colorspace == CMYKColorspace))
1521 if (black.index != white.index)
1522 SetPixelIndex(indexes+x,stretch_map[
1523 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
1527 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1529 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1534#if defined(MAGICKCORE_OPENMP_SUPPORT)
1538 proceed=SetImageProgress(image,ContrastStretchImageTag,progress,
1540 if (proceed == MagickFalse)
1544 image_view=DestroyCacheView(image_view);
1576#define EnhancePixel(weight) \
1577 mean=QuantumScale*((double) GetPixelRed(r)+(double) pixel.red)/2.0; \
1578 distance=QuantumScale*((double) GetPixelRed(r)-(double) pixel.red); \
1579 distance_squared=(4.0+mean)*distance*distance; \
1580 mean=QuantumScale*((double) GetPixelGreen(r)+(double) pixel.green)/2.0; \
1581 distance=QuantumScale*((double) GetPixelGreen(r)-(double) pixel.green); \
1582 distance_squared+=(7.0-mean)*distance*distance; \
1583 mean=QuantumScale*((double) GetPixelBlue(r)+(double) pixel.blue)/2.0; \
1584 distance=QuantumScale*((double) GetPixelBlue(r)-(double) pixel.blue); \
1585 distance_squared+=(5.0-mean)*distance*distance; \
1586 mean=QuantumScale*((double) GetPixelOpacity(r)+(double) pixel.opacity)/2.0; \
1587 distance=QuantumScale*((double) GetPixelOpacity(r)-(double) pixel.opacity); \
1588 distance_squared+=(5.0-mean)*distance*distance; \
1589 if (distance_squared < 0.069) \
1591 aggregate.red+=(weight)*(double) GetPixelRed(r); \
1592 aggregate.green+=(weight)*(double) GetPixelGreen(r); \
1593 aggregate.blue+=(weight)*(double) GetPixelBlue(r); \
1594 aggregate.opacity+=(weight)*(double) GetPixelOpacity(r); \
1595 total_weight+=(weight); \
1598#define EnhanceImageTag "Enhance/Image"
1622 assert(image != (
const Image *) NULL);
1623 assert(image->signature == MagickCoreSignature);
1624 if (IsEventLogging() != MagickFalse)
1625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1627 assert(exception->signature == MagickCoreSignature);
1628 if ((image->columns < 5) || (image->rows < 5))
1629 return((
Image *) NULL);
1630 enhance_image=CloneImage(image,0,0,MagickTrue,exception);
1631 if (enhance_image == (
Image *) NULL)
1632 return((
Image *) NULL);
1633 if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
1635 InheritException(exception,&enhance_image->exception);
1636 enhance_image=DestroyImage(enhance_image);
1637 return((
Image *) NULL);
1644 (void) memset(&zero,0,
sizeof(zero));
1645 image_view=AcquireAuthenticCacheView(image,exception);
1646 enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
1647#if defined(MAGICKCORE_OPENMP_SUPPORT)
1648 #pragma omp parallel for schedule(static) shared(progress,status) \
1649 magick_number_threads(image,enhance_image,image->rows,1)
1651 for (y=0; y < (ssize_t) image->rows; y++)
1665 if (status == MagickFalse)
1667 p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
1668 q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
1675 for (x=0; x < (ssize_t) image->columns; x++)
1697 r=p+2*(image->columns+4)+2;
1700 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1701 EnhancePixel(8.0); EnhancePixel(5.0);
1702 r=p+(image->columns+4);
1703 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1704 EnhancePixel(20.0); EnhancePixel(8.0);
1705 r=p+2*(image->columns+4);
1706 EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
1707 EnhancePixel(40.0); EnhancePixel(10.0);
1708 r=p+3*(image->columns+4);
1709 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1710 EnhancePixel(20.0); EnhancePixel(8.0);
1711 r=p+4*(image->columns+4);
1712 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1713 EnhancePixel(8.0); EnhancePixel(5.0);
1714 if (total_weight > MagickEpsilon)
1716 SetPixelRed(q,(aggregate.red+(total_weight/2)-1)/total_weight);
1717 SetPixelGreen(q,(aggregate.green+(total_weight/2)-1)/total_weight);
1718 SetPixelBlue(q,(aggregate.blue+(total_weight/2)-1)/total_weight);
1719 SetPixelOpacity(q,(aggregate.opacity+(total_weight/2)-1)/
1725 if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
1727 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1732#if defined(MAGICKCORE_OPENMP_SUPPORT)
1736 proceed=SetImageProgress(image,EnhanceImageTag,progress,image->rows);
1737 if (proceed == MagickFalse)
1741 enhance_view=DestroyCacheView(enhance_view);
1742 image_view=DestroyCacheView(image_view);
1743 if (status == MagickFalse)
1744 enhance_image=DestroyImage(enhance_image);
1745 return(enhance_image);
1775MagickExport MagickBooleanType EqualizeImage(
Image *image)
1777 return(EqualizeImageChannel(image,DefaultChannels));
1780MagickExport MagickBooleanType EqualizeImageChannel(
Image *image,
1781 const ChannelType channel)
1783#define EqualizeImageTag "Equalize/Image"
1813 assert(image != (
Image *) NULL);
1814 assert(image->signature == MagickCoreSignature);
1815 if (IsEventLogging() != MagickFalse)
1816 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1817 exception=(&image->exception);
1819#if defined(MAGICKCORE_OPENCL_SUPPORT)
1821 status=AccelerateEqualizeImage(image,channel,&image->exception);
1822 if (status != MagickFalse)
1829 sizeof(*equalize_map));
1831 sizeof(*histogram));
1844 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1850 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
1851 image_view=AcquireVirtualCacheView(image,exception);
1852 for (y=0; y < (ssize_t) image->rows; y++)
1855 *magick_restrict indexes;
1863 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1866 indexes=GetCacheViewVirtualIndexQueue(image_view);
1867 if ((channel & SyncChannels) != 0)
1868 for (x=0; x < (ssize_t) image->columns; x++)
1870 MagickRealType intensity=GetPixelIntensity(image,p);
1871 histogram[ScaleQuantumToMap(ClampToQuantum(intensity))].red++;
1875 for (x=0; x < (ssize_t) image->columns; x++)
1877 if ((channel & RedChannel) != 0)
1878 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
1879 if ((channel & GreenChannel) != 0)
1880 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
1881 if ((channel & BlueChannel) != 0)
1882 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
1883 if ((channel & OpacityChannel) != 0)
1884 histogram[ScaleQuantumToMap(GetPixelOpacity(p))].opacity++;
1885 if (((channel & IndexChannel) != 0) &&
1886 (image->colorspace == CMYKColorspace))
1887 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
1891 image_view=DestroyCacheView(image_view);
1895 (void) memset(&intensity,0,
sizeof(intensity));
1896 for (i=0; i <= (ssize_t) MaxMap; i++)
1898 if ((channel & SyncChannels) != 0)
1900 intensity.red+=histogram[i].red;
1904 if ((channel & RedChannel) != 0)
1905 intensity.red+=histogram[i].red;
1906 if ((channel & GreenChannel) != 0)
1907 intensity.green+=histogram[i].green;
1908 if ((channel & BlueChannel) != 0)
1909 intensity.blue+=histogram[i].blue;
1910 if ((channel & OpacityChannel) != 0)
1911 intensity.opacity+=histogram[i].opacity;
1912 if (((channel & IndexChannel) != 0) &&
1913 (image->colorspace == CMYKColorspace))
1914 intensity.index+=histogram[i].index;
1918 white=map[(int) MaxMap];
1919 (void) memset(equalize_map,0,(MaxMap+1)*
sizeof(*equalize_map));
1920 for (i=0; i <= (ssize_t) MaxMap; i++)
1922 if ((channel & SyncChannels) != 0)
1924 if (white.red != black.red)
1925 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1926 (map[i].red-black.red))/(white.red-black.red)));
1929 if (((channel & RedChannel) != 0) && (white.red != black.red))
1930 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1931 (map[i].red-black.red))/(white.red-black.red)));
1932 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1933 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1934 (map[i].green-black.green))/(white.green-black.green)));
1935 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1936 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1937 (map[i].blue-black.blue))/(white.blue-black.blue)));
1938 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
1939 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1940 (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
1941 if ((((channel & IndexChannel) != 0) &&
1942 (image->colorspace == CMYKColorspace)) &&
1943 (white.index != black.index))
1944 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
1945 (map[i].index-black.index))/(white.index-black.index)));
1949 if (image->storage_class == PseudoClass)
1954 for (i=0; i < (ssize_t) image->colors; i++)
1956 if ((channel & SyncChannels) != 0)
1958 if (white.red != black.red)
1960 image->colormap[i].red=equalize_map[
1961 ScaleQuantumToMap(image->colormap[i].red)].red;
1962 image->colormap[i].green=equalize_map[
1963 ScaleQuantumToMap(image->colormap[i].green)].red;
1964 image->colormap[i].blue=equalize_map[
1965 ScaleQuantumToMap(image->colormap[i].blue)].red;
1966 image->colormap[i].opacity=equalize_map[
1967 ScaleQuantumToMap(image->colormap[i].opacity)].red;
1971 if (((channel & RedChannel) != 0) && (white.red != black.red))
1972 image->colormap[i].red=equalize_map[
1973 ScaleQuantumToMap(image->colormap[i].red)].red;
1974 if (((channel & GreenChannel) != 0) && (white.green != black.green))
1975 image->colormap[i].green=equalize_map[
1976 ScaleQuantumToMap(image->colormap[i].green)].green;
1977 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
1978 image->colormap[i].blue=equalize_map[
1979 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1980 if (((channel & OpacityChannel) != 0) &&
1981 (white.opacity != black.opacity))
1982 image->colormap[i].opacity=equalize_map[
1983 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
1991 image_view=AcquireAuthenticCacheView(image,exception);
1992#if defined(MAGICKCORE_OPENMP_SUPPORT)
1993 #pragma omp parallel for schedule(static) shared(progress,status) \
1994 magick_number_threads(image,image,image->rows,1)
1996 for (y=0; y < (ssize_t) image->rows; y++)
1999 *magick_restrict indexes;
2007 if (status == MagickFalse)
2009 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2015 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2016 for (x=0; x < (ssize_t) image->columns; x++)
2018 if ((channel & SyncChannels) != 0)
2020 if (white.red != black.red)
2022 SetPixelRed(q,equalize_map[
2023 ScaleQuantumToMap(GetPixelRed(q))].red);
2024 SetPixelGreen(q,equalize_map[
2025 ScaleQuantumToMap(GetPixelGreen(q))].red);
2026 SetPixelBlue(q,equalize_map[
2027 ScaleQuantumToMap(GetPixelBlue(q))].red);
2028 SetPixelOpacity(q,equalize_map[
2029 ScaleQuantumToMap(GetPixelOpacity(q))].red);
2030 if (image->colorspace == CMYKColorspace)
2031 SetPixelIndex(indexes+x,equalize_map[
2032 ScaleQuantumToMap(GetPixelIndex(indexes+x))].red);
2037 if (((channel & RedChannel) != 0) && (white.red != black.red))
2038 SetPixelRed(q,equalize_map[
2039 ScaleQuantumToMap(GetPixelRed(q))].red);
2040 if (((channel & GreenChannel) != 0) && (white.green != black.green))
2041 SetPixelGreen(q,equalize_map[
2042 ScaleQuantumToMap(GetPixelGreen(q))].green);
2043 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
2044 SetPixelBlue(q,equalize_map[
2045 ScaleQuantumToMap(GetPixelBlue(q))].blue);
2046 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
2047 SetPixelOpacity(q,equalize_map[
2048 ScaleQuantumToMap(GetPixelOpacity(q))].opacity);
2049 if ((((channel & IndexChannel) != 0) &&
2050 (image->colorspace == CMYKColorspace)) &&
2051 (white.index != black.index))
2052 SetPixelIndex(indexes+x,equalize_map[
2053 ScaleQuantumToMap(GetPixelIndex(indexes+x))].index);
2056 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2058 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2063#if defined(MAGICKCORE_OPENMP_SUPPORT)
2067 proceed=SetImageProgress(image,EqualizeImageTag,progress,image->rows);
2068 if (proceed == MagickFalse)
2072 image_view=DestroyCacheView(image_view);
2115static inline double gamma_pow(
const double value,
const double gamma)
2117 return(value < 0.0 ? value : pow(value,gamma));
2120MagickExport MagickBooleanType GammaImage(
Image *image,
const char *level)
2132 assert(image != (
Image *) NULL);
2133 assert(image->signature == MagickCoreSignature);
2134 if (IsEventLogging() != MagickFalse)
2135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2136 if (level == (
char *) NULL)
2137 return(MagickFalse);
2139 flags=ParseGeometry(level,&geometry_info);
2140 if ((flags & RhoValue) != 0)
2141 gamma.red=geometry_info.rho;
2142 gamma.green=gamma.red;
2143 if ((flags & SigmaValue) != 0)
2144 gamma.green=geometry_info.sigma;
2145 gamma.blue=gamma.red;
2146 if ((flags & XiValue) != 0)
2147 gamma.blue=geometry_info.xi;
2148 if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
2150 if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
2151 status=GammaImageChannel(image,(ChannelType) (RedChannel | GreenChannel |
2152 BlueChannel),(
double) gamma.red);
2155 status=GammaImageChannel(image,RedChannel,(
double) gamma.red);
2156 status&=GammaImageChannel(image,GreenChannel,(
double) gamma.green);
2157 status&=GammaImageChannel(image,BlueChannel,(
double) gamma.blue);
2159 return(status != 0 ? MagickTrue : MagickFalse);
2162MagickExport MagickBooleanType GammaImageChannel(
Image *image,
2163 const ChannelType channel,
const double gamma)
2165#define GammaImageTag "Gamma/Image"
2191 assert(image != (
Image *) NULL);
2192 assert(image->signature == MagickCoreSignature);
2193 if (IsEventLogging() != MagickFalse)
2194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2195 exception=(&image->exception);
2198 gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*gamma_map));
2199 if (gamma_map == (Quantum *) NULL)
2200 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2202 (void) memset(gamma_map,0,(MaxMap+1)*
sizeof(*gamma_map));
2204 for (i=0; i <= (ssize_t) MaxMap; i++)
2205 gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
2206 MagickRealType) (MaxMap*pow((
double) i/MaxMap,
2207 PerceptibleReciprocal(gamma)))));
2208 if (image->storage_class == PseudoClass)
2213 for (i=0; i < (ssize_t) image->colors; i++)
2215#if !defined(MAGICKCORE_HDRI_SUPPORT)
2216 if ((channel & RedChannel) != 0)
2217 image->colormap[i].red=gamma_map[ScaleQuantumToMap(
2218 image->colormap[i].red)];
2219 if ((channel & GreenChannel) != 0)
2220 image->colormap[i].green=gamma_map[ScaleQuantumToMap(
2221 image->colormap[i].green)];
2222 if ((channel & BlueChannel) != 0)
2223 image->colormap[i].blue=gamma_map[ScaleQuantumToMap(
2224 image->colormap[i].blue)];
2225 if ((channel & OpacityChannel) != 0)
2227 if (image->matte == MagickFalse)
2228 image->colormap[i].opacity=gamma_map[ScaleQuantumToMap(
2229 image->colormap[i].opacity)];
2231 image->colormap[i].opacity=QuantumRange-gamma_map[
2232 ScaleQuantumToMap((Quantum) (QuantumRange-
2233 image->colormap[i].opacity))];
2236 if ((channel & RedChannel) != 0)
2237 image->colormap[i].red=(double) QuantumRange*gamma_pow(QuantumScale*
2238 (
double) image->colormap[i].red,PerceptibleReciprocal(gamma));
2239 if ((channel & GreenChannel) != 0)
2240 image->colormap[i].green=(double) QuantumRange*gamma_pow(QuantumScale*
2241 (
double) image->colormap[i].green,PerceptibleReciprocal(gamma));
2242 if ((channel & BlueChannel) != 0)
2243 image->colormap[i].blue=(double) QuantumRange*gamma_pow(QuantumScale*
2244 (
double) image->colormap[i].blue,PerceptibleReciprocal(gamma));
2245 if ((channel & OpacityChannel) != 0)
2247 if (image->matte == MagickFalse)
2248 image->colormap[i].opacity=(double) QuantumRange*
2249 gamma_pow(QuantumScale*(
double) image->colormap[i].opacity,
2250 PerceptibleReciprocal(gamma));
2252 image->colormap[i].opacity=(double) QuantumRange-(
double)
2253 QuantumRange*gamma_pow(QuantumScale*((
double) QuantumRange-
2254 (
double) image->colormap[i].opacity),1.0/gamma);
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,(
double) QuantumRange*gamma_pow(QuantumScale*(
double)
2320 GetPixelRed(q),PerceptibleReciprocal(gamma)));
2321 SetPixelGreen(q,(
double) QuantumRange*gamma_pow(QuantumScale*(
double)
2322 GetPixelGreen(q),PerceptibleReciprocal(gamma)));
2323 SetPixelBlue(q,(
double) QuantumRange*gamma_pow(QuantumScale*(
double)
2324 GetPixelBlue(q),PerceptibleReciprocal(gamma)));
2328 if ((channel & RedChannel) != 0)
2329 SetPixelRed(q,(
double) QuantumRange*gamma_pow(QuantumScale*
2330 (
double) GetPixelRed(q),PerceptibleReciprocal(gamma)));
2331 if ((channel & GreenChannel) != 0)
2332 SetPixelGreen(q,(
double) QuantumRange*gamma_pow(QuantumScale*
2333 (
double) GetPixelGreen(q),PerceptibleReciprocal(gamma)));
2334 if ((channel & BlueChannel) != 0)
2335 SetPixelBlue(q,(
double) QuantumRange*gamma_pow(QuantumScale*
2336 (
double) GetPixelBlue(q),PerceptibleReciprocal(gamma)));
2337 if ((channel & OpacityChannel) != 0)
2339 if (image->matte == MagickFalse)
2340 SetPixelOpacity(q,(
double) QuantumRange*gamma_pow(QuantumScale*
2341 (
double) GetPixelOpacity(q),PerceptibleReciprocal(gamma)));
2343 SetPixelAlpha(q,(
double) QuantumRange*gamma_pow(QuantumScale*
2344 (
double) 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;
2403MagickExport 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*(
double) red+(
double)
2508 green*(
double) green+(
double) blue*(
double) blue)/
2509 (3.0*(
double) QuantumRange));
2512 case Rec601LumaPixelIntensityMethod:
2514 if (image->colorspace == RGBColorspace)
2516 red=EncodePixelGamma(red);
2517 green=EncodePixelGamma(green);
2518 blue=EncodePixelGamma(blue);
2520 intensity=0.298839*red+0.586811*green+0.114350*blue;
2523 case Rec601LuminancePixelIntensityMethod:
2525 if (image->colorspace == sRGBColorspace)
2527 red=DecodePixelGamma(red);
2528 green=DecodePixelGamma(green);
2529 blue=DecodePixelGamma(blue);
2531 intensity=0.298839*red+0.586811*green+0.114350*blue;
2534 case Rec709LumaPixelIntensityMethod:
2537 if (image->colorspace == RGBColorspace)
2539 red=EncodePixelGamma(red);
2540 green=EncodePixelGamma(green);
2541 blue=EncodePixelGamma(blue);
2543 intensity=0.212656*red+0.715158*green+0.072186*blue;
2546 case Rec709LuminancePixelIntensityMethod:
2548 if (image->colorspace == sRGBColorspace)
2550 red=DecodePixelGamma(red);
2551 green=DecodePixelGamma(green);
2552 blue=DecodePixelGamma(blue);
2554 intensity=0.212656*red+0.715158*green+0.072186*blue;
2557 case RMSPixelIntensityMethod:
2559 intensity=(MagickRealType) (sqrt((
double) red*red+green*green+
2560 blue*blue)/sqrt(3.0));
2564 SetPixelGray(q,ClampToQuantum(intensity));
2567 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2569 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2574#if defined(MAGICKCORE_OPENMP_SUPPORT)
2578 proceed=SetImageProgress(image,GrayscaleImageTag,progress,image->rows);
2579 if (proceed == MagickFalse)
2583 image_view=DestroyCacheView(image_view);
2584 image->intensity=method;
2585 image->type=GrayscaleType;
2586 if ((method == Rec601LuminancePixelIntensityMethod) ||
2587 (method == Rec709LuminancePixelIntensityMethod))
2588 return(SetImageColorspace(image,LinearGRAYColorspace));
2589 return(SetImageColorspace(image,GRAYColorspace));
2625MagickExport MagickBooleanType HaldClutImage(
Image *image,
2626 const Image *hald_image)
2628 return(HaldClutImageChannel(image,DefaultChannels,hald_image));
2631MagickExport MagickBooleanType HaldClutImageChannel(
Image *image,
2632 const ChannelType channel,
const Image *hald_image)
2634#define HaldClutImageTag "Clut/Image"
2636 typedef struct _HaldInfo
2671 assert(image != (
Image *) NULL);
2672 assert(image->signature == MagickCoreSignature);
2673 if (IsEventLogging() != MagickFalse)
2674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2675 assert(hald_image != (
Image *) NULL);
2676 assert(hald_image->signature == MagickCoreSignature);
2677 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2678 return(MagickFalse);
2679 if (IsGrayColorspace(image->colorspace) != MagickFalse)
2680 (void) SetImageColorspace(image,sRGBColorspace);
2681 if (image->matte == MagickFalse)
2682 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
2688 length=(size_t) MagickMin((MagickRealType) hald_image->columns,
2689 (MagickRealType) hald_image->rows);
2690 for (level=2; (level*level*level) < length; level++) ;
2692 cube_size=level*level;
2693 width=(double) hald_image->columns;
2694 GetMagickPixelPacket(hald_image,&zero);
2695 exception=(&image->exception);
2696 image_view=AcquireAuthenticCacheView(image,exception);
2697 hald_view=AcquireAuthenticCacheView(hald_image,exception);
2698#if defined(MAGICKCORE_OPENMP_SUPPORT)
2699 #pragma omp parallel for schedule(static) shared(progress,status) \
2700 magick_number_threads(image,hald_image,image->rows,1)
2702 for (y=0; y < (ssize_t) image->rows; y++)
2719 *magick_restrict indexes;
2727 if (status == MagickFalse)
2729 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2735 indexes=GetCacheViewAuthenticIndexQueue(hald_view);
2741 for (x=0; x < (ssize_t) image->columns; x++)
2743 point.x=QuantumScale*(level-1.0)*(
double) GetPixelRed(q);
2744 point.y=QuantumScale*(level-1.0)*(
double) GetPixelGreen(q);
2745 point.z=QuantumScale*(level-1.0)*(
double) GetPixelBlue(q);
2746 offset=(double) (point.x+level*floor(point.y)+cube_size*floor(point.z));
2747 point.x-=floor(point.x);
2748 point.y-=floor(point.y);
2749 point.z-=floor(point.z);
2750 status=InterpolateMagickPixelPacket(image,hald_view,
2751 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2753 if (status == MagickFalse)
2755 status=InterpolateMagickPixelPacket(image,hald_view,
2756 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2757 width),&pixel2,exception);
2758 if (status == MagickFalse)
2761 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2762 area=(point.y < 0.5) ? 0.0 : 1.0;
2763 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2764 pixel2.opacity,area,&pixel3);
2766 status=InterpolateMagickPixelPacket(image,hald_view,
2767 UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
2769 if (status == MagickFalse)
2771 status=InterpolateMagickPixelPacket(image,hald_view,
2772 UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
2773 width),&pixel2,exception);
2774 if (status == MagickFalse)
2776 MagickPixelCompositeAreaBlend(&pixel1,pixel1.opacity,&pixel2,
2777 pixel2.opacity,area,&pixel4);
2779 if (hald_image->interpolate == NearestNeighborInterpolatePixel)
2780 area=(point.z < 0.5)? 0.0 : 1.0;
2781 MagickPixelCompositeAreaBlend(&pixel3,pixel3.opacity,&pixel4,
2782 pixel4.opacity,area,&pixel);
2783 if ((channel & RedChannel) != 0)
2784 SetPixelRed(q,ClampToQuantum(pixel.red));
2785 if ((channel & GreenChannel) != 0)
2786 SetPixelGreen(q,ClampToQuantum(pixel.green));
2787 if ((channel & BlueChannel) != 0)
2788 SetPixelBlue(q,ClampToQuantum(pixel.blue));
2789 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2790 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
2791 if (((channel & IndexChannel) != 0) &&
2792 (image->colorspace == CMYKColorspace))
2793 SetPixelIndex(indexes+x,ClampToQuantum(pixel.index));
2796 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2798 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2803#if defined(MAGICKCORE_OPENMP_SUPPORT)
2807 proceed=SetImageProgress(image,HaldClutImageTag,progress,image->rows);
2808 if (proceed == MagickFalse)
2812 hald_view=DestroyCacheView(hald_view);
2813 image_view=DestroyCacheView(image_view);
2858MagickExport MagickBooleanType LevelImage(
Image *image,
const char *levels)
2863 white_point = (double) QuantumRange;
2877 if (levels == (
char *) NULL)
2878 return(MagickFalse);
2879 flags=ParseGeometry(levels,&geometry_info);
2880 if ((flags & RhoValue) != 0)
2881 black_point=geometry_info.rho;
2882 if ((flags & SigmaValue) != 0)
2883 white_point=geometry_info.sigma;
2884 if ((flags & XiValue) != 0)
2885 gamma=geometry_info.xi;
2886 if ((flags & PercentValue) != 0)
2888 black_point*=(double) image->columns*image->rows/100.0;
2889 white_point*=(double) image->columns*image->rows/100.0;
2891 if ((flags & SigmaValue) == 0)
2892 white_point=(double) QuantumRange-black_point;
2893 if ((flags & AspectValue ) == 0)
2894 status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
2897 status=LevelizeImage(image,black_point,white_point,gamma);
2944static inline double LevelPixel(
const double black_point,
2945 const double white_point,
const double gamma,
const MagickRealType pixel)
2951 scale=PerceptibleReciprocal(white_point-black_point);
2952 level_pixel=(double) QuantumRange*gamma_pow(scale*((
double) pixel-
2953 black_point),PerceptibleReciprocal(gamma));
2954 return(level_pixel);
2957MagickExport MagickBooleanType LevelImageChannel(
Image *image,
2958 const ChannelType channel,
const double black_point,
const double white_point,
2961#define LevelImageTag "Level/Image"
2984 assert(image != (
Image *) NULL);
2985 assert(image->signature == MagickCoreSignature);
2986 if (IsEventLogging() != MagickFalse)
2987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2988 if (image->storage_class == PseudoClass)
2989 for (i=0; i < (ssize_t) image->colors; i++)
2994 if ((channel & RedChannel) != 0)
2995 image->colormap[i].red=(Quantum) ClampToQuantum(LevelPixel(black_point,
2996 white_point,gamma,(MagickRealType) image->colormap[i].red));
2997 if ((channel & GreenChannel) != 0)
2998 image->colormap[i].green=(Quantum) ClampToQuantum(LevelPixel(
2999 black_point,white_point,gamma,(MagickRealType)
3000 image->colormap[i].green));
3001 if ((channel & BlueChannel) != 0)
3002 image->colormap[i].blue=(Quantum) ClampToQuantum(LevelPixel(black_point,
3003 white_point,gamma,(MagickRealType) image->colormap[i].blue));
3004 if ((channel & OpacityChannel) != 0)
3005 image->colormap[i].opacity=(Quantum) (QuantumRange-(Quantum)
3006 ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3007 (MagickRealType) (QuantumRange-image->colormap[i].opacity))));
3014 exception=(&image->exception);
3015 image_view=AcquireAuthenticCacheView(image,exception);
3016#if defined(MAGICKCORE_OPENMP_SUPPORT)
3017 #pragma omp parallel for schedule(static) shared(progress,status) \
3018 magick_number_threads(image,image,image->rows,1)
3020 for (y=0; y < (ssize_t) image->rows; y++)
3023 *magick_restrict indexes;
3031 if (status == MagickFalse)
3033 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3039 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3040 for (x=0; x < (ssize_t) image->columns; x++)
3042 if ((channel & RedChannel) != 0)
3043 SetPixelRed(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3044 (MagickRealType) GetPixelRed(q))));
3045 if ((channel & GreenChannel) != 0)
3046 SetPixelGreen(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3047 (MagickRealType) GetPixelGreen(q))));
3048 if ((channel & BlueChannel) != 0)
3049 SetPixelBlue(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3050 (MagickRealType) GetPixelBlue(q))));
3051 if (((channel & OpacityChannel) != 0) &&
3052 (image->matte != MagickFalse))
3053 SetPixelAlpha(q,ClampToQuantum(LevelPixel(black_point,white_point,gamma,
3054 (MagickRealType) GetPixelAlpha(q))));
3055 if (((channel & IndexChannel) != 0) &&
3056 (image->colorspace == CMYKColorspace))
3057 SetPixelIndex(indexes+x,ClampToQuantum(LevelPixel(black_point,
3058 white_point,gamma,(MagickRealType) GetPixelIndex(indexes+x))));
3061 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3063 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3068#if defined(MAGICKCORE_OPENMP_SUPPORT)
3072 proceed=SetImageProgress(image,LevelImageTag,progress,image->rows);
3073 if (proceed == MagickFalse)
3077 image_view=DestroyCacheView(image_view);
3078 (void) ClampImage(image);
3125MagickExport MagickBooleanType LevelizeImage(
Image *image,
3126 const double black_point,
const double white_point,
const double gamma)
3131 status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
3136MagickExport MagickBooleanType LevelizeImageChannel(
Image *image,
3137 const ChannelType channel,
const double black_point,
const double white_point,
3140#define LevelizeImageTag "Levelize/Image"
3141#define LevelizeValue(x) ClampToQuantum(((MagickRealType) gamma_pow((double) \
3142 (QuantumScale*(double) (x)),gamma))*((double) white_point-(double) \
3143 black_point)+(double) black_point)
3166 assert(image != (
Image *) NULL);
3167 assert(image->signature == MagickCoreSignature);
3168 if (IsEventLogging() != MagickFalse)
3169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3170 if (image->storage_class == PseudoClass)
3171 for (i=0; i < (ssize_t) image->colors; i++)
3176 if ((channel & RedChannel) != 0)
3177 image->colormap[i].red=LevelizeValue(image->colormap[i].red);
3178 if ((channel & GreenChannel) != 0)
3179 image->colormap[i].green=LevelizeValue(image->colormap[i].green);
3180 if ((channel & BlueChannel) != 0)
3181 image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
3182 if ((channel & OpacityChannel) != 0)
3183 image->colormap[i].opacity=(Quantum) (QuantumRange-LevelizeValue(
3184 QuantumRange-image->colormap[i].opacity));
3191 exception=(&image->exception);
3192 image_view=AcquireAuthenticCacheView(image,exception);
3193#if defined(MAGICKCORE_OPENMP_SUPPORT)
3194 #pragma omp parallel for schedule(static) shared(progress,status) \
3195 magick_number_threads(image,image,image->rows,1)
3197 for (y=0; y < (ssize_t) image->rows; y++)
3200 *magick_restrict indexes;
3208 if (status == MagickFalse)
3210 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3216 indexes=GetCacheViewAuthenticIndexQueue(image_view);
3217 for (x=0; x < (ssize_t) image->columns; x++)
3219 if ((channel & RedChannel) != 0)
3220 SetPixelRed(q,LevelizeValue(GetPixelRed(q)));
3221 if ((channel & GreenChannel) != 0)
3222 SetPixelGreen(q,LevelizeValue(GetPixelGreen(q)));
3223 if ((channel & BlueChannel) != 0)
3224 SetPixelBlue(q,LevelizeValue(GetPixelBlue(q)));
3225 if (((channel & OpacityChannel) != 0) &&
3226 (image->matte != MagickFalse))
3227 SetPixelAlpha(q,LevelizeValue(GetPixelAlpha(q)));
3228 if (((channel & IndexChannel) != 0) &&
3229 (image->colorspace == CMYKColorspace))
3230 SetPixelIndex(indexes+x,LevelizeValue(GetPixelIndex(indexes+x)));
3233 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3235 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3240#if defined(MAGICKCORE_OPENMP_SUPPORT)
3244 proceed=SetImageProgress(image,LevelizeImageTag,progress,image->rows);
3245 if (proceed == MagickFalse)
3249 image_view=DestroyCacheView(image_view);
3298MagickExport MagickBooleanType LevelColorsImage(
Image *image,
3300 const MagickBooleanType invert)
3305 status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
3310MagickExport MagickBooleanType LevelColorsImageChannel(
Image *image,
3320 assert(image != (
Image *) NULL);
3321 assert(image->signature == MagickCoreSignature);
3322 if (IsEventLogging() != MagickFalse)
3323 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3324 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3325 ((IsGrayColorspace(black_color->colorspace) != MagickFalse) ||
3326 (IsGrayColorspace(white_color->colorspace) != MagickFalse)))
3327 (void) SetImageColorspace(image,sRGBColorspace);
3329 if (invert == MagickFalse)
3331 if ((channel & RedChannel) != 0)
3332 status&=LevelImageChannel(image,RedChannel,black_color->red,
3333 white_color->red,(
double) 1.0);
3334 if ((channel & GreenChannel) != 0)
3335 status&=LevelImageChannel(image,GreenChannel,black_color->green,
3336 white_color->green,(
double) 1.0);
3337 if ((channel & BlueChannel) != 0)
3338 status&=LevelImageChannel(image,BlueChannel,black_color->blue,
3339 white_color->blue,(
double) 1.0);
3340 if (((channel & OpacityChannel) != 0) &&
3341 (image->matte != MagickFalse))
3342 status&=LevelImageChannel(image,OpacityChannel,black_color->opacity,
3343 white_color->opacity,(
double) 1.0);
3344 if (((channel & IndexChannel) != 0) &&
3345 (image->colorspace == CMYKColorspace))
3346 status&=LevelImageChannel(image,IndexChannel,black_color->index,
3347 white_color->index,(
double) 1.0);
3351 if ((channel & RedChannel) != 0)
3352 status&=LevelizeImageChannel(image,RedChannel,black_color->red,
3353 white_color->red,(
double) 1.0);
3354 if ((channel & GreenChannel) != 0)
3355 status&=LevelizeImageChannel(image,GreenChannel,black_color->green,
3356 white_color->green,(
double) 1.0);
3357 if ((channel & BlueChannel) != 0)
3358 status&=LevelizeImageChannel(image,BlueChannel,black_color->blue,
3359 white_color->blue,(
double) 1.0);
3360 if (((channel & OpacityChannel) != 0) &&
3361 (image->matte != MagickFalse))
3362 status&=LevelizeImageChannel(image,OpacityChannel,black_color->opacity,
3363 white_color->opacity,(
double) 1.0);
3364 if (((channel & IndexChannel) != 0) &&
3365 (image->colorspace == CMYKColorspace))
3366 status&=LevelizeImageChannel(image,IndexChannel,black_color->index,
3367 white_color->index,(
double) 1.0);
3369 return(status == 0 ? MagickFalse : MagickTrue);
3400MagickExport MagickBooleanType LinearStretchImage(
Image *image,
3401 const double black_point,
const double white_point)
3403#define LinearStretchImageTag "LinearStretch/Image"
3423 assert(image != (
Image *) NULL);
3424 assert(image->signature == MagickCoreSignature);
3425 exception=(&image->exception);
3426 histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
3427 sizeof(*histogram));
3428 if (histogram == (MagickRealType *) NULL)
3429 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
3434 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
3435 for (y=0; y < (ssize_t) image->rows; y++)
3443 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3446 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3448 histogram[ScaleQuantumToMap(ClampToQuantum(GetPixelIntensity(image,p)))]++;
3456 for (black=0; black < (ssize_t) MaxMap; black++)
3458 intensity+=histogram[black];
3459 if (intensity >= black_point)
3463 for (white=(ssize_t) MaxMap; white != 0; white--)
3465 intensity+=histogram[white];
3466 if (intensity >= white_point)
3469 histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
3470 status=LevelImageChannel(image,DefaultChannels,(
double)
3471 ScaleMapToQuantum(black),(
double) ScaleMapToQuantum(white),1.0);
3505static inline void ModulateHCL(
const double percent_hue,
3506 const double percent_chroma,
const double percent_luma,Quantum *red,
3507 Quantum *green,Quantum *blue)
3517 ConvertRGBToHCL(*red,*green,*blue,&hue,&chroma,&luma);
3518 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3519 chroma*=0.01*percent_chroma;
3520 luma*=0.01*percent_luma;
3521 ConvertHCLToRGB(hue,chroma,luma,red,green,blue);
3524static inline void ModulateHCLp(
const double percent_hue,
3525 const double percent_chroma,
const double percent_luma,Quantum *red,
3526 Quantum *green,Quantum *blue)
3536 ConvertRGBToHCLp(*red,*green,*blue,&hue,&chroma,&luma);
3537 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3538 chroma*=0.01*percent_chroma;
3539 luma*=0.01*percent_luma;
3540 ConvertHCLpToRGB(hue,chroma,luma,red,green,blue);
3543static inline void ModulateHSB(
const double percent_hue,
3544 const double percent_saturation,
const double percent_brightness,Quantum *red,
3545 Quantum *green,Quantum *blue)
3555 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
3556 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3557 saturation*=0.01*percent_saturation;
3558 brightness*=0.01*percent_brightness;
3559 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
3562static inline void ModulateHSI(
const double percent_hue,
3563 const double percent_saturation,
const double percent_intensity,Quantum *red,
3564 Quantum *green,Quantum *blue)
3574 ConvertRGBToHSI(*red,*green,*blue,&hue,&saturation,&intensity);
3575 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3576 saturation*=0.01*percent_saturation;
3577 intensity*=0.01*percent_intensity;
3578 ConvertHSIToRGB(hue,saturation,intensity,red,green,blue);
3581static inline void ModulateHSL(
const double percent_hue,
3582 const double percent_saturation,
const double percent_lightness,Quantum *red,
3583 Quantum *green,Quantum *blue)
3593 ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
3594 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3595 saturation*=0.01*percent_saturation;
3596 lightness*=0.01*percent_lightness;
3597 ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
3600static inline void ModulateHSV(
const double percent_hue,
3601 const double percent_saturation,
const double percent_value,Quantum *red,
3602 Quantum *green,Quantum *blue)
3612 ConvertRGBToHSV(*red,*green,*blue,&hue,&saturation,&value);
3613 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3614 saturation*=0.01*percent_saturation;
3615 value*=0.01*percent_value;
3616 ConvertHSVToRGB(hue,saturation,value,red,green,blue);
3619static inline void ModulateHWB(
const double percent_hue,
3620 const double percent_whiteness,
const double percent_blackness,Quantum *red,
3621 Quantum *green,Quantum *blue)
3631 ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
3632 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3633 blackness*=0.01*percent_blackness;
3634 whiteness*=0.01*percent_whiteness;
3635 ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
3638static inline void ModulateLCHab(
const double percent_luma,
3639 const double percent_chroma,
const double percent_hue,Quantum *red,
3640 Quantum *green,Quantum *blue)
3650 ConvertRGBToLCHab(*red,*green,*blue,&luma,&chroma,&hue);
3651 luma*=0.01*percent_luma;
3652 chroma*=0.01*percent_chroma;
3653 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3654 ConvertLCHabToRGB(luma,chroma,hue,red,green,blue);
3657static inline void ModulateLCHuv(
const double percent_luma,
3658 const double percent_chroma,
const double percent_hue,Quantum *red,
3659 Quantum *green,Quantum *blue)
3669 ConvertRGBToLCHuv(*red,*green,*blue,&luma,&chroma,&hue);
3670 luma*=0.01*percent_luma;
3671 chroma*=0.01*percent_chroma;
3672 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3673 ConvertLCHuvToRGB(luma,chroma,hue,red,green,blue);
3676MagickExport MagickBooleanType ModulateImage(
Image *image,
const char *modulate)
3678#define ModulateImageTag "Modulate/Image"
3690 percent_brightness = 100.0,
3691 percent_hue = 100.0,
3692 percent_saturation = 100.0;
3718 assert(image != (
Image *) NULL);
3719 assert(image->signature == MagickCoreSignature);
3720 if (IsEventLogging() != MagickFalse)
3721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3722 if (modulate == (
char *) NULL)
3723 return(MagickFalse);
3724 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3725 (void) SetImageColorspace(image,sRGBColorspace);
3726 flags=ParseGeometry(modulate,&geometry_info);
3727 if ((flags & RhoValue) != 0)
3728 percent_brightness=geometry_info.rho;
3729 if ((flags & SigmaValue) != 0)
3730 percent_saturation=geometry_info.sigma;
3731 if ((flags & XiValue) != 0)
3732 percent_hue=geometry_info.xi;
3733 colorspace=UndefinedColorspace;
3734 artifact=GetImageArtifact(image,
"modulate:colorspace");
3735 if (artifact != (
const char *) NULL)
3736 colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
3737 MagickFalse,artifact);
3738 if (image->storage_class == PseudoClass)
3739 for (i=0; i < (ssize_t) image->colors; i++)
3749 red=image->colormap[i].red;
3750 green=image->colormap[i].green;
3751 blue=image->colormap[i].blue;
3756 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3760 case HCLpColorspace:
3762 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3768 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3774 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3781 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3787 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3793 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3797 case LCHabColorspace:
3800 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3804 case LCHuvColorspace:
3806 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3811 image->colormap[i].red=red;
3812 image->colormap[i].green=green;
3813 image->colormap[i].blue=blue;
3821#if defined(MAGICKCORE_OPENCL_SUPPORT)
3822 status=AccelerateModulateImage(image,percent_brightness,percent_hue,
3823 percent_saturation,colorspace,&image->exception);
3824 if (status != MagickFalse)
3829 exception=(&image->exception);
3830 image_view=AcquireAuthenticCacheView(image,exception);
3831#if defined(MAGICKCORE_OPENMP_SUPPORT)
3832 #pragma omp parallel for schedule(static) shared(progress,status) \
3833 magick_number_threads(image,image,image->rows,1)
3835 for (y=0; y < (ssize_t) image->rows; y++)
3843 if (status == MagickFalse)
3845 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3851 for (x=0; x < (ssize_t) image->columns; x++)
3859 green=GetPixelGreen(q);
3860 blue=GetPixelBlue(q);
3865 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3869 case HCLpColorspace:
3871 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3877 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3883 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3890 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3896 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3902 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3906 case LCHabColorspace:
3908 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3913 case LCHuvColorspace:
3915 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3921 SetPixelGreen(q,green);
3922 SetPixelBlue(q,blue);
3925 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3927 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3932#if defined(MAGICKCORE_OPENMP_SUPPORT)
3936 proceed=SetImageProgress(image,ModulateImageTag,progress,image->rows);
3937 if (proceed == MagickFalse)
3941 image_view=DestroyCacheView(image_view);
3976MagickExport MagickBooleanType NegateImage(
Image *image,
3977 const MagickBooleanType grayscale)
3982 status=NegateImageChannel(image,DefaultChannels,grayscale);
3986MagickExport MagickBooleanType NegateImageChannel(
Image *image,
3987 const ChannelType channel,
const MagickBooleanType grayscale)
3989#define NegateImageTag "Negate/Image"
4009 assert(image != (
Image *) NULL);
4010 assert(image->signature == MagickCoreSignature);
4011 if (IsEventLogging() != MagickFalse)
4012 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4013 if (image->storage_class == PseudoClass)
4018 for (i=0; i < (ssize_t) image->colors; i++)
4020 if (grayscale != MagickFalse)
4021 if ((image->colormap[i].red != image->colormap[i].green) ||
4022 (image->colormap[i].green != image->colormap[i].blue))
4024 if ((channel & RedChannel) != 0)
4025 image->colormap[i].red=QuantumRange-image->colormap[i].red;
4026 if ((channel & GreenChannel) != 0)
4027 image->colormap[i].green=QuantumRange-image->colormap[i].green;
4028 if ((channel & BlueChannel) != 0)
4029 image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
4037 exception=(&image->exception);
4038 image_view=AcquireAuthenticCacheView(image,exception);
4039 if (grayscale != MagickFalse)
4041#if defined(MAGICKCORE_OPENMP_SUPPORT)
4042 #pragma omp parallel for schedule(static) shared(progress,status) \
4043 magick_number_threads(image,image,image->rows,1)
4045 for (y=0; y < (ssize_t) image->rows; y++)
4051 *magick_restrict indexes;
4059 if (status == MagickFalse)
4061 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4068 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4069 for (x=0; x < (ssize_t) image->columns; x++)
4071 if ((GetPixelRed(q) != GetPixelGreen(q)) ||
4072 (GetPixelGreen(q) != GetPixelBlue(q)))
4077 if ((channel & RedChannel) != 0)
4078 SetPixelRed(q,QuantumRange-GetPixelRed(q));
4079 if ((channel & GreenChannel) != 0)
4080 SetPixelGreen(q,QuantumRange-GetPixelGreen(q));
4081 if ((channel & BlueChannel) != 0)
4082 SetPixelBlue(q,QuantumRange-GetPixelBlue(q));
4083 if ((channel & OpacityChannel) != 0)
4084 SetPixelOpacity(q,QuantumRange-GetPixelOpacity(q));
4085 if (((channel & IndexChannel) != 0) &&
4086 (image->colorspace == CMYKColorspace))
4087 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4090 sync=SyncCacheViewAuthenticPixels(image_view,exception);
4091 if (sync == MagickFalse)
4093 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4098#if defined(MAGICKCORE_OPENMP_SUPPORT)
4102 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4103 if (proceed == MagickFalse)
4107 image_view=DestroyCacheView(image_view);
4113#if defined(MAGICKCORE_OPENMP_SUPPORT)
4114 #pragma omp parallel for schedule(static) shared(progress,status) \
4115 magick_number_threads(image,image,image->rows,1)
4117 for (y=0; y < (ssize_t) image->rows; y++)
4120 *magick_restrict indexes;
4128 if (status == MagickFalse)
4130 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4136 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4137 if (channel == DefaultChannels)
4138 for (x=0; x < (ssize_t) image->columns; x++)
4140 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4141 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4142 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4145 for (x=0; x < (ssize_t) image->columns; x++)
4147 if ((channel & RedChannel) != 0)
4148 SetPixelRed(q+x,QuantumRange-GetPixelRed(q+x));
4149 if ((channel & GreenChannel) != 0)
4150 SetPixelGreen(q+x,QuantumRange-GetPixelGreen(q+x));
4151 if ((channel & BlueChannel) != 0)
4152 SetPixelBlue(q+x,QuantumRange-GetPixelBlue(q+x));
4153 if ((channel & OpacityChannel) != 0)
4154 SetPixelOpacity(q+x,QuantumRange-GetPixelOpacity(q+x));
4156 if (((channel & IndexChannel) != 0) &&
4157 (image->colorspace == CMYKColorspace))
4158 for (x=0; x < (ssize_t) image->columns; x++)
4159 SetPixelIndex(indexes+x,QuantumRange-GetPixelIndex(indexes+x));
4160 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4162 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4167#if defined(MAGICKCORE_OPENMP_SUPPORT)
4171 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4172 if (proceed == MagickFalse)
4176 image_view=DestroyCacheView(image_view);
4209MagickExport MagickBooleanType NormalizeImage(
Image *image)
4214 status=NormalizeImageChannel(image,DefaultChannels);
4218MagickExport MagickBooleanType NormalizeImageChannel(
Image *image,
4219 const ChannelType channel)
4225 black_point=0.02*image->columns*image->rows;
4226 white_point=0.99*image->columns*image->rows;
4227 return(ContrastStretchImageChannel(image,channel,black_point,white_point));
4296#if defined(MAGICKCORE_HAVE_ATANH)
4297#define Sigmoidal(a,b,x) ( tanh((0.5*(a))*((x)-(b))) )
4299#define Sigmoidal(a,b,x) ( 1.0/(1.0+exp((a)*((b)-(x)))) )
4318#define ScaledSigmoidal(a,b,x) ( \
4319 (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \
4320 (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) )
4330static inline double InverseScaledSigmoidal(
const double a,
const double b,
4333 const double sig0=Sigmoidal(a,b,0.0);
4334 const double sig1=Sigmoidal(a,b,1.0);
4335 const double argument=(sig1-sig0)*x+sig0;
4336 const double clamped=
4338#if defined(MAGICKCORE_HAVE_ATANH)
4339 argument < -1+MagickEpsilon
4343 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4345 return(b+(2.0/a)*atanh(clamped));
4347 argument < MagickEpsilon
4351 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4353 return(b-log(1.0/clamped-1.0)/a);
4357MagickExport MagickBooleanType SigmoidalContrastImage(
Image *image,
4358 const MagickBooleanType sharpen,
const char *levels)
4369 flags=ParseGeometry(levels,&geometry_info);
4370 if ((flags & SigmaValue) == 0)
4371 geometry_info.sigma=1.0*(double) QuantumRange/2.0;
4372 if ((flags & PercentValue) != 0)
4373 geometry_info.sigma=1.0*(double) QuantumRange*geometry_info.sigma/100.0;
4374 status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
4375 geometry_info.rho,geometry_info.sigma);
4379MagickExport MagickBooleanType SigmoidalContrastImageChannel(
Image *image,
4380 const ChannelType channel,
const MagickBooleanType sharpen,
4381 const double contrast,
const double midpoint)
4383#define SigmoidalContrastImageTag "SigmoidalContrast/Image"
4410 if (contrast < MagickEpsilon)
4415 assert(image != (
Image *) NULL);
4416 assert(image->signature == MagickCoreSignature);
4417 if (IsEventLogging() != MagickFalse)
4418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4419 exception=(&image->exception);
4420 sigmoidal_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
4421 sizeof(*sigmoidal_map));
4422 if (sigmoidal_map == (MagickRealType *) NULL)
4423 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
4425 (void) memset(sigmoidal_map,0,(MaxMap+1)*
sizeof(*sigmoidal_map));
4426 if (sharpen != MagickFalse)
4427 for (i=0; i <= (ssize_t) MaxMap; i++)
4428 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
4429 (MaxMap*ScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4432 for (i=0; i <= (ssize_t) MaxMap; i++)
4433 sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType) (
4434 MaxMap*InverseScaledSigmoidal(contrast,QuantumScale*midpoint,(
double) i/
4439 if (image->storage_class == PseudoClass)
4440 for (i=0; i < (ssize_t) image->colors; i++)
4442 if ((channel & RedChannel) != 0)
4443 image->colormap[i].red=ClampToQuantum(sigmoidal_map[
4444 ScaleQuantumToMap(image->colormap[i].red)]);
4445 if ((channel & GreenChannel) != 0)
4446 image->colormap[i].green=ClampToQuantum(sigmoidal_map[
4447 ScaleQuantumToMap(image->colormap[i].green)]);
4448 if ((channel & BlueChannel) != 0)
4449 image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
4450 ScaleQuantumToMap(image->colormap[i].blue)]);
4451 if ((channel & OpacityChannel) != 0)
4452 image->colormap[i].opacity=ClampToQuantum(sigmoidal_map[
4453 ScaleQuantumToMap(image->colormap[i].opacity)]);
4460 image_view=AcquireAuthenticCacheView(image,exception);
4461#if defined(MAGICKCORE_OPENMP_SUPPORT)
4462 #pragma omp parallel for schedule(static) shared(progress,status) \
4463 magick_number_threads(image,image,image->rows,1)
4465 for (y=0; y < (ssize_t) image->rows; y++)
4468 *magick_restrict indexes;
4476 if (status == MagickFalse)
4478 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4484 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4485 for (x=0; x < (ssize_t) image->columns; x++)
4487 if ((channel & RedChannel) != 0)
4488 SetPixelRed(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4490 if ((channel & GreenChannel) != 0)
4491 SetPixelGreen(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4492 GetPixelGreen(q))]));
4493 if ((channel & BlueChannel) != 0)
4494 SetPixelBlue(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4495 GetPixelBlue(q))]));
4496 if ((channel & OpacityChannel) != 0)
4497 SetPixelOpacity(q,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4498 GetPixelOpacity(q))]));
4499 if (((channel & IndexChannel) != 0) &&
4500 (image->colorspace == CMYKColorspace))
4501 SetPixelIndex(indexes+x,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
4502 GetPixelIndex(indexes+x))]));
4505 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4507 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4512#if defined(MAGICKCORE_OPENMP_SUPPORT)
4516 proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress,
4518 if (proceed == MagickFalse)
4522 image_view=DestroyCacheView(image_view);
4523 sigmoidal_map=(MagickRealType *) RelinquishMagickMemory(sigmoidal_map);