From 977511beedb466ea54946df2bc2f090d40dedb02 Mon Sep 17 00:00:00 2001 From: Cristy Date: Tue, 19 Mar 2024 21:07:46 -0400 Subject: [PATCH] validate the level argument of the -posterize option (https://github.com/ImageMagick/ImageMagick/issues/7181) --- MagickCore/quantize.c | 330 ++++++++++++++++++++++-------------------- 1 file changed, 177 insertions(+), 153 deletions(-) diff --git a/MagickCore/quantize.c b/MagickCore/quantize.c index cfea31b9ec..1a2299e07f 100644 --- a/MagickCore/quantize.c +++ b/MagickCore/quantize.c @@ -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); }