mirror of
https://github.com/ImageMagick/ImageMagick.git
synced 2026-05-25 11:24:54 +02:00
validate the level argument of the -posterize option (https://github.com/ImageMagick/ImageMagick/issues/7181)
This commit is contained in:
+177
-153
@@ -2881,178 +2881,202 @@ MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
|
||||
assert(exception->signature == MagickCoreSignature);
|
||||
if (IsEventLogging() != MagickFalse)
|
||||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
||||
|
||||
if (dither_method != NoDitherMethod && levels > 1) {
|
||||
Image
|
||||
*map_image;
|
||||
|
||||
ssize_t
|
||||
i;
|
||||
|
||||
size_t
|
||||
channels = 0,
|
||||
numPoolCols;
|
||||
|
||||
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
|
||||
if ((dither_method != NoDitherMethod) && (levels > 1) && (levels < 20))
|
||||
for (y=0; y < 1; y++)
|
||||
{
|
||||
PixelChannel channel = GetPixelChannelChannel(image,i);
|
||||
PixelTrait traits = GetPixelChannelTraits(image,channel);
|
||||
if ((traits & UpdatePixelTrait) != 0)
|
||||
channels++;
|
||||
}
|
||||
numPoolCols = pow (levels, channels);
|
||||
Image
|
||||
*map_image;
|
||||
|
||||
map_image = CloneImage(image, numPoolCols, 1, MagickTrue, exception);
|
||||
if (map_image == (Image *) NULL)
|
||||
return MagickFalse;
|
||||
|
||||
if (SetImageStorageClass (map_image, DirectClass, exception) == MagickFalse)
|
||||
return MagickFalse;
|
||||
|
||||
{ /* Populate the map image */
|
||||
CacheView
|
||||
*map_image_view;
|
||||
|
||||
Quantum
|
||||
*magick_restrict q;
|
||||
|
||||
MagickRealType
|
||||
valmult = QuantumRange / (levels - 1.0);
|
||||
|
||||
ssize_t
|
||||
x, c;
|
||||
|
||||
map_image_view=AcquireAuthenticCacheView (map_image,exception);
|
||||
|
||||
q = GetCacheViewAuthenticPixels (map_image_view,0,0,numPoolCols,1,
|
||||
exception);
|
||||
if (q == (const Quantum *) NULL)
|
||||
return MagickFalse;
|
||||
|
||||
for (x=0; x < (ssize_t) numPoolCols; x++) {
|
||||
size_t rem = x;
|
||||
for (c=0; c < (ssize_t) GetPixelChannels(image); c++) {
|
||||
PixelChannel channel = GetPixelChannelChannel (image, c);
|
||||
PixelTrait traits = GetPixelChannelTraits (image, channel);
|
||||
if ((traits & UpdatePixelTrait) != 0) {
|
||||
size_t val = rem % levels;
|
||||
SetPixelChannel (map_image, channel, val * valmult, q);
|
||||
rem = (rem - val) / levels;
|
||||
}
|
||||
}
|
||||
q += GetPixelChannels (map_image);
|
||||
}
|
||||
if (SyncCacheViewAuthenticPixels (map_image_view,exception) == MagickFalse)
|
||||
return MagickFalse;
|
||||
map_image_view = DestroyCacheView (map_image_view);
|
||||
}
|
||||
|
||||
{ /* Remap to the map_image. */
|
||||
ImageInfo *ii = AcquireImageInfo ();
|
||||
QuantizeInfo *quantize_info = AcquireQuantizeInfo (ii);
|
||||
quantize_info->dither_method = dither_method;
|
||||
(void) RemapImage (quantize_info, image, map_image, exception);
|
||||
quantize_info=DestroyQuantizeInfo(quantize_info);
|
||||
}
|
||||
map_image = DestroyImage (map_image);
|
||||
|
||||
} else {
|
||||
/* No dither. */
|
||||
if (image->storage_class == PseudoClass)
|
||||
{
|
||||
ssize_t
|
||||
i;
|
||||
|
||||
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
||||
#pragma omp parallel for schedule(static) shared(progress,status) \
|
||||
magick_number_threads(image,image,image->colors,1)
|
||||
#endif
|
||||
for (i=0; i < (ssize_t) image->colors; i++)
|
||||
{
|
||||
/*
|
||||
Posterize colormap.
|
||||
*/
|
||||
if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].red=(double)
|
||||
PosterizePixel(image->colormap[i].red,levels);
|
||||
if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].green=(double)
|
||||
PosterizePixel(image->colormap[i].green,levels);
|
||||
if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].blue=(double)
|
||||
PosterizePixel(image->colormap[i].blue,levels);
|
||||
if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].alpha=(double)
|
||||
PosterizePixel(image->colormap[i].alpha,levels);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Posterize image.
|
||||
*/
|
||||
progress=0;
|
||||
image_view=AcquireAuthenticCacheView(image,exception);
|
||||
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
||||
#pragma omp parallel for schedule(static) shared(progress,status) \
|
||||
magick_number_threads(image,image,image->rows,1)
|
||||
#endif
|
||||
for (y=0; y < (ssize_t) image->rows; y++)
|
||||
{
|
||||
Quantum
|
||||
*magick_restrict q;
|
||||
size_t
|
||||
channels = 0,
|
||||
number_columns;
|
||||
|
||||
ssize_t
|
||||
x;
|
||||
i;
|
||||
|
||||
if (status == MagickFalse)
|
||||
continue;
|
||||
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
|
||||
if (q == (Quantum *) NULL)
|
||||
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
|
||||
{
|
||||
PixelChannel channel = GetPixelChannelChannel(image,i);
|
||||
PixelTrait traits = GetPixelChannelTraits(image,channel);
|
||||
if ((traits & UpdatePixelTrait) != 0)
|
||||
channels++;
|
||||
}
|
||||
number_columns=pow(levels,channels);
|
||||
map_image=CloneImage(image,number_columns,1,MagickTrue,exception);
|
||||
if (map_image == (Image *) NULL)
|
||||
{
|
||||
status=MagickFalse;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (SetImageStorageClass(map_image,DirectClass,exception) == MagickFalse)
|
||||
{
|
||||
status=MagickFalse;
|
||||
break;
|
||||
}
|
||||
for (x=0; x < (ssize_t) image->columns; x++)
|
||||
{
|
||||
ssize_t
|
||||
i;
|
||||
CacheView
|
||||
*map_image_view;
|
||||
|
||||
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
|
||||
MagickRealType
|
||||
scale = QuantumRange/(levels-1.0);
|
||||
|
||||
Quantum
|
||||
*magick_restrict q;
|
||||
|
||||
ssize_t
|
||||
c,
|
||||
x;
|
||||
|
||||
/*
|
||||
Populate the map image.
|
||||
*/
|
||||
map_image_view=AcquireAuthenticCacheView (map_image,exception);
|
||||
q=GetCacheViewAuthenticPixels(map_image_view,0,0,number_columns,1,
|
||||
exception);
|
||||
if (q == (const Quantum *) NULL)
|
||||
{
|
||||
map_image_view=DestroyCacheView(map_image_view);
|
||||
status=MagickFalse;
|
||||
break;
|
||||
}
|
||||
for (x=0; x < (ssize_t) number_columns; x++)
|
||||
{
|
||||
PixelChannel channel = GetPixelChannelChannel(image,i);
|
||||
PixelTrait traits = GetPixelChannelTraits(image,channel);
|
||||
if ((traits & UpdatePixelTrait) == 0)
|
||||
continue;
|
||||
SetPixelChannel(image,channel,PosterizePixel(q[i],levels),q);
|
||||
size_t remainder = x;
|
||||
for (c=0; c < (ssize_t) GetPixelChannels(image); c++)
|
||||
{
|
||||
PixelChannel channel = GetPixelChannelChannel (image, c);
|
||||
PixelTrait traits = GetPixelChannelTraits (image, channel);
|
||||
if ((traits & UpdatePixelTrait) != 0)
|
||||
{
|
||||
size_t value = remainder % levels;
|
||||
SetPixelChannel(map_image,channel,scale*value,q);
|
||||
remainder=(remainder-value)/levels;
|
||||
}
|
||||
}
|
||||
q+=GetPixelChannels(map_image);
|
||||
}
|
||||
q+=GetPixelChannels(image);
|
||||
if (SyncCacheViewAuthenticPixels(map_image_view,exception) == MagickFalse)
|
||||
{
|
||||
map_image_view=DestroyCacheView(map_image_view);
|
||||
status=MagickFalse;
|
||||
break;
|
||||
}
|
||||
map_image_view=DestroyCacheView(map_image_view);
|
||||
}
|
||||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||||
status=MagickFalse;
|
||||
if (image->progress_monitor != (MagickProgressMonitor) NULL)
|
||||
if (status != MagickFalse)
|
||||
{
|
||||
MagickBooleanType
|
||||
proceed;
|
||||
/*
|
||||
Remap to the map image.
|
||||
*/
|
||||
QuantizeInfo *quantize_info = AcquireQuantizeInfo(
|
||||
(ImageInfo *) NULL);
|
||||
quantize_info->dither_method=dither_method;
|
||||
(void) RemapImage(quantize_info,image,map_image,exception);
|
||||
quantize_info=DestroyQuantizeInfo(quantize_info);
|
||||
}
|
||||
map_image=DestroyImage(map_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
No dither or too many levels.
|
||||
*/
|
||||
if (image->storage_class == PseudoClass)
|
||||
{
|
||||
ssize_t
|
||||
i;
|
||||
|
||||
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
||||
#pragma omp atomic
|
||||
#pragma omp parallel for schedule(static) shared(progress,status) \
|
||||
magick_number_threads(image,image,image->colors,1)
|
||||
#endif
|
||||
progress++;
|
||||
proceed=SetImageProgress(image,PosterizeImageTag,progress,
|
||||
image->rows);
|
||||
if (proceed == MagickFalse)
|
||||
status=MagickFalse;
|
||||
for (i=0; i < (ssize_t) image->colors; i++)
|
||||
{
|
||||
/*
|
||||
Posterize colormap.
|
||||
*/
|
||||
if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].red=(double)
|
||||
PosterizePixel(image->colormap[i].red,levels);
|
||||
if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].green=(double)
|
||||
PosterizePixel(image->colormap[i].green,levels);
|
||||
if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].blue=(double)
|
||||
PosterizePixel(image->colormap[i].blue,levels);
|
||||
if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
|
||||
image->colormap[i].alpha=(double)
|
||||
PosterizePixel(image->colormap[i].alpha,levels);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Posterize image.
|
||||
*/
|
||||
progress=0;
|
||||
image_view=AcquireAuthenticCacheView(image,exception);
|
||||
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
||||
#pragma omp parallel for schedule(static) shared(progress,status) \
|
||||
magick_number_threads(image,image,image->rows,1)
|
||||
#endif
|
||||
for (y=0; y < (ssize_t) image->rows; y++)
|
||||
{
|
||||
Quantum
|
||||
*magick_restrict q;
|
||||
|
||||
ssize_t
|
||||
x;
|
||||
|
||||
if (status == MagickFalse)
|
||||
continue;
|
||||
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
|
||||
exception);
|
||||
if (q == (Quantum *) NULL)
|
||||
{
|
||||
status=MagickFalse;
|
||||
continue;
|
||||
}
|
||||
for (x=0; x < (ssize_t) image->columns; x++)
|
||||
{
|
||||
ssize_t
|
||||
i;
|
||||
|
||||
for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
|
||||
{
|
||||
PixelChannel channel = GetPixelChannelChannel(image,i);
|
||||
PixelTrait traits = GetPixelChannelTraits(image,channel);
|
||||
if ((traits & UpdatePixelTrait) == 0)
|
||||
continue;
|
||||
SetPixelChannel(image,channel,PosterizePixel(q[i],levels),q);
|
||||
}
|
||||
q+=GetPixelChannels(image);
|
||||
}
|
||||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||||
status=MagickFalse;
|
||||
if (image->progress_monitor != (MagickProgressMonitor) NULL)
|
||||
{
|
||||
MagickBooleanType
|
||||
proceed;
|
||||
|
||||
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
||||
#pragma omp atomic
|
||||
#endif
|
||||
progress++;
|
||||
proceed=SetImageProgress(image,PosterizeImageTag,progress,
|
||||
image->rows);
|
||||
if (proceed == MagickFalse)
|
||||
status=MagickFalse;
|
||||
}
|
||||
}
|
||||
image_view=DestroyCacheView(image_view);
|
||||
{
|
||||
QuantizeInfo *quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
|
||||
quantize_info->number_colors=(size_t) MagickMin(levels*levels*levels,
|
||||
MaxColormapSize);
|
||||
quantize_info->dither_method=dither_method;
|
||||
status=QuantizeImage(quantize_info,image,exception);
|
||||
quantize_info=DestroyQuantizeInfo(quantize_info);
|
||||
}
|
||||
}
|
||||
image_view=DestroyCacheView(image_view);
|
||||
{
|
||||
QuantizeInfo *quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
|
||||
quantize_info->number_colors=(size_t) MagickMin(levels*levels*levels,
|
||||
MaxColormapSize);
|
||||
quantize_info->dither_method=dither_method;
|
||||
status=QuantizeImage(quantize_info,image,exception);
|
||||
quantize_info=DestroyQuantizeInfo(quantize_info);
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user