43 #include "MagickCore/studio.h"
44 #include "MagickCore/accelerate-private.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/cache-private.h"
49 #include "MagickCore/cache-view.h"
50 #include "MagickCore/channel.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/color-private.h"
53 #include "MagickCore/colorspace.h"
54 #include "MagickCore/colorspace-private.h"
55 #include "MagickCore/composite-private.h"
56 #include "MagickCore/enhance.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/fx.h"
60 #include "MagickCore/gem.h"
61 #include "MagickCore/gem-private.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/histogram.h"
64 #include "MagickCore/image.h"
65 #include "MagickCore/image-private.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/option.h"
70 #include "MagickCore/pixel.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/quantum.h"
73 #include "MagickCore/quantum-private.h"
74 #include "MagickCore/resample.h"
75 #include "MagickCore/resample-private.h"
76 #include "MagickCore/resource_.h"
77 #include "MagickCore/statistic.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/thread-private.h"
81 #include "MagickCore/threshold.h"
82 #include "MagickCore/token.h"
83 #include "MagickCore/xml-tree.h"
84 #include "MagickCore/xml-tree-private.h"
111 MagickExport MagickBooleanType AutoGammaImage(
Image *image,
127 if (image->channel_mask == DefaultChannels)
132 (void) GetImageMean(image,&mean,&sans,exception);
133 gamma=log(mean*QuantumScale)/log_mean;
134 return(LevelImage(image,0.0,(
double) QuantumRange,gamma,exception));
140 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
145 PixelChannel channel = GetPixelChannelChannel(image,i);
146 PixelTrait traits = GetPixelChannelTraits(image,channel);
147 if ((traits & UpdatePixelTrait) == 0)
149 channel_mask=SetImageChannelMask(image,(ChannelType) (1UL << i));
150 status=GetImageMean(image,&mean,&sans,exception);
151 gamma=log(mean*QuantumScale)/log_mean;
152 status&=LevelImage(image,0.0,(
double) QuantumRange,gamma,exception);
153 (void) SetImageChannelMask(image,channel_mask);
154 if (status == MagickFalse)
157 return(status != 0 ? MagickTrue : MagickFalse);
185 MagickExport MagickBooleanType AutoLevelImage(
Image *image,
188 return(MinMaxStretchImage(image,0.0,0.0,1.0,exception));
222 MagickExport MagickBooleanType BrightnessContrastImage(
Image *image,
223 const double brightness,
const double contrast,
ExceptionInfo *exception)
225 #define BrightnessContastImageTag "BrightnessContast/Image"
239 assert(image != (
Image *) NULL);
240 assert(image->signature == MagickCoreSignature);
241 if (IsEventLogging() != MagickFalse)
242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
244 slope=tan((
double) (MagickPI*(alpha/100.0+1.0)/4.0));
247 intercept=brightness/100.0+((100-brightness)/200.0)*(1.0-slope);
248 coefficients[0]=slope;
249 coefficients[1]=intercept;
250 status=FunctionImage(image,PolynomialFunction,2,coefficients,exception);
302 static void ClipCLAHEHistogram(
const double clip_limit,
const size_t number_bins,
305 #define NumberCLAHEGrays (65536)
321 if (number_bins == 0)
324 for (i=0; i < (ssize_t) number_bins; i++)
326 excess=(ssize_t) histogram[i]-(ssize_t) clip_limit;
328 cumulative_excess+=excess;
333 step=cumulative_excess/number_bins;
334 excess=(ssize_t) (clip_limit-step);
335 for (i=0; i < (ssize_t) number_bins; i++)
337 if ((
double) histogram[i] > clip_limit)
338 histogram[i]=(
size_t) clip_limit;
340 if ((ssize_t) histogram[i] > excess)
342 cumulative_excess-=histogram[i]-excess;
343 histogram[i]=(size_t) clip_limit;
347 cumulative_excess-=step;
362 previous_excess=cumulative_excess;
364 q=histogram+number_bins;
365 while ((cumulative_excess != 0) && (p < q))
367 step=number_bins/cumulative_excess;
370 for (p=histogram; (p < q) && (cumulative_excess != 0); p+=step)
371 if ((
double) *p < clip_limit)
378 }
while ((cumulative_excess != 0) && (cumulative_excess < previous_excess));
381 static void GenerateCLAHEHistogram(
const RectangleInfo *clahe_info,
383 const unsigned short *lut,
const unsigned short *pixels,
size_t *histogram)
394 for (i=0; i < (ssize_t) number_bins; i++)
397 for (i=0; i < (ssize_t) tile_info->height; i++)
402 q=p+tile_info->width;
404 histogram[lut[*p++]]++;
405 q+=clahe_info->width;
406 p=q-tile_info->width;
410 static void InterpolateCLAHE(
const RectangleInfo *clahe_info,
const size_t *Q12,
411 const size_t *Q22,
const size_t *Q11,
const size_t *Q21,
412 const RectangleInfo *tile,
const unsigned short *lut,
unsigned short *pixels)
423 for (y=(ssize_t) tile->height; y > 0; y--)
428 for (x=(ssize_t) tile->width; x > 0; x--)
430 intensity=lut[*pixels];
431 *pixels++=(
unsigned short) (PerceptibleReciprocal((
double) tile->width*
432 tile->height)*(y*((double) x*Q12[intensity]+(tile->width-x)*
433 Q22[intensity])+(tile->height-y)*((double) x*Q11[intensity]+
434 (tile->width-x)*Q21[intensity])));
436 pixels+=(clahe_info->width-tile->width);
440 static void GenerateCLAHELut(
const RangeInfo *range_info,
441 const size_t number_bins,
unsigned short *lut)
452 delta=(
unsigned short) ((range_info->max-range_info->min)/number_bins+1);
453 for (i=(ssize_t) range_info->min; i <= (ssize_t) range_info->max; i++)
454 lut[i]=(
unsigned short) ((i-range_info->min)/delta);
457 static void MapCLAHEHistogram(
const RangeInfo *range_info,
458 const size_t number_bins,
const size_t number_pixels,
size_t *histogram)
470 scale=(double) (range_info->max-range_info->min)/number_pixels;
472 for (i=0; i < (ssize_t) number_bins; i++)
475 histogram[i]=(size_t) (range_info->min+scale*sum);
476 if (histogram[i] > range_info->max)
477 histogram[i]=range_info->max;
481 static MagickBooleanType CLAHE(
const RectangleInfo *clahe_info,
483 const size_t number_bins,
const double clip_limit,
unsigned short *pixels)
504 if (clip_limit == 1.0)
506 tile_cache=AcquireVirtualMemory((
size_t) clahe_info->x*number_bins,
507 clahe_info->y*
sizeof(*tiles));
510 lut=(
unsigned short *) AcquireQuantumMemory(NumberCLAHEGrays,
sizeof(*lut));
511 if (lut == (
unsigned short *) NULL)
513 tile_cache=RelinquishVirtualMemory(tile_cache);
516 tiles=(
size_t *) GetVirtualMemoryBlob(tile_cache);
517 limit=(size_t) (clip_limit*(tile_info->width*tile_info->height)/number_bins);
523 GenerateCLAHELut(range_info,number_bins,lut);
525 for (y=0; y < (ssize_t) clahe_info->y; y++)
530 for (x=0; x < (ssize_t) clahe_info->x; x++)
535 histogram=tiles+(number_bins*(y*clahe_info->x+x));
536 GenerateCLAHEHistogram(clahe_info,tile_info,number_bins,lut,p,histogram);
537 ClipCLAHEHistogram((
double) limit,number_bins,histogram);
538 MapCLAHEHistogram(range_info,number_bins,tile_info->width*
539 tile_info->height,histogram);
542 p+=clahe_info->width*(tile_info->height-1);
548 for (y=0; y <= (ssize_t) clahe_info->y; y++)
559 tile.height=tile_info->height;
567 tile.height=tile_info->height >> 1;
572 if (y == (ssize_t) clahe_info->y)
577 tile.height=(tile_info->height+1) >> 1;
578 tile.y=clahe_info->y-1;
581 for (x=0; x <= (ssize_t) clahe_info->x; x++)
583 tile.width=tile_info->width;
591 tile.width=tile_info->width >> 1;
596 if (x == (ssize_t) clahe_info->x)
601 tile.width=(tile_info->width+1) >> 1;
602 tile.x=clahe_info->x-1;
605 InterpolateCLAHE(clahe_info,
606 tiles+(number_bins*(tile.y*clahe_info->x+tile.x)),
607 tiles+(number_bins*(tile.y*clahe_info->x+offset.x)),
608 tiles+(number_bins*(offset.y*clahe_info->x+tile.x)),
609 tiles+(number_bins*(offset.y*clahe_info->x+offset.x)),
613 p+=clahe_info->width*(tile.height-1);
615 lut=(
unsigned short *) RelinquishMagickMemory(lut);
616 tile_cache=RelinquishVirtualMemory(tile_cache);
620 MagickExport MagickBooleanType CLAHEImage(
Image *image,
const size_t width,
621 const size_t height,
const size_t number_bins,
const double clip_limit,
624 #define CLAHEImageTag "CLAHE/Image"
660 assert(image != (
Image *) NULL);
661 assert(image->signature == MagickCoreSignature);
662 if (IsEventLogging() != MagickFalse)
663 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
665 range_info.max=NumberCLAHEGrays-1;
666 tile_info.width=width;
667 if (tile_info.width == 0)
668 tile_info.width=image->columns >> 3;
669 tile_info.height=height;
670 if (tile_info.height == 0)
671 tile_info.height=image->rows >> 3;
673 if ((image->columns % tile_info.width) != 0)
674 tile_info.x=(ssize_t) tile_info.width-(image->columns % tile_info.width);
676 if ((image->rows % tile_info.height) != 0)
677 tile_info.y=(ssize_t) tile_info.height-(image->rows % tile_info.height);
678 clahe_info.width=image->columns+tile_info.x;
679 clahe_info.height=image->rows+tile_info.y;
680 clahe_info.x=(ssize_t) clahe_info.width/tile_info.width;
681 clahe_info.y=(ssize_t) clahe_info.height/tile_info.height;
682 pixel_cache=AcquireVirtualMemory(clahe_info.width,clahe_info.height*
685 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
687 pixels=(
unsigned short *) GetVirtualMemoryBlob(pixel_cache);
688 colorspace=image->colorspace;
689 if (TransformImageColorspace(image,LabColorspace,exception) == MagickFalse)
691 pixel_cache=RelinquishVirtualMemory(pixel_cache);
697 image_view=AcquireVirtualCacheView(image,exception);
701 for (y=0; y < (ssize_t) clahe_info.height; y++)
709 if (status == MagickFalse)
711 p=GetCacheViewVirtualPixels(image_view,-(tile_info.x >> 1),y-
712 (tile_info.y >> 1),clahe_info.width,1,exception);
713 if (p == (
const Quantum *) NULL)
718 for (x=0; x < (ssize_t) clahe_info.width; x++)
720 pixels[n++]=ScaleQuantumToShort(p[0]);
721 p+=GetPixelChannels(image);
723 if (image->progress_monitor != (MagickProgressMonitor) NULL)
729 proceed=SetImageProgress(image,CLAHEImageTag,progress,2*
730 GetPixelChannels(image));
731 if (proceed == MagickFalse)
735 image_view=DestroyCacheView(image_view);
736 status=CLAHE(&clahe_info,&tile_info,&range_info,number_bins == 0 ?
737 (
size_t) 128 : MagickMin(number_bins,256),clip_limit,pixels);
738 if (status == MagickFalse)
739 (void) ThrowMagickException(exception,GetMagickModule(),
740 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
744 image_view=AcquireAuthenticCacheView(image,exception);
745 n=clahe_info.width*(tile_info.y >> 1);
746 for (y=0; y < (ssize_t) image->rows; y++)
754 if (status == MagickFalse)
756 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
757 if (q == (Quantum *) NULL)
763 for (x=0; x < (ssize_t) image->columns; x++)
765 q[0]=ScaleShortToQuantum(pixels[n++]);
766 q+=GetPixelChannels(image);
768 n+=(clahe_info.width-image->columns-(tile_info.x >> 1));
769 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
771 if (image->progress_monitor != (MagickProgressMonitor) NULL)
777 proceed=SetImageProgress(image,CLAHEImageTag,progress,2*
778 GetPixelChannels(image));
779 if (proceed == MagickFalse)
783 image_view=DestroyCacheView(image_view);
784 pixel_cache=RelinquishVirtualMemory(pixel_cache);
785 if (TransformImageColorspace(image,colorspace,exception) == MagickFalse)
835 MagickExport MagickBooleanType ClutImage(
Image *image,
const Image *clut_image,
836 const PixelInterpolateMethod method,
ExceptionInfo *exception)
838 #define ClutImageTag "Clut/Image"
859 assert(image != (
Image *) NULL);
860 assert(image->signature == MagickCoreSignature);
861 assert(clut_image != (
Image *) NULL);
862 assert(clut_image->signature == MagickCoreSignature);
863 if (IsEventLogging() != MagickFalse)
864 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
865 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
867 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
868 (IsGrayColorspace(clut_image->colorspace) == MagickFalse))
869 (void) SetImageColorspace(image,sRGBColorspace,exception);
870 clut_map=(
PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*clut_map));
872 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
879 adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
880 clut_view=AcquireVirtualCacheView(clut_image,exception);
881 for (i=0; i <= (ssize_t) MaxMap; i++)
883 GetPixelInfo(clut_image,clut_map+i);
884 status=InterpolatePixelInfo(clut_image,clut_view,method,
885 (
double) i*(clut_image->columns-adjust)/MaxMap,(
double) i*
886 (clut_image->rows-adjust)/MaxMap,clut_map+i,exception);
887 if (status == MagickFalse)
890 clut_view=DestroyCacheView(clut_view);
891 image_view=AcquireAuthenticCacheView(image,exception);
892 #if defined(MAGICKCORE_OPENMP_SUPPORT)
893 #pragma omp parallel for schedule(static) shared(progress,status) \
894 magick_number_threads(image,image,image->rows,1)
896 for (y=0; y < (ssize_t) image->rows; y++)
907 if (status == MagickFalse)
909 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
910 if (q == (Quantum *) NULL)
915 GetPixelInfo(image,&pixel);
916 for (x=0; x < (ssize_t) image->columns; x++)
921 GetPixelInfoPixel(image,q,&pixel);
922 traits=GetPixelChannelTraits(image,RedPixelChannel);
923 if ((traits & UpdatePixelTrait) != 0)
924 pixel.red=clut_map[ScaleQuantumToMap(ClampToQuantum(
926 traits=GetPixelChannelTraits(image,GreenPixelChannel);
927 if ((traits & UpdatePixelTrait) != 0)
928 pixel.green=clut_map[ScaleQuantumToMap(ClampToQuantum(
929 pixel.green))].green;
930 traits=GetPixelChannelTraits(image,BluePixelChannel);
931 if ((traits & UpdatePixelTrait) != 0)
932 pixel.blue=clut_map[ScaleQuantumToMap(ClampToQuantum(
934 traits=GetPixelChannelTraits(image,BlackPixelChannel);
935 if ((traits & UpdatePixelTrait) != 0)
936 pixel.black=clut_map[ScaleQuantumToMap(ClampToQuantum(
937 pixel.black))].black;
938 traits=GetPixelChannelTraits(image,AlphaPixelChannel);
939 if ((traits & UpdatePixelTrait) != 0)
940 pixel.alpha=clut_map[ScaleQuantumToMap(ClampToQuantum(
941 pixel.alpha))].alpha;
942 SetPixelViaPixelInfo(image,&pixel,q);
943 q+=GetPixelChannels(image);
945 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
947 if (image->progress_monitor != (MagickProgressMonitor) NULL)
952 #if defined(MAGICKCORE_OPENMP_SUPPORT)
956 proceed=SetImageProgress(image,ClutImageTag,progress,image->rows);
957 if (proceed == MagickFalse)
961 image_view=DestroyCacheView(image_view);
962 clut_map=(
PixelInfo *) RelinquishMagickMemory(clut_map);
963 if ((clut_image->alpha_trait != UndefinedPixelTrait) &&
964 ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0))
965 (
void) SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
1014 MagickExport MagickBooleanType ColorDecisionListImage(
Image *image,
1015 const char *color_correction_collection,
ExceptionInfo *exception)
1017 #define ColorDecisionListCorrectImageTag "ColorDecisionList/Image"
1019 typedef struct _Correction
1027 typedef struct _ColorCorrection
1042 token[MagickPathExtent];
1075 assert(image != (
Image *) NULL);
1076 assert(image->signature == MagickCoreSignature);
1077 if (IsEventLogging() != MagickFalse)
1078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1079 if (color_correction_collection == (
const char *) NULL)
1080 return(MagickFalse);
1081 ccc=NewXMLTree((
const char *) color_correction_collection,exception);
1083 return(MagickFalse);
1084 cc=GetXMLTreeChild(ccc,
"ColorCorrection");
1087 ccc=DestroyXMLTree(ccc);
1088 return(MagickFalse);
1090 color_correction.red.slope=1.0;
1091 color_correction.red.offset=0.0;
1092 color_correction.red.power=1.0;
1093 color_correction.green.slope=1.0;
1094 color_correction.green.offset=0.0;
1095 color_correction.green.power=1.0;
1096 color_correction.blue.slope=1.0;
1097 color_correction.blue.offset=0.0;
1098 color_correction.blue.power=1.0;
1099 color_correction.saturation=0.0;
1100 sop=GetXMLTreeChild(cc,
"SOPNode");
1108 slope=GetXMLTreeChild(sop,
"Slope");
1111 content=GetXMLTreeContent(slope);
1112 p=(
const char *) content;
1113 for (i=0; (*p !=
'\0') && (i < 3); i++)
1115 (void) GetNextToken(p,&p,MagickPathExtent,token);
1117 (void) GetNextToken(p,&p,MagickPathExtent,token);
1122 color_correction.red.slope=StringToDouble(token,(
char **) NULL);
1127 color_correction.green.slope=StringToDouble(token,
1133 color_correction.blue.slope=StringToDouble(token,
1140 offset=GetXMLTreeChild(sop,
"Offset");
1143 content=GetXMLTreeContent(offset);
1144 p=(
const char *) content;
1145 for (i=0; (*p !=
'\0') && (i < 3); i++)
1147 (void) GetNextToken(p,&p,MagickPathExtent,token);
1149 (void) GetNextToken(p,&p,MagickPathExtent,token);
1154 color_correction.red.offset=StringToDouble(token,
1160 color_correction.green.offset=StringToDouble(token,
1166 color_correction.blue.offset=StringToDouble(token,
1173 power=GetXMLTreeChild(sop,
"Power");
1176 content=GetXMLTreeContent(power);
1177 p=(
const char *) content;
1178 for (i=0; (*p !=
'\0') && (i < 3); i++)
1180 (void) GetNextToken(p,&p,MagickPathExtent,token);
1182 (void) GetNextToken(p,&p,MagickPathExtent,token);
1187 color_correction.red.power=StringToDouble(token,(
char **) NULL);
1192 color_correction.green.power=StringToDouble(token,
1198 color_correction.blue.power=StringToDouble(token,
1206 sat=GetXMLTreeChild(cc,
"SATNode");
1212 saturation=GetXMLTreeChild(sat,
"Saturation");
1215 content=GetXMLTreeContent(saturation);
1216 p=(
const char *) content;
1217 (void) GetNextToken(p,&p,MagickPathExtent,token);
1218 color_correction.saturation=StringToDouble(token,(
char **) NULL);
1221 ccc=DestroyXMLTree(ccc);
1222 if (image->debug != MagickFalse)
1224 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1225 " Color Correction Collection:");
1226 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1227 " color_correction.red.slope: %g",color_correction.red.slope);
1228 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1229 " color_correction.red.offset: %g",color_correction.red.offset);
1230 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1231 " color_correction.red.power: %g",color_correction.red.power);
1232 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1233 " color_correction.green.slope: %g",color_correction.green.slope);
1234 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1235 " color_correction.green.offset: %g",color_correction.green.offset);
1236 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1237 " color_correction.green.power: %g",color_correction.green.power);
1238 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1239 " color_correction.blue.slope: %g",color_correction.blue.slope);
1240 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1241 " color_correction.blue.offset: %g",color_correction.blue.offset);
1242 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1243 " color_correction.blue.power: %g",color_correction.blue.power);
1244 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1245 " color_correction.saturation: %g",color_correction.saturation);
1247 cdl_map=(
PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*cdl_map));
1249 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1251 for (i=0; i <= (ssize_t) MaxMap; i++)
1253 cdl_map[i].red=(double) ScaleMapToQuantum((
double)
1254 (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
1255 color_correction.red.offset,color_correction.red.power))));
1256 cdl_map[i].green=(double) ScaleMapToQuantum((
double)
1257 (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
1258 color_correction.green.offset,color_correction.green.power))));
1259 cdl_map[i].blue=(double) ScaleMapToQuantum((
double)
1260 (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
1261 color_correction.blue.offset,color_correction.blue.power))));
1263 if (image->storage_class == PseudoClass)
1264 for (i=0; i < (ssize_t) image->colors; i++)
1272 luma=0.21267f*image->colormap[i].red+0.71526*image->colormap[i].green+
1273 0.07217f*image->colormap[i].blue;
1274 image->colormap[i].red=luma+color_correction.saturation*cdl_map[
1275 ScaleQuantumToMap(ClampToQuantum(image->colormap[i].red))].red-luma;
1276 image->colormap[i].green=luma+color_correction.saturation*cdl_map[
1277 ScaleQuantumToMap(ClampToQuantum(image->colormap[i].green))].green-luma;
1278 image->colormap[i].blue=luma+color_correction.saturation*cdl_map[
1279 ScaleQuantumToMap(ClampToQuantum(image->colormap[i].blue))].blue-luma;
1286 image_view=AcquireAuthenticCacheView(image,exception);
1287 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1288 #pragma omp parallel for schedule(static) shared(progress,status) \
1289 magick_number_threads(image,image,image->rows,1)
1291 for (y=0; y < (ssize_t) image->rows; y++)
1302 if (status == MagickFalse)
1304 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1305 if (q == (Quantum *) NULL)
1310 for (x=0; x < (ssize_t) image->columns; x++)
1312 luma=0.21267f*GetPixelRed(image,q)+0.71526*GetPixelGreen(image,q)+
1313 0.07217f*GetPixelBlue(image,q);
1314 SetPixelRed(image,ClampToQuantum(luma+color_correction.saturation*
1315 (cdl_map[ScaleQuantumToMap(GetPixelRed(image,q))].red-luma)),q);
1316 SetPixelGreen(image,ClampToQuantum(luma+color_correction.saturation*
1317 (cdl_map[ScaleQuantumToMap(GetPixelGreen(image,q))].green-luma)),q);
1318 SetPixelBlue(image,ClampToQuantum(luma+color_correction.saturation*
1319 (cdl_map[ScaleQuantumToMap(GetPixelBlue(image,q))].blue-luma)),q);
1320 q+=GetPixelChannels(image);
1322 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1324 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1329 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1333 proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
1334 progress,image->rows);
1335 if (proceed == MagickFalse)
1339 image_view=DestroyCacheView(image_view);
1340 cdl_map=(
PixelInfo *) RelinquishMagickMemory(cdl_map);
1374 static void Contrast(
const int sign,
double *red,
double *green,
double *blue)
1384 assert(red != (
double *) NULL);
1385 assert(green != (
double *) NULL);
1386 assert(blue != (
double *) NULL);
1390 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
1391 brightness+=0.5*sign*(0.5*(sin((
double) (MagickPI*(brightness-0.5)))+1.0)-
1393 if (brightness > 1.0)
1396 if (brightness < 0.0)
1398 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
1401 MagickExport MagickBooleanType ContrastImage(
Image *image,
1404 #define ContrastImageTag "Contrast/Image"
1424 assert(image != (
Image *) NULL);
1425 assert(image->signature == MagickCoreSignature);
1426 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1427 if (AccelerateContrastImage(image,sharpen,exception) != MagickFalse)
1430 if (IsEventLogging() != MagickFalse)
1431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1432 sign=sharpen != MagickFalse ? 1 : -1;
1433 if (image->storage_class == PseudoClass)
1438 for (i=0; i < (ssize_t) image->colors; i++)
1445 red=(double) image->colormap[i].red;
1446 green=(
double) image->colormap[i].green;
1447 blue=(double) image->colormap[i].blue;
1448 Contrast(sign,&red,&green,&blue);
1449 image->colormap[i].red=(MagickRealType) red;
1450 image->colormap[i].green=(MagickRealType) green;
1451 image->colormap[i].blue=(MagickRealType) blue;
1459 image_view=AcquireAuthenticCacheView(image,exception);
1460 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1461 #pragma omp parallel for schedule(static) shared(progress,status) \
1462 magick_number_threads(image,image,image->rows,1)
1464 for (y=0; y < (ssize_t) image->rows; y++)
1477 if (status == MagickFalse)
1479 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1480 if (q == (Quantum *) NULL)
1485 for (x=0; x < (ssize_t) image->columns; x++)
1487 red=(double) GetPixelRed(image,q);
1488 green=(double) GetPixelGreen(image,q);
1489 blue=(double) GetPixelBlue(image,q);
1490 Contrast(sign,&red,&green,&blue);
1491 SetPixelRed(image,ClampToQuantum(red),q);
1492 SetPixelGreen(image,ClampToQuantum(green),q);
1493 SetPixelBlue(image,ClampToQuantum(blue),q);
1494 q+=GetPixelChannels(image);
1496 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1498 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1503 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1507 proceed=SetImageProgress(image,ContrastImageTag,progress,image->rows);
1508 if (proceed == MagickFalse)
1512 image_view=DestroyCacheView(image_view);
1553 MagickExport MagickBooleanType ContrastStretchImage(
Image *image,
1554 const double black_point,
const double white_point,
ExceptionInfo *exception)
1556 #define MaxRange(color) ((double) ScaleQuantumToMap((Quantum) (color)))
1557 #define ContrastStretchImageTag "ContrastStretch/Image"
1586 assert(image != (
Image *) NULL);
1587 assert(image->signature == MagickCoreSignature);
1588 if (IsEventLogging() != MagickFalse)
1589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1590 type=IdentifyImageType(image,exception);
1591 if (IsGrayImageType(type) != MagickFalse)
1592 (void) SetImageColorspace(image,GRAYColorspace,exception);
1593 black=(
double *) AcquireQuantumMemory(MaxPixelChannels,
sizeof(*black));
1594 white=(
double *) AcquireQuantumMemory(MaxPixelChannels,
sizeof(*white));
1595 histogram=(
double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
1596 sizeof(*histogram));
1597 stretch_map=(
double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
1598 sizeof(*stretch_map));
1599 if ((black == (
double *) NULL) || (white == (
double *) NULL) ||
1600 (histogram == (
double *) NULL) || (stretch_map == (
double *) NULL))
1602 if (stretch_map != (
double *) NULL)
1603 stretch_map=(
double *) RelinquishMagickMemory(stretch_map);
1604 if (histogram != (
double *) NULL)
1605 histogram=(
double *) RelinquishMagickMemory(histogram);
1606 if (white != (
double *) NULL)
1607 white=(
double *) RelinquishMagickMemory(white);
1608 if (black != (
double *) NULL)
1609 black=(
double *) RelinquishMagickMemory(black);
1610 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
1617 (void) memset(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
1618 sizeof(*histogram));
1619 image_view=AcquireVirtualCacheView(image,exception);
1620 for (y=0; y < (ssize_t) image->rows; y++)
1628 if (status == MagickFalse)
1630 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1631 if (p == (
const Quantum *) NULL)
1636 for (x=0; x < (ssize_t) image->columns; x++)
1641 pixel=GetPixelIntensity(image,p);
1642 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1644 if (image->channel_mask != DefaultChannels)
1645 pixel=(double) p[i];
1646 histogram[GetPixelChannels(image)*ScaleQuantumToMap(
1647 ClampToQuantum(pixel))+i]++;
1649 p+=GetPixelChannels(image);
1652 image_view=DestroyCacheView(image_view);
1656 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1665 white[i]=MaxRange(QuantumRange);
1667 for (j=0; j <= (ssize_t) MaxMap; j++)
1669 intensity+=histogram[GetPixelChannels(image)*j+i];
1670 if (intensity > black_point)
1673 black[i]=(double) j;
1675 for (j=(ssize_t) MaxMap; j != 0; j--)
1677 intensity+=histogram[GetPixelChannels(image)*j+i];
1678 if (intensity > ((
double) image->columns*image->rows-white_point))
1681 white[i]=(double) j;
1683 histogram=(
double *) RelinquishMagickMemory(histogram);
1687 (void) memset(stretch_map,0,(MaxMap+1)*GetPixelChannels(image)*
1688 sizeof(*stretch_map));
1689 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1694 for (j=0; j <= (ssize_t) MaxMap; j++)
1699 gamma=PerceptibleReciprocal(white[i]-black[i]);
1700 if (j < (ssize_t) black[i])
1701 stretch_map[GetPixelChannels(image)*j+i]=0.0;
1703 if (j > (ssize_t) white[i])
1704 stretch_map[GetPixelChannels(image)*j+i]=(double) QuantumRange;
1706 if (black[i] != white[i])
1707 stretch_map[GetPixelChannels(image)*j+i]=(double) ScaleMapToQuantum(
1708 (
double) (MaxMap*gamma*(j-black[i])));
1711 if (image->storage_class == PseudoClass)
1719 for (j=0; j < (ssize_t) image->colors; j++)
1721 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1723 i=GetPixelChannelOffset(image,RedPixelChannel);
1724 image->colormap[j].red=stretch_map[GetPixelChannels(image)*
1725 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].red))+i];
1727 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1729 i=GetPixelChannelOffset(image,GreenPixelChannel);
1730 image->colormap[j].green=stretch_map[GetPixelChannels(image)*
1731 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].green))+i];
1733 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1735 i=GetPixelChannelOffset(image,BluePixelChannel);
1736 image->colormap[j].blue=stretch_map[GetPixelChannels(image)*
1737 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].blue))+i];
1739 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1741 i=GetPixelChannelOffset(image,AlphaPixelChannel);
1742 image->colormap[j].alpha=stretch_map[GetPixelChannels(image)*
1743 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].alpha))+i];
1752 image_view=AcquireAuthenticCacheView(image,exception);
1753 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1754 #pragma omp parallel for schedule(static) shared(progress,status) \
1755 magick_number_threads(image,image,image->rows,1)
1757 for (y=0; y < (ssize_t) image->rows; y++)
1765 if (status == MagickFalse)
1767 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1768 if (q == (Quantum *) NULL)
1773 for (x=0; x < (ssize_t) image->columns; x++)
1778 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
1780 PixelChannel channel = GetPixelChannelChannel(image,j);
1781 PixelTrait traits = GetPixelChannelTraits(image,channel);
1782 if ((traits & UpdatePixelTrait) == 0)
1784 if (black[j] == white[j])
1786 q[j]=ClampToQuantum(stretch_map[GetPixelChannels(image)*
1787 ScaleQuantumToMap(q[j])+j]);
1789 q+=GetPixelChannels(image);
1791 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1793 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1798 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1802 proceed=SetImageProgress(image,ContrastStretchImageTag,progress,
1804 if (proceed == MagickFalse)
1808 image_view=DestroyCacheView(image_view);
1809 stretch_map=(
double *) RelinquishMagickMemory(stretch_map);
1810 white=(
double *) RelinquishMagickMemory(white);
1811 black=(
double *) RelinquishMagickMemory(black);
1842 #define EnhanceImageTag "Enhance/Image"
1843 #define EnhancePixel(weight) \
1844 mean=QuantumScale*((double) GetPixelRed(image,r)+pixel.red)/2.0; \
1845 distance=QuantumScale*((double) GetPixelRed(image,r)-pixel.red); \
1846 distance_squared=(4.0+mean)*distance*distance; \
1847 mean=QuantumScale*((double) GetPixelGreen(image,r)+pixel.green)/2.0; \
1848 distance=QuantumScale*((double) GetPixelGreen(image,r)-pixel.green); \
1849 distance_squared+=(7.0-mean)*distance*distance; \
1850 mean=QuantumScale*((double) GetPixelBlue(image,r)+pixel.blue)/2.0; \
1851 distance=QuantumScale*((double) GetPixelBlue(image,r)-pixel.blue); \
1852 distance_squared+=(5.0-mean)*distance*distance; \
1853 mean=QuantumScale*((double) GetPixelBlack(image,r)+pixel.black)/2.0; \
1854 distance=QuantumScale*((double) GetPixelBlack(image,r)-pixel.black); \
1855 distance_squared+=(5.0-mean)*distance*distance; \
1856 mean=QuantumScale*((double) GetPixelAlpha(image,r)+pixel.alpha)/2.0; \
1857 distance=QuantumScale*((double) GetPixelAlpha(image,r)-pixel.alpha); \
1858 distance_squared+=(5.0-mean)*distance*distance; \
1859 if (distance_squared < 0.069) \
1861 aggregate.red+=(weight)*GetPixelRed(image,r); \
1862 aggregate.green+=(weight)*GetPixelGreen(image,r); \
1863 aggregate.blue+=(weight)*GetPixelBlue(image,r); \
1864 aggregate.black+=(weight)*GetPixelBlack(image,r); \
1865 aggregate.alpha+=(weight)*GetPixelAlpha(image,r); \
1866 total_weight+=(weight); \
1868 r+=GetPixelChannels(image);
1889 assert(image != (
const Image *) NULL);
1890 assert(image->signature == MagickCoreSignature);
1891 if (IsEventLogging() != MagickFalse)
1892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1894 assert(exception->signature == MagickCoreSignature);
1895 enhance_image=CloneImage(image,0,0,MagickTrue,
1897 if (enhance_image == (
Image *) NULL)
1898 return((
Image *) NULL);
1899 if (SetImageStorageClass(enhance_image,DirectClass,exception) == MagickFalse)
1901 enhance_image=DestroyImage(enhance_image);
1902 return((
Image *) NULL);
1909 image_view=AcquireVirtualCacheView(image,exception);
1910 enhance_view=AcquireAuthenticCacheView(enhance_image,exception);
1911 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1912 #pragma omp parallel for schedule(static) shared(progress,status) \
1913 magick_number_threads(image,enhance_image,image->rows,1)
1915 for (y=0; y < (ssize_t) image->rows; y++)
1932 if (status == MagickFalse)
1934 p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
1935 q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
1937 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
1942 center=(ssize_t) GetPixelChannels(image)*(2*(image->columns+4)+2);
1943 GetPixelInfo(image,&pixel);
1944 for (x=0; x < (ssize_t) image->columns; x++)
1958 GetPixelInfo(image,&aggregate);
1960 GetPixelInfoPixel(image,p+center,&pixel);
1962 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1963 EnhancePixel(8.0); EnhancePixel(5.0);
1964 r=p+GetPixelChannels(image)*(image->columns+4);
1965 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1966 EnhancePixel(20.0); EnhancePixel(8.0);
1967 r=p+2*GetPixelChannels(image)*(image->columns+4);
1968 EnhancePixel(10.0); EnhancePixel(40.0); EnhancePixel(80.0);
1969 EnhancePixel(40.0); EnhancePixel(10.0);
1970 r=p+3*GetPixelChannels(image)*(image->columns+4);
1971 EnhancePixel(8.0); EnhancePixel(20.0); EnhancePixel(40.0);
1972 EnhancePixel(20.0); EnhancePixel(8.0);
1973 r=p+4*GetPixelChannels(image)*(image->columns+4);
1974 EnhancePixel(5.0); EnhancePixel(8.0); EnhancePixel(10.0);
1975 EnhancePixel(8.0); EnhancePixel(5.0);
1976 if (total_weight > MagickEpsilon)
1978 pixel.red=((aggregate.red+total_weight/2.0)/total_weight);
1979 pixel.green=((aggregate.green+total_weight/2.0)/total_weight);
1980 pixel.blue=((aggregate.blue+total_weight/2.0)/total_weight);
1981 pixel.black=((aggregate.black+total_weight/2.0)/total_weight);
1982 pixel.alpha=((aggregate.alpha+total_weight/2.0)/total_weight);
1984 SetPixelViaPixelInfo(enhance_image,&pixel,q);
1985 p+=GetPixelChannels(image);
1986 q+=GetPixelChannels(enhance_image);
1988 if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
1990 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1995 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1999 proceed=SetImageProgress(image,EnhanceImageTag,progress,image->rows);
2000 if (proceed == MagickFalse)
2004 enhance_view=DestroyCacheView(enhance_view);
2005 image_view=DestroyCacheView(image_view);
2006 if (status == MagickFalse)
2007 enhance_image=DestroyImage(enhance_image);
2008 return(enhance_image);
2035 MagickExport MagickBooleanType EqualizeImage(
Image *image,
2038 #define EqualizeImageTag "Equalize/Image"
2044 black[2*CompositePixelChannel+1],
2048 white[2*CompositePixelChannel+1];
2065 assert(image != (
Image *) NULL);
2066 assert(image->signature == MagickCoreSignature);
2067 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2068 if (AccelerateEqualizeImage(image,exception) != MagickFalse)
2071 if (IsEventLogging() != MagickFalse)
2072 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2073 equalize_map=(
double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
2074 sizeof(*equalize_map));
2075 histogram=(
double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
2076 sizeof(*histogram));
2077 map=(
double *) AcquireQuantumMemory(MaxMap+1UL,MaxPixelChannels*
sizeof(*map));
2078 if ((equalize_map == (
double *) NULL) || (histogram == (
double *) NULL) ||
2079 (map == (
double *) NULL))
2081 if (map != (
double *) NULL)
2082 map=(
double *) RelinquishMagickMemory(map);
2083 if (histogram != (
double *) NULL)
2084 histogram=(
double *) RelinquishMagickMemory(histogram);
2085 if (equalize_map != (
double *) NULL)
2086 equalize_map=(
double *) RelinquishMagickMemory(equalize_map);
2087 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2094 (void) memset(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
2095 sizeof(*histogram));
2096 image_view=AcquireVirtualCacheView(image,exception);
2097 for (y=0; y < (ssize_t) image->rows; y++)
2105 if (status == MagickFalse)
2107 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2108 if (p == (
const Quantum *) NULL)
2113 for (x=0; x < (ssize_t) image->columns; x++)
2115 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2120 intensity=(double) p[i];
2121 if ((image->channel_mask & SyncChannels) != 0)
2122 intensity=GetPixelIntensity(image,p);
2123 histogram[GetPixelChannels(image)*ScaleQuantumToMap(
2124 ClampToQuantum(intensity))+i]++;
2126 p+=GetPixelChannels(image);
2129 image_view=DestroyCacheView(image_view);
2133 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2142 for (j=0; j <= (ssize_t) MaxMap; j++)
2144 intensity+=histogram[GetPixelChannels(image)*j+i];
2145 map[GetPixelChannels(image)*j+i]=intensity;
2148 (void) memset(equalize_map,0,(MaxMap+1)*GetPixelChannels(image)*
2149 sizeof(*equalize_map));
2150 (void) memset(black,0,
sizeof(*black));
2151 (void) memset(white,0,
sizeof(*white));
2152 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2158 white[i]=map[GetPixelChannels(image)*MaxMap+i];
2159 if (black[i] != white[i])
2160 for (j=0; j <= (ssize_t) MaxMap; j++)
2161 equalize_map[GetPixelChannels(image)*j+i]=(double)
2162 ScaleMapToQuantum((
double) ((MaxMap*(map[
2163 GetPixelChannels(image)*j+i]-black[i]))/(white[i]-black[i])));
2165 histogram=(
double *) RelinquishMagickMemory(histogram);
2166 map=(
double *) RelinquishMagickMemory(map);
2167 if (image->storage_class == PseudoClass)
2175 for (j=0; j < (ssize_t) image->colors; j++)
2177 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2179 PixelChannel channel = GetPixelChannelChannel(image,
2181 if (black[channel] != white[channel])
2182 image->colormap[j].red=equalize_map[GetPixelChannels(image)*
2183 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].red))+
2186 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2188 PixelChannel channel = GetPixelChannelChannel(image,
2190 if (black[channel] != white[channel])
2191 image->colormap[j].green=equalize_map[GetPixelChannels(image)*
2192 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].green))+
2195 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2197 PixelChannel channel = GetPixelChannelChannel(image,
2199 if (black[channel] != white[channel])
2200 image->colormap[j].blue=equalize_map[GetPixelChannels(image)*
2201 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].blue))+
2204 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
2206 PixelChannel channel = GetPixelChannelChannel(image,
2208 if (black[channel] != white[channel])
2209 image->colormap[j].alpha=equalize_map[GetPixelChannels(image)*
2210 ScaleQuantumToMap(ClampToQuantum(image->colormap[j].alpha))+
2219 image_view=AcquireAuthenticCacheView(image,exception);
2220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2221 #pragma omp parallel for schedule(static) shared(progress,status) \
2222 magick_number_threads(image,image,image->rows,1)
2224 for (y=0; y < (ssize_t) image->rows; y++)
2232 if (status == MagickFalse)
2234 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2235 if (q == (Quantum *) NULL)
2240 for (x=0; x < (ssize_t) image->columns; x++)
2245 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
2247 PixelChannel channel = GetPixelChannelChannel(image,j);
2248 PixelTrait traits = GetPixelChannelTraits(image,channel);
2249 if (((traits & UpdatePixelTrait) == 0) || (black[j] == white[j]))
2251 q[j]=ClampToQuantum(equalize_map[GetPixelChannels(image)*
2252 ScaleQuantumToMap(q[j])+j]);
2254 q+=GetPixelChannels(image);
2256 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2258 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2263 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2267 proceed=SetImageProgress(image,EqualizeImageTag,progress,image->rows);
2268 if (proceed == MagickFalse)
2272 image_view=DestroyCacheView(image_view);
2273 equalize_map=(
double *) RelinquishMagickMemory(equalize_map);
2312 static inline double gamma_pow(
const double value,
const double gamma)
2314 return(value < 0.0 ? value : pow(value,gamma));
2317 MagickExport MagickBooleanType GammaImage(
Image *image,
const double gamma,
2320 #define GammaImageTag "Gamma/Image"
2343 assert(image != (
Image *) NULL);
2344 assert(image->signature == MagickCoreSignature);
2345 if (IsEventLogging() != MagickFalse)
2346 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2349 gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*gamma_map));
2350 if (gamma_map == (Quantum *) NULL)
2351 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
2353 (void) memset(gamma_map,0,(MaxMap+1)*
sizeof(*gamma_map));
2355 for (i=0; i <= (ssize_t) MaxMap; i++)
2356 gamma_map[i]=ScaleMapToQuantum((
double) (MaxMap*pow((
double) i/
2357 MaxMap,PerceptibleReciprocal(gamma))));
2358 if (image->storage_class == PseudoClass)
2359 for (i=0; i < (ssize_t) image->colors; i++)
2364 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2365 image->colormap[i].red=(double) gamma_map[ScaleQuantumToMap(
2366 ClampToQuantum(image->colormap[i].red))];
2367 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2368 image->colormap[i].green=(double) gamma_map[ScaleQuantumToMap(
2369 ClampToQuantum(image->colormap[i].green))];
2370 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2371 image->colormap[i].blue=(double) gamma_map[ScaleQuantumToMap(
2372 ClampToQuantum(image->colormap[i].blue))];
2373 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
2374 image->colormap[i].alpha=(double) gamma_map[ScaleQuantumToMap(
2375 ClampToQuantum(image->colormap[i].alpha))];
2382 image_view=AcquireAuthenticCacheView(image,exception);
2383 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2384 #pragma omp parallel for schedule(static) shared(progress,status) \
2385 magick_number_threads(image,image,image->rows,1)
2387 for (y=0; y < (ssize_t) image->rows; y++)
2395 if (status == MagickFalse)
2397 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2398 if (q == (Quantum *) NULL)
2403 for (x=0; x < (ssize_t) image->columns; x++)
2408 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
2410 PixelChannel channel = GetPixelChannelChannel(image,j);
2411 PixelTrait traits = GetPixelChannelTraits(image,channel);
2412 if ((traits & UpdatePixelTrait) == 0)
2414 q[j]=gamma_map[ScaleQuantumToMap(ClampToQuantum((MagickRealType)
2417 q+=GetPixelChannels(image);
2419 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2421 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2426 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2430 proceed=SetImageProgress(image,GammaImageTag,progress,image->rows);
2431 if (proceed == MagickFalse)
2435 image_view=DestroyCacheView(image_view);
2436 gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
2437 if (image->gamma != 0.0)
2438 image->gamma*=gamma;
2469 MagickExport MagickBooleanType GrayscaleImage(
Image *image,
2472 #define GrayscaleImageTag "Grayscale/Image"
2486 assert(image != (
Image *) NULL);
2487 assert(image->signature == MagickCoreSignature);
2488 if (IsEventLogging() != MagickFalse)
2489 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2490 if (image->storage_class == PseudoClass)
2492 if (SyncImage(image,exception) == MagickFalse)
2493 return(MagickFalse);
2494 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2495 return(MagickFalse);
2497 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2498 if (AccelerateGrayscaleImage(image,method,exception) != MagickFalse)
2500 image->intensity=method;
2501 image->type=GrayscaleType;
2502 if ((method == Rec601LuminancePixelIntensityMethod) ||
2503 (method == Rec709LuminancePixelIntensityMethod))
2504 return(SetImageColorspace(image,LinearGRAYColorspace,exception));
2505 return(SetImageColorspace(image,GRAYColorspace,exception));
2513 image_view=AcquireAuthenticCacheView(image,exception);
2514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2515 #pragma omp parallel for schedule(static) shared(progress,status) \
2516 magick_number_threads(image,image,image->rows,1)
2518 for (y=0; y < (ssize_t) image->rows; y++)
2526 if (status == MagickFalse)
2528 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2529 if (q == (Quantum *) NULL)
2534 for (x=0; x < (ssize_t) image->columns; x++)
2542 red=(MagickRealType) GetPixelRed(image,q);
2543 green=(MagickRealType) GetPixelGreen(image,q);
2544 blue=(MagickRealType) GetPixelBlue(image,q);
2548 case AveragePixelIntensityMethod:
2550 intensity=(red+green+blue)/3.0;
2553 case BrightnessPixelIntensityMethod:
2555 intensity=MagickMax(MagickMax(red,green),blue);
2558 case LightnessPixelIntensityMethod:
2560 intensity=(MagickMin(MagickMin(red,green),blue)+
2561 MagickMax(MagickMax(red,green),blue))/2.0;
2564 case MSPixelIntensityMethod:
2566 intensity=(MagickRealType) (((
double) red*red+green*green+
2570 case Rec601LumaPixelIntensityMethod:
2572 if (image->colorspace == RGBColorspace)
2574 red=EncodePixelGamma(red);
2575 green=EncodePixelGamma(green);
2576 blue=EncodePixelGamma(blue);
2578 intensity=0.298839*red+0.586811*green+0.114350*blue;
2581 case Rec601LuminancePixelIntensityMethod:
2583 if (image->colorspace == sRGBColorspace)
2585 red=DecodePixelGamma(red);
2586 green=DecodePixelGamma(green);
2587 blue=DecodePixelGamma(blue);
2589 intensity=0.298839*red+0.586811*green+0.114350*blue;
2592 case Rec709LumaPixelIntensityMethod:
2595 if (image->colorspace == RGBColorspace)
2597 red=EncodePixelGamma(red);
2598 green=EncodePixelGamma(green);
2599 blue=EncodePixelGamma(blue);
2601 intensity=0.212656*red+0.715158*green+0.072186*blue;
2604 case Rec709LuminancePixelIntensityMethod:
2606 if (image->colorspace == sRGBColorspace)
2608 red=DecodePixelGamma(red);
2609 green=DecodePixelGamma(green);
2610 blue=DecodePixelGamma(blue);
2612 intensity=0.212656*red+0.715158*green+0.072186*blue;
2615 case RMSPixelIntensityMethod:
2617 intensity=(MagickRealType) (sqrt((
double) red*red+green*green+
2618 blue*blue)/sqrt(3.0));
2622 SetPixelGray(image,ClampToQuantum(intensity),q);
2623 q+=GetPixelChannels(image);
2625 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2627 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2632 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2636 proceed=SetImageProgress(image,GrayscaleImageTag,progress,image->rows);
2637 if (proceed == MagickFalse)
2641 image_view=DestroyCacheView(image_view);
2642 image->intensity=method;
2643 image->type=GrayscaleType;
2644 if ((method == Rec601LuminancePixelIntensityMethod) ||
2645 (method == Rec709LuminancePixelIntensityMethod))
2646 return(SetImageColorspace(image,LinearGRAYColorspace,exception));
2647 return(SetImageColorspace(image,GRAYColorspace,exception));
2681 MagickExport MagickBooleanType HaldClutImage(
Image *image,
2684 #define HaldClutImageTag "Clut/Image"
2686 typedef struct _HaldInfo
2718 assert(image != (
Image *) NULL);
2719 assert(image->signature == MagickCoreSignature);
2720 if (IsEventLogging() != MagickFalse)
2721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2722 assert(hald_image != (
Image *) NULL);
2723 assert(hald_image->signature == MagickCoreSignature);
2724 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2725 return(MagickFalse);
2726 if (image->alpha_trait == UndefinedPixelTrait)
2727 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
2733 length=(size_t) MagickMin((MagickRealType) hald_image->columns,
2734 (MagickRealType) hald_image->rows);
2735 for (level=2; (level*level*level) < length; level++) ;
2737 cube_size=level*level;
2738 width=(double) hald_image->columns;
2739 GetPixelInfo(hald_image,&zero);
2740 hald_view=AcquireVirtualCacheView(hald_image,exception);
2741 image_view=AcquireAuthenticCacheView(image,exception);
2742 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2743 #pragma omp parallel for schedule(static) shared(progress,status) \
2744 magick_number_threads(image,image,image->rows,1)
2746 for (y=0; y < (ssize_t) image->rows; y++)
2754 if (status == MagickFalse)
2756 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2757 if (q == (Quantum *) NULL)
2762 for (x=0; x < (ssize_t) image->columns; x++)
2778 point.x=QuantumScale*(level-1.0)*GetPixelRed(image,q);
2779 point.y=QuantumScale*(level-1.0)*GetPixelGreen(image,q);
2780 point.z=QuantumScale*(level-1.0)*GetPixelBlue(image,q);
2781 offset=point.x+level*floor(point.y)+cube_size*floor(point.z);
2782 point.x-=floor(point.x);
2783 point.y-=floor(point.y);
2784 point.z-=floor(point.z);
2786 status=InterpolatePixelInfo(hald_image,hald_view,hald_image->interpolate,
2787 fmod(offset,width),floor(offset/width),&pixel1,exception);
2788 if (status == MagickFalse)
2791 status=InterpolatePixelInfo(hald_image,hald_view,hald_image->interpolate,
2792 fmod(offset+level,width),floor((offset+level)/width),&pixel2,exception);
2793 if (status == MagickFalse)
2797 if (hald_image->interpolate == NearestInterpolatePixel)
2798 area=(point.y < 0.5) ? 0.0 : 1.0;
2799 CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,pixel2.alpha,
2802 status=InterpolatePixelInfo(hald_image,hald_view,hald_image->interpolate,
2803 fmod(offset,width),floor(offset/width),&pixel1,exception);
2804 if (status == MagickFalse)
2806 status=InterpolatePixelInfo(hald_image,hald_view,hald_image->interpolate,
2807 fmod(offset+level,width),floor((offset+level)/width),&pixel2,exception);
2808 if (status == MagickFalse)
2811 CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,pixel2.alpha,
2815 if (hald_image->interpolate == NearestInterpolatePixel)
2816 area=(point.z < 0.5)? 0.0 : 1.0;
2817 CompositePixelInfoAreaBlend(&pixel3,pixel3.alpha,&pixel4,pixel4.alpha,
2819 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2820 SetPixelRed(image,ClampToQuantum(pixel.red),q);
2821 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2822 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
2823 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2824 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
2825 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
2826 (image->colorspace == CMYKColorspace))
2827 SetPixelBlack(image,ClampToQuantum(pixel.black),q);
2828 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
2829 (image->alpha_trait != UndefinedPixelTrait))
2830 SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
2831 q+=GetPixelChannels(image);
2833 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2835 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2840 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2844 proceed=SetImageProgress(image,HaldClutImageTag,progress,image->rows);
2845 if (proceed == MagickFalse)
2849 hald_view=DestroyCacheView(hald_view);
2850 image_view=DestroyCacheView(image_view);
2898 static inline double LevelPixel(
const double black_point,
2899 const double white_point,
const double gamma,
const double pixel)
2905 scale=PerceptibleReciprocal(white_point-black_point);
2906 level_pixel=QuantumRange*gamma_pow(scale*((
double) pixel-black_point),
2907 PerceptibleReciprocal(gamma));
2908 return(level_pixel);
2911 MagickExport MagickBooleanType LevelImage(
Image *image,
const double black_point,
2912 const double white_point,
const double gamma,
ExceptionInfo *exception)
2914 #define LevelImageTag "Level/Image"
2934 assert(image != (
Image *) NULL);
2935 assert(image->signature == MagickCoreSignature);
2936 if (IsEventLogging() != MagickFalse)
2937 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2938 if (image->storage_class == PseudoClass)
2939 for (i=0; i < (ssize_t) image->colors; i++)
2944 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
2945 image->colormap[i].red=(double) ClampToQuantum(LevelPixel(black_point,
2946 white_point,gamma,image->colormap[i].red));
2947 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
2948 image->colormap[i].green=(double) ClampToQuantum(LevelPixel(black_point,
2949 white_point,gamma,image->colormap[i].green));
2950 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
2951 image->colormap[i].blue=(double) ClampToQuantum(LevelPixel(black_point,
2952 white_point,gamma,image->colormap[i].blue));
2953 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
2954 image->colormap[i].alpha=(double) ClampToQuantum(LevelPixel(black_point,
2955 white_point,gamma,image->colormap[i].alpha));
2962 image_view=AcquireAuthenticCacheView(image,exception);
2963 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2964 #pragma omp parallel for schedule(static) shared(progress,status) \
2965 magick_number_threads(image,image,image->rows,1)
2967 for (y=0; y < (ssize_t) image->rows; y++)
2975 if (status == MagickFalse)
2977 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2978 if (q == (Quantum *) NULL)
2983 for (x=0; x < (ssize_t) image->columns; x++)
2988 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
2990 PixelChannel channel = GetPixelChannelChannel(image,j);
2991 PixelTrait traits = GetPixelChannelTraits(image,channel);
2992 if ((traits & UpdatePixelTrait) == 0)
2994 q[j]=ClampToQuantum(LevelPixel(black_point,white_point,gamma,
2997 q+=GetPixelChannels(image);
2999 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3001 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3006 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3010 proceed=SetImageProgress(image,LevelImageTag,progress,image->rows);
3011 if (proceed == MagickFalse)
3015 image_view=DestroyCacheView(image_view);
3016 (void) ClampImage(image,exception);
3062 MagickExport MagickBooleanType LevelizeImage(
Image *image,
3063 const double black_point,
const double white_point,
const double gamma,
3066 #define LevelizeImageTag "Levelize/Image"
3067 #define LevelizeValue(x) ClampToQuantum(((MagickRealType) gamma_pow((double) \
3068 (QuantumScale*(x)),gamma))*(white_point-black_point)+black_point)
3088 assert(image != (
Image *) NULL);
3089 assert(image->signature == MagickCoreSignature);
3090 if (IsEventLogging() != MagickFalse)
3091 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3092 if (image->storage_class == PseudoClass)
3093 for (i=0; i < (ssize_t) image->colors; i++)
3098 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
3099 image->colormap[i].red=(double) LevelizeValue(image->colormap[i].red);
3100 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
3101 image->colormap[i].green=(double) LevelizeValue(
3102 image->colormap[i].green);
3103 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
3104 image->colormap[i].blue=(double) LevelizeValue(image->colormap[i].blue);
3105 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
3106 image->colormap[i].alpha=(double) LevelizeValue(
3107 image->colormap[i].alpha);
3114 image_view=AcquireAuthenticCacheView(image,exception);
3115 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3116 #pragma omp parallel for schedule(static) shared(progress,status) \
3117 magick_number_threads(image,image,image->rows,1)
3119 for (y=0; y < (ssize_t) image->rows; y++)
3127 if (status == MagickFalse)
3129 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3130 if (q == (Quantum *) NULL)
3135 for (x=0; x < (ssize_t) image->columns; x++)
3140 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
3142 PixelChannel channel = GetPixelChannelChannel(image,j);
3143 PixelTrait traits = GetPixelChannelTraits(image,channel);
3144 if ((traits & UpdatePixelTrait) == 0)
3146 q[j]=LevelizeValue(q[j]);
3148 q+=GetPixelChannels(image);
3150 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3152 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3157 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3161 proceed=SetImageProgress(image,LevelizeImageTag,progress,image->rows);
3162 if (proceed == MagickFalse)
3166 image_view=DestroyCacheView(image_view);
3211 MagickExport MagickBooleanType LevelImageColors(
Image *image,
3224 assert(image != (
Image *) NULL);
3225 assert(image->signature == MagickCoreSignature);
3226 if (IsEventLogging() != MagickFalse)
3227 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3228 if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3229 ((IsGrayColorspace(black_color->colorspace) == MagickFalse) ||
3230 (IsGrayColorspace(white_color->colorspace) == MagickFalse)))
3231 (
void) SetImageColorspace(image,sRGBColorspace,exception);
3233 if (invert == MagickFalse)
3235 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
3237 channel_mask=SetImageChannelMask(image,RedChannel);
3238 status&=LevelImage(image,black_color->red,white_color->red,1.0,
3240 (void) SetImageChannelMask(image,channel_mask);
3242 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
3244 channel_mask=SetImageChannelMask(image,GreenChannel);
3245 status&=LevelImage(image,black_color->green,white_color->green,1.0,
3247 (void) SetImageChannelMask(image,channel_mask);
3249 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
3251 channel_mask=SetImageChannelMask(image,BlueChannel);
3252 status&=LevelImage(image,black_color->blue,white_color->blue,1.0,
3254 (void) SetImageChannelMask(image,channel_mask);
3256 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
3257 (image->colorspace == CMYKColorspace))
3259 channel_mask=SetImageChannelMask(image,BlackChannel);
3260 status&=LevelImage(image,black_color->black,white_color->black,1.0,
3262 (void) SetImageChannelMask(image,channel_mask);
3264 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
3265 (image->alpha_trait != UndefinedPixelTrait))
3267 channel_mask=SetImageChannelMask(image,AlphaChannel);
3268 status&=LevelImage(image,black_color->alpha,white_color->alpha,1.0,
3270 (void) SetImageChannelMask(image,channel_mask);
3275 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
3277 channel_mask=SetImageChannelMask(image,RedChannel);
3278 status&=LevelizeImage(image,black_color->red,white_color->red,1.0,
3280 (void) SetImageChannelMask(image,channel_mask);
3282 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
3284 channel_mask=SetImageChannelMask(image,GreenChannel);
3285 status&=LevelizeImage(image,black_color->green,white_color->green,1.0,
3287 (void) SetImageChannelMask(image,channel_mask);
3289 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
3291 channel_mask=SetImageChannelMask(image,BlueChannel);
3292 status&=LevelizeImage(image,black_color->blue,white_color->blue,1.0,
3294 (void) SetImageChannelMask(image,channel_mask);
3296 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
3297 (image->colorspace == CMYKColorspace))
3299 channel_mask=SetImageChannelMask(image,BlackChannel);
3300 status&=LevelizeImage(image,black_color->black,white_color->black,1.0,
3302 (void) SetImageChannelMask(image,channel_mask);
3304 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
3305 (image->alpha_trait != UndefinedPixelTrait))
3307 channel_mask=SetImageChannelMask(image,AlphaChannel);
3308 status&=LevelizeImage(image,black_color->alpha,white_color->alpha,1.0,
3310 (void) SetImageChannelMask(image,channel_mask);
3313 return(status != 0 ? MagickTrue : MagickFalse);
3347 MagickExport MagickBooleanType LinearStretchImage(
Image *image,
3348 const double black_point,
const double white_point,
ExceptionInfo *exception)
3350 #define LinearStretchImageTag "LinearStretch/Image"
3370 assert(image != (
Image *) NULL);
3371 assert(image->signature == MagickCoreSignature);
3372 histogram=(
double *) AcquireQuantumMemory(MaxMap+1UL,
sizeof(*histogram));
3373 if (histogram == (
double *) NULL)
3374 ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
3379 (void) memset(histogram,0,(MaxMap+1)*
sizeof(*histogram));
3380 image_view=AcquireVirtualCacheView(image,exception);
3381 for (y=0; y < (ssize_t) image->rows; y++)
3389 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3390 if (p == (
const Quantum *) NULL)
3392 for (x=0; x < (ssize_t) image->columns; x++)
3394 intensity=GetPixelIntensity(image,p);
3395 histogram[ScaleQuantumToMap(ClampToQuantum(intensity))]++;
3396 p+=GetPixelChannels(image);
3399 image_view=DestroyCacheView(image_view);
3404 for (black=0; black < (ssize_t) MaxMap; black++)
3406 intensity+=histogram[black];
3407 if (intensity >= black_point)
3411 for (white=(ssize_t) MaxMap; white != 0; white--)
3413 intensity+=histogram[white];
3414 if (intensity >= white_point)
3417 histogram=(
double *) RelinquishMagickMemory(histogram);
3418 status=LevelImage(image,(
double) ScaleMapToQuantum((MagickRealType) black),
3419 (
double) ScaleMapToQuantum((MagickRealType) white),1.0,exception);
3456 static inline void ModulateHCL(
const double percent_hue,
3457 const double percent_chroma,
const double percent_luma,
double *red,
3458 double *green,
double *blue)
3468 ConvertRGBToHCL(*red,*green,*blue,&hue,&chroma,&luma);
3469 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3470 chroma*=0.01*percent_chroma;
3471 luma*=0.01*percent_luma;
3472 ConvertHCLToRGB(hue,chroma,luma,red,green,blue);
3475 static inline void ModulateHCLp(
const double percent_hue,
3476 const double percent_chroma,
const double percent_luma,
double *red,
3477 double *green,
double *blue)
3487 ConvertRGBToHCLp(*red,*green,*blue,&hue,&chroma,&luma);
3488 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3489 chroma*=0.01*percent_chroma;
3490 luma*=0.01*percent_luma;
3491 ConvertHCLpToRGB(hue,chroma,luma,red,green,blue);
3494 static inline void ModulateHSB(
const double percent_hue,
3495 const double percent_saturation,
const double percent_brightness,
double *red,
3496 double *green,
double *blue)
3506 ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
3507 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3508 saturation*=0.01*percent_saturation;
3509 brightness*=0.01*percent_brightness;
3510 ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
3513 static inline void ModulateHSI(
const double percent_hue,
3514 const double percent_saturation,
const double percent_intensity,
double *red,
3515 double *green,
double *blue)
3525 ConvertRGBToHSI(*red,*green,*blue,&hue,&saturation,&intensity);
3526 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3527 saturation*=0.01*percent_saturation;
3528 intensity*=0.01*percent_intensity;
3529 ConvertHSIToRGB(hue,saturation,intensity,red,green,blue);
3532 static inline void ModulateHSL(
const double percent_hue,
3533 const double percent_saturation,
const double percent_lightness,
double *red,
3534 double *green,
double *blue)
3544 ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
3545 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3546 saturation*=0.01*percent_saturation;
3547 lightness*=0.01*percent_lightness;
3548 ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
3551 static inline void ModulateHSV(
const double percent_hue,
3552 const double percent_saturation,
const double percent_value,
double *red,
3553 double *green,
double *blue)
3563 ConvertRGBToHSV(*red,*green,*blue,&hue,&saturation,&value);
3564 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3565 saturation*=0.01*percent_saturation;
3566 value*=0.01*percent_value;
3567 ConvertHSVToRGB(hue,saturation,value,red,green,blue);
3570 static inline void ModulateHWB(
const double percent_hue,
3571 const double percent_whiteness,
const double percent_blackness,
double *red,
3572 double *green,
double *blue)
3582 ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
3583 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3584 blackness*=0.01*percent_blackness;
3585 whiteness*=0.01*percent_whiteness;
3586 ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
3589 static inline void ModulateLCHab(
const double percent_luma,
3590 const double percent_chroma,
const double percent_hue,
3591 const IlluminantType illuminant,
double *red,
double *green,
double *blue)
3601 ConvertRGBToLCHab(*red,*green,*blue,illuminant,&luma,&chroma,&hue);
3602 luma*=0.01*percent_luma;
3603 chroma*=0.01*percent_chroma;
3604 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3605 ConvertLCHabToRGB(luma,chroma,hue,illuminant,red,green,blue);
3608 static inline void ModulateLCHuv(
const double percent_luma,
3609 const double percent_chroma,
const double percent_hue,
3610 const IlluminantType illuminant,
double *red,
double *green,
double *blue)
3620 ConvertRGBToLCHuv(*red,*green,*blue,illuminant,&luma,&chroma,&hue);
3621 luma*=0.01*percent_luma;
3622 chroma*=0.01*percent_chroma;
3623 hue+=fmod((percent_hue-100.0),200.0)/200.0;
3624 ConvertLCHuvToRGB(luma,chroma,hue,illuminant,red,green,blue);
3627 MagickExport MagickBooleanType ModulateImage(
Image *image,
const char *modulate,
3630 #define ModulateImageTag "Modulate/Image"
3636 colorspace = UndefinedColorspace;
3642 percent_brightness = 100.0,
3643 percent_hue = 100.0,
3644 percent_saturation = 100.0;
3650 illuminant = D65Illuminant;
3670 assert(image != (
Image *) NULL);
3671 assert(image->signature == MagickCoreSignature);
3672 if (IsEventLogging() != MagickFalse)
3673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3674 if (modulate == (
char *) NULL)
3675 return(MagickFalse);
3676 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3677 (
void) SetImageColorspace(image,sRGBColorspace,exception);
3678 flags=ParseGeometry(modulate,&geometry_info);
3679 if ((flags & RhoValue) != 0)
3680 percent_brightness=geometry_info.rho;
3681 if ((flags & SigmaValue) != 0)
3682 percent_saturation=geometry_info.sigma;
3683 if ((flags & XiValue) != 0)
3684 percent_hue=geometry_info.xi;
3685 artifact=GetImageArtifact(image,
"modulate:colorspace");
3686 if (artifact != (
const char *) NULL)
3687 colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
3688 MagickFalse,artifact);
3689 artifact=GetImageArtifact(image,
"color:illuminant");
3690 if (artifact != (
const char *) NULL)
3692 illuminant=(IlluminantType) ParseCommandOption(MagickIlluminantOptions,
3693 MagickFalse,artifact);
3694 if ((ssize_t) illuminant < 0)
3696 illuminant=UndefinedIlluminant;
3697 colorspace=UndefinedColorspace;
3700 if (image->storage_class == PseudoClass)
3701 for (i=0; i < (ssize_t) image->colors; i++)
3711 red=(double) image->colormap[i].red;
3712 green=(
double) image->colormap[i].green;
3713 blue=(double) image->colormap[i].blue;
3718 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3722 case HCLpColorspace:
3724 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3730 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3736 ModulateHSI(percent_hue,percent_saturation,percent_brightness,
3743 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3749 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3755 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3760 case LCHabColorspace:
3762 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3763 illuminant,&red,&green,&blue);
3766 case LCHuvColorspace:
3768 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3769 illuminant,&red,&green,&blue);
3773 image->colormap[i].red=red;
3774 image->colormap[i].green=green;
3775 image->colormap[i].blue=blue;
3780 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3781 if (AccelerateModulateImage(image,percent_brightness,percent_hue,
3782 percent_saturation,colorspace,exception) != MagickFalse)
3787 image_view=AcquireAuthenticCacheView(image,exception);
3788 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3789 #pragma omp parallel for schedule(static) shared(progress,status) \
3790 magick_number_threads(image,image,image->rows,1)
3792 for (y=0; y < (ssize_t) image->rows; y++)
3800 if (status == MagickFalse)
3802 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3803 if (q == (Quantum *) NULL)
3808 for (x=0; x < (ssize_t) image->columns; x++)
3815 red=(double) GetPixelRed(image,q);
3816 green=(double) GetPixelGreen(image,q);
3817 blue=(double) GetPixelBlue(image,q);
3822 ModulateHCL(percent_hue,percent_saturation,percent_brightness,
3826 case HCLpColorspace:
3828 ModulateHCLp(percent_hue,percent_saturation,percent_brightness,
3834 ModulateHSB(percent_hue,percent_saturation,percent_brightness,
3841 ModulateHSL(percent_hue,percent_saturation,percent_brightness,
3847 ModulateHSV(percent_hue,percent_saturation,percent_brightness,
3853 ModulateHWB(percent_hue,percent_saturation,percent_brightness,
3857 case LCHabColorspace:
3859 ModulateLCHab(percent_brightness,percent_saturation,percent_hue,
3860 illuminant,&red,&green,&blue);
3864 case LCHuvColorspace:
3866 ModulateLCHuv(percent_brightness,percent_saturation,percent_hue,
3867 illuminant,&red,&green,&blue);
3871 SetPixelRed(image,ClampToQuantum(red),q);
3872 SetPixelGreen(image,ClampToQuantum(green),q);
3873 SetPixelBlue(image,ClampToQuantum(blue),q);
3874 q+=GetPixelChannels(image);
3876 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3878 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3883 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3887 proceed=SetImageProgress(image,ModulateImageTag,progress,image->rows);
3888 if (proceed == MagickFalse)
3892 image_view=DestroyCacheView(image_view);
3924 MagickExport MagickBooleanType NegateImage(
Image *image,
3927 #define NegateImageTag "Negate/Image"
3944 assert(image != (
Image *) NULL);
3945 assert(image->signature == MagickCoreSignature);
3946 if (IsEventLogging() != MagickFalse)
3947 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3948 if (image->storage_class == PseudoClass)
3949 for (i=0; i < (ssize_t) image->colors; i++)
3954 if (grayscale != MagickFalse)
3955 if ((image->colormap[i].red != image->colormap[i].green) ||
3956 (image->colormap[i].green != image->colormap[i].blue))
3958 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
3959 image->colormap[i].red=QuantumRange-image->colormap[i].red;
3960 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
3961 image->colormap[i].green=QuantumRange-image->colormap[i].green;
3962 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
3963 image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
3970 image_view=AcquireAuthenticCacheView(image,exception);
3971 if( grayscale != MagickFalse )
3973 for (y=0; y < (ssize_t) image->rows; y++)
3984 if (status == MagickFalse)
3986 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
3988 if (q == (Quantum *) NULL)
3993 for (x=0; x < (ssize_t) image->columns; x++)
3998 if (IsPixelGray(image,q) == MagickFalse)
4000 q+=GetPixelChannels(image);
4003 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
4005 PixelChannel channel = GetPixelChannelChannel(image,j);
4006 PixelTrait traits = GetPixelChannelTraits(image,channel);
4007 if ((traits & UpdatePixelTrait) == 0)
4009 q[j]=QuantumRange-q[j];
4011 q+=GetPixelChannels(image);
4013 sync=SyncCacheViewAuthenticPixels(image_view,exception);
4014 if (sync == MagickFalse)
4016 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4022 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4023 if (proceed == MagickFalse)
4027 image_view=DestroyCacheView(image_view);
4033 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4034 #pragma omp parallel for schedule(static) shared(progress,status) \
4035 magick_number_threads(image,image,image->rows,1)
4037 for (y=0; y < (ssize_t) image->rows; y++)
4045 if (status == MagickFalse)
4047 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4048 if (q == (Quantum *) NULL)
4053 for (x=0; x < (ssize_t) image->columns; x++)
4058 for (j=0; j < (ssize_t) GetPixelChannels(image); j++)
4060 PixelChannel channel = GetPixelChannelChannel(image,j);
4061 PixelTrait traits = GetPixelChannelTraits(image,channel);
4062 if ((traits & UpdatePixelTrait) == 0)
4064 q[j]=QuantumRange-q[j];
4066 q+=GetPixelChannels(image);
4068 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4070 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4075 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4079 proceed=SetImageProgress(image,NegateImageTag,progress,image->rows);
4080 if (proceed == MagickFalse)
4084 image_view=DestroyCacheView(image_view);
4114 MagickExport MagickBooleanType NormalizeImage(
Image *image,
4121 black_point=(double) image->columns*image->rows*0.0015;
4122 white_point=(
double) image->columns*image->rows*0.9995;
4123 return(ContrastStretchImage(image,black_point,white_point,exception));
4190 #if defined(MAGICKCORE_HAVE_ATANH)
4191 #define Sigmoidal(a,b,x) ( tanh((0.5*(a))*((x)-(b))) )
4193 #define Sigmoidal(a,b,x) ( 1.0/(1.0+exp((a)*((b)-(x)))) )
4212 #define ScaledSigmoidal(a,b,x) ( \
4213 (Sigmoidal((a),(b),(x))-Sigmoidal((a),(b),0.0)) / \
4214 (Sigmoidal((a),(b),1.0)-Sigmoidal((a),(b),0.0)) )
4224 static inline double InverseScaledSigmoidal(
const double a,
const double b,
4227 const double sig0=Sigmoidal(a,b,0.0);
4228 const double sig1=Sigmoidal(a,b,1.0);
4229 const double argument=(sig1-sig0)*x+sig0;
4230 const double clamped=
4232 #if defined(MAGICKCORE_HAVE_ATANH)
4233 argument < -1+MagickEpsilon
4237 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4239 return(b+(2.0/a)*atanh(clamped));
4241 argument < MagickEpsilon
4245 ( argument > 1-MagickEpsilon ? 1-MagickEpsilon : argument )
4247 return(b-log(1.0/clamped-1.0)/a);
4251 MagickExport MagickBooleanType SigmoidalContrastImage(
Image *image,
4252 const MagickBooleanType sharpen,
const double contrast,
const double midpoint,
4255 #define SigmoidalContrastImageTag "SigmoidalContrast/Image"
4256 #define ScaledSig(x) ( ClampToQuantum(QuantumRange* \
4257 ScaledSigmoidal(contrast,QuantumScale*midpoint,QuantumScale*(x))) )
4258 #define InverseScaledSig(x) ( ClampToQuantum(QuantumRange* \
4259 InverseScaledSigmoidal(contrast,QuantumScale*midpoint,QuantumScale*(x))) )
4276 assert(image != (
Image *) NULL);
4277 assert(image->signature == MagickCoreSignature);
4278 if (IsEventLogging() != MagickFalse)
4279 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4284 if (contrast < MagickEpsilon)
4289 if (image->storage_class == PseudoClass)
4294 if( sharpen != MagickFalse )
4295 for (i=0; i < (ssize_t) image->colors; i++)
4297 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
4298 image->colormap[i].red=(MagickRealType) ScaledSig(
4299 image->colormap[i].red);
4300 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
4301 image->colormap[i].green=(MagickRealType) ScaledSig(
4302 image->colormap[i].green);
4303 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
4304 image->colormap[i].blue=(MagickRealType) ScaledSig(
4305 image->colormap[i].blue);
4306 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
4307 image->colormap[i].alpha=(MagickRealType) ScaledSig(
4308 image->colormap[i].alpha);
4311 for (i=0; i < (ssize_t) image->colors; i++)
4313 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
4314 image->colormap[i].red=(MagickRealType) InverseScaledSig(
4315 image->colormap[i].red);
4316 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
4317 image->colormap[i].green=(MagickRealType) InverseScaledSig(
4318 image->colormap[i].green);
4319 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
4320 image->colormap[i].blue=(MagickRealType) InverseScaledSig(
4321 image->colormap[i].blue);
4322 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
4323 image->colormap[i].alpha=(MagickRealType) InverseScaledSig(
4324 image->colormap[i].alpha);
4332 image_view=AcquireAuthenticCacheView(image,exception);
4333 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4334 #pragma omp parallel for schedule(static) shared(progress,status) \
4335 magick_number_threads(image,image,image->rows,1)
4337 for (y=0; y < (ssize_t) image->rows; y++)
4345 if (status == MagickFalse)
4347 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4348 if (q == (Quantum *) NULL)
4353 for (x=0; x < (ssize_t) image->columns; x++)
4358 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4360 PixelChannel channel = GetPixelChannelChannel(image,i);
4361 PixelTrait traits = GetPixelChannelTraits(image,channel);
4362 if ((traits & UpdatePixelTrait) == 0)
4364 if( sharpen != MagickFalse )
4365 q[i]=ScaledSig(q[i]);
4367 q[i]=InverseScaledSig(q[i]);
4369 q+=GetPixelChannels(image);
4371 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4373 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4378 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4382 proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress,
4384 if (proceed == MagickFalse)
4388 image_view=DestroyCacheView(image_view);
4418 MagickExport MagickBooleanType WhiteBalanceImage(
Image *image,
4421 #define WhiteBalanceImageTag "WhiteBalance/Image"
4445 assert(image != (
Image *) NULL);
4446 assert(image->signature == MagickCoreSignature);
4447 if (IsEventLogging() != MagickFalse)
4448 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4449 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4450 return(MagickFalse);
4451 status=TransformImageColorspace(image,LabColorspace,exception);
4454 image_view=AcquireAuthenticCacheView(image,exception);
4455 for (y=0; y < (ssize_t) image->rows; y++)
4463 if (status == MagickFalse)
4465 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4466 if (p == (Quantum *) NULL)
4471 for (x=0; x < (ssize_t) image->columns; x++)
4473 a_mean+=QuantumScale*GetPixela(image,p)-0.5;
4474 b_mean+=QuantumScale*GetPixelb(image,p)-0.5;
4475 p+=GetPixelChannels(image);
4478 a_mean/=((double) image->columns*image->rows);
4479 b_mean/=((double) image->columns*image->rows);
4481 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4482 #pragma omp parallel for schedule(static) shared(progress,status) \
4483 magick_number_threads(image,image,image->rows,1)
4485 for (y=0; y < (ssize_t) image->rows; y++)
4493 if (status == MagickFalse)
4495 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4496 if (q == (Quantum *) NULL)
4501 for (x=0; x < (ssize_t) image->columns; x++)
4510 a=(double) GetPixela(image,q)-1.1*GetPixelL(image,q)*a_mean;
4511 b=(double) GetPixelb(image,q)-1.1*GetPixelL(image,q)*b_mean;
4512 SetPixela(image,ClampToQuantum(a),q);
4513 SetPixelb(image,ClampToQuantum(b),q);
4514 q+=GetPixelChannels(image);
4516 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4518 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4523 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4527 proceed=SetImageProgress(image,WhiteBalanceImageTag,progress,image->rows);
4528 if (proceed == MagickFalse)
4532 image_view=DestroyCacheView(image_view);
4533 artifact=GetImageArtifact(image,
"white-balance:vibrance");
4534 if (artifact != (
const char *) NULL)
4551 flags=ParseGeometry(artifact,&geometry_info);
4552 if ((flags & RhoValue) != 0)
4553 black_point=geometry_info.rho;
4554 if ((flags & PercentValue) != 0)
4555 black_point*=(double) (QuantumRange/100.0);
4556 channel_mask=SetImageChannelMask(image,(ChannelType) (aChannel |
4558 status&=LevelImage(image,black_point,(
double) QuantumRange-black_point,
4560 (void) SetImageChannelMask(image,channel_mask);
4562 status&=TransformImageColorspace(image,sRGBColorspace,exception);
4563 return(status != 0 ? MagickTrue : MagickFalse);