Commit message: https://github.com/ImageMagick/ImageMagick/issues/1754
CVE: CVE-2020-27754
CWE: CWE-190
Vulnerability description: In IntensityCompare() of /magick/quantize.c, there are calls to PixelPacketIntensity() which could return overflowed values to the caller when ImageMagick processes a crafted input file. To mitigate this, the patch introduces and uses the ConstrainPixelIntensity() function, which forces the pixel intensities to be within the proper bounds in the event of an overflow. This flaw affects ImageMagick versions prior to 6.9.10-69 and 7.0.8-69.

Project: ImageMagick6
File: quantize.c

MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
{
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(quantize_info != (QuantizeInfo *) NULL);
  (void) memset(quantize_info,0,sizeof(*quantize_info));
  quantize_info->number_colors=256;
  quantize_info->dither=MagickTrue;
  quantize_info->dither_method=RiemersmaDitherMethod;
  quantize_info->colorspace=UndefinedColorspace;
  quantize_info->measure_error=MagickFalse;
  quantize_info->signature=MagickCoreSignature;
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType PosterizeImageChannel(Image *image,
  const ChannelType channel,const size_t levels,const MagickBooleanType dither)
{
#define PosterizeImageTag  "Posterize/Image"
#define PosterizePixel(pixel) ClampToQuantum((MagickRealType) QuantumRange*( \
  MagickRound(QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  QuantizeInfo
    *quantize_info;

  register ssize_t
    i;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (image->storage_class == PseudoClass)
#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 ((channel & RedChannel) != 0)
        image->colormap[i].red=PosterizePixel(image->colormap[i].red);
      if ((channel & GreenChannel) != 0)
        image->colormap[i].green=PosterizePixel(image->colormap[i].green);
      if ((channel & BlueChannel) != 0)
        image->colormap[i].blue=PosterizePixel(image->colormap[i].blue);
      if ((channel & OpacityChannel) != 0)
        image->colormap[i].opacity=PosterizePixel(image->colormap[i].opacity);
    }
  /*
    Posterize image.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  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++)
  {
    register IndexPacket
      *magick_restrict indexes;

    register PixelPacket
      *magick_restrict q;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if ((channel & RedChannel) != 0)
        SetPixelRed(q,PosterizePixel(GetPixelRed(q)));
      if ((channel & GreenChannel) != 0)
        SetPixelGreen(q,PosterizePixel(GetPixelGreen(q)));
      if ((channel & BlueChannel) != 0)
        SetPixelBlue(q,PosterizePixel(GetPixelBlue(q)));
      if (((channel & OpacityChannel) != 0) &&
          (image->matte != MagickFalse))
        SetPixelOpacity(q,PosterizePixel(GetPixelOpacity(q)));
      if (((channel & IndexChannel) != 0) &&
          (image->colorspace == CMYKColorspace))
        SetPixelIndex(indexes+x,PosterizePixel(GetPixelIndex(indexes+x)));
      q++;
    }
    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);
  quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
  quantize_info->number_colors=(size_t) MagickMin((ssize_t) levels*levels*
    levels,MaxColormapSize+1);
  quantize_info->dither=dither;
  quantize_info->tree_depth=MaxTreeDepth;
  status=QuantizeImage(quantize_info,image);
  quantize_info=DestroyQuantizeInfo(quantize_info);
  return(status);
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
{
#define AssignImageTag  "Assign/Image"

  ColorspaceType
    colorspace;

  ssize_t
    y;

  /*
    Allocate image colormap.
  */
  colorspace=image->colorspace;
  if (cube_info->quantize_info->colorspace != UndefinedColorspace)
    (void) TransformImageColorspace(image,cube_info->quantize_info->colorspace);
  if (AcquireImageColormap(image,cube_info->colors) == MagickFalse)
    ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  image->colors=0;
  cube_info->transparent_pixels=0;
  cube_info->transparent_index=(-1);
  (void) DefineImageColormap(image,cube_info,cube_info->root);
  /*
    Create a reduced color image.
  */
  if ((cube_info->quantize_info->dither != MagickFalse) &&
      (cube_info->quantize_info->dither_method != NoDitherMethod))
    (void) DitherImage(image,cube_info);
  else
    {
      CacheView
        *image_view;

      ExceptionInfo
        *exception;

      MagickBooleanType
        status;

      status=MagickTrue;
      exception=(&image->exception);
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static) shared(status) \
        magick_number_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        CubeInfo
          cube;

        register IndexPacket
          *magick_restrict indexes;

        register PixelPacket
          *magick_restrict q;

        register ssize_t
          x;

        ssize_t
          count;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        indexes=GetCacheViewAuthenticIndexQueue(image_view);
        cube=(*cube_info);
        for (x=0; x < (ssize_t) image->columns; x+=count)
        {
          DoublePixelPacket
            pixel;

          register const NodeInfo
            *node_info;

          register ssize_t
            i;

          size_t
            id,
            index;

          /*
            Identify the deepest node containing the pixel's color.
          */
          for (count=1; (x+count) < (ssize_t) image->columns; count++)
            if (IsSameColor(image,q,q+count) == MagickFalse)
              break;
          AssociateAlphaPixel(&cube,q,&pixel);
          node_info=cube.root;
          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
          {
            id=ColorToNodeId(&cube,&pixel,index);
            if (node_info->child[id] == (NodeInfo *) NULL)
              break;
            node_info=node_info->child[id];
          }
          /*
            Find closest color among siblings and their children.
          */
          cube.target=pixel;
          cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
            (QuantumRange+1.0)+1.0);
          ClosestColor(image,&cube,node_info->parent);
          index=cube.color_number;
          for (i=0; i < (ssize_t) count; i++)
          {
            if (image->storage_class == PseudoClass)
              SetPixelIndex(indexes+x+i,index);
            if (cube.quantize_info->measure_error == MagickFalse)
              {
                SetPixelRgb(q,image->colormap+index);
                if (cube.associate_alpha != MagickFalse)
                  SetPixelOpacity(q,image->colormap[index].opacity);
              }
            q++;
          }
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
        if (image->progress_monitor != (MagickProgressMonitor) NULL)
          {
            MagickBooleanType
              proceed;

            proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
              image->rows);
            if (proceed == MagickFalse)
              status=MagickFalse;
          }
      }
      image_view=DestroyCacheView(image_view);
    }
  if (cube_info->quantize_info->measure_error != MagickFalse)
    (void) GetImageQuantizeError(image);
  if ((cube_info->quantize_info->number_colors == 2) &&
      ((cube_info->quantize_info->colorspace == LinearGRAYColorspace) ||
       (cube_info->quantize_info->colorspace == GRAYColorspace)))
    {
      double
        intensity;

      /*
        Monochrome image.
      */
      intensity=0.0;
      if ((image->colors > 1) &&
          (GetPixelLuma(image,image->colormap+0) > 
           GetPixelLuma(image,image->colormap+1)))
        intensity=(double) QuantumRange;
      image->colormap[0].red=intensity;
      image->colormap[0].green=intensity;
      image->colormap[0].blue=intensity;
      if (image->colors > 1)
        {
          image->colormap[1].red=(double) QuantumRange-intensity;
          image->colormap[1].green=(double) QuantumRange-intensity;
          image->colormap[1].blue=(double) QuantumRange-intensity;
        }
    }
  (void) SyncImage(image);
  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
      (IssRGBCompatibleColorspace(colorspace) == MagickFalse))
    (void) TransformImageColorspace(image,colorspace);
  return(MagickTrue);
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
  Image *image,const Image *remap_image)
{
  CubeInfo
    *cube_info;

  MagickBooleanType
    status;

  /*
    Initialize color cube.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(remap_image != (Image *) NULL);
  assert(remap_image->signature == MagickCoreSignature);
  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
    quantize_info->number_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
  if (status != MagickFalse)
    {
      /*
        Classify image colors from the reference image.
      */
      cube_info->quantize_info->number_colors=cube_info->colors;
      status=AssignImageColors(image,cube_info);
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
{
  CacheView
    *image_view;

  MagickBooleanType
    status;

  register ssize_t
    i;

  size_t
    depth;

  if (cube_info->quantize_info->dither_method != RiemersmaDitherMethod)
    return(FloydSteinbergDither(image,cube_info));
  /*
    Distribute quantization error along a Hilbert curve.
  */
  (void) memset(cube_info->error,0,ErrorQueueLength*sizeof(*cube_info->error));
  cube_info->x=0;
  cube_info->y=0;
  i=MagickMax((ssize_t) image->columns,(ssize_t) image->rows);
  for (depth=1; i != 0; depth++)
    i>>=1;
  if ((ssize_t) (1L << depth) < MagickMax((ssize_t) image->columns,(ssize_t) image->rows))
    depth++;
  cube_info->offset=0;
  cube_info->span=(MagickSizeType) image->columns*image->rows;
  image_view=AcquireAuthenticCacheView(image,&image->exception);
  if (depth > 1)
    Riemersma(image,image_view,cube_info,depth-1,NorthGravity);
  status=RiemersmaDither(image,image_view,cube_info,ForgetGravity);
  image_view=DestroyCacheView(image_view);
  return(status);
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info)
{
#define DitherImageTag  "Dither/Image"

  CacheView
    *image_view;

  const char
    *artifact;

  double
    amount;

  DoublePixelPacket
    **pixels;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  ssize_t
    y;

  /*
    Distribute quantization error using Floyd-Steinberg.
  */
  pixels=AcquirePixelThreadSet(image->columns);
  if (pixels == (DoublePixelPacket **) NULL)
    return(MagickFalse);
  exception=(&image->exception);
  status=MagickTrue;
  amount=1.0;
  artifact=GetImageArtifact(image,"dither:diffusion-amount");
  if (artifact != (const char *) NULL)
    amount=StringToDoubleInterval(artifact,1.0);
  image_view=AcquireAuthenticCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    const int
      id = GetOpenMPThreadId();

    CubeInfo
      cube;

    DoublePixelPacket
      *current,
      *previous;

    register IndexPacket
      *magick_restrict indexes;

    register PixelPacket
      *magick_restrict q;

    register ssize_t
      x;

    size_t
      index;

    ssize_t
      v;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    cube=(*cube_info);
    current=pixels[id]+(y & 0x01)*image->columns;
    previous=pixels[id]+((y+1) & 0x01)*image->columns;
    v=(ssize_t) ((y & 0x01) ? -1 : 1);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      DoublePixelPacket
        color,
        pixel;

      register ssize_t
        i;

      ssize_t
        u;

      u=(y & 0x01) ? (ssize_t) image->columns-1-x : x;
      AssociateAlphaPixel(&cube,q+u,&pixel);
      if (x > 0)
        {
          pixel.red+=7.0*amount*current[u-v].red/16;
          pixel.green+=7.0*amount*current[u-v].green/16;
          pixel.blue+=7.0*amount*current[u-v].blue/16;
          if (cube.associate_alpha != MagickFalse)
            pixel.opacity+=7.0*amount*current[u-v].opacity/16;
        }
      if (y > 0)
        {
          if (x < (ssize_t) (image->columns-1))
            {
              pixel.red+=previous[u+v].red/16;
              pixel.green+=previous[u+v].green/16;
              pixel.blue+=previous[u+v].blue/16;
              if (cube.associate_alpha != MagickFalse)
                pixel.opacity+=previous[u+v].opacity/16;
            }
          pixel.red+=5.0*amount*previous[u].red/16;
          pixel.green+=5.0*amount*previous[u].green/16;
          pixel.blue+=5.0*amount*previous[u].blue/16;
          if (cube.associate_alpha != MagickFalse)
            pixel.opacity+=5.0*amount*previous[u].opacity/16;
          if (x > 0)
            {
              pixel.red+=3.0*amount*previous[u-v].red/16;
              pixel.green+=3.0*amount*previous[u-v].green/16;
              pixel.blue+=3.0*amount*previous[u-v].blue/16;
              if (cube.associate_alpha != MagickFalse)
                pixel.opacity+=3.0*amount*previous[u-v].opacity/16;
            }
        }
      pixel.red=(MagickRealType) ClampPixel(pixel.red);
      pixel.green=(MagickRealType) ClampPixel(pixel.green);
      pixel.blue=(MagickRealType) ClampPixel(pixel.blue);
      if (cube.associate_alpha != MagickFalse)
        pixel.opacity=(MagickRealType) ClampPixel(pixel.opacity);
      i=CacheOffset(&cube,&pixel);
      if (cube.cache[i] < 0)
        {
          register NodeInfo
            *node_info;

          register size_t
            id;

          /*
            Identify the deepest node containing the pixel's color.
          */
          node_info=cube.root;
          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
          {
            id=ColorToNodeId(&cube,&pixel,index);
            if (node_info->child[id] == (NodeInfo *) NULL)
              break;
            node_info=node_info->child[id];
          }
          /*
            Find closest color among siblings and their children.
          */
          cube.target=pixel;
          cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
            1.0)+1.0);
          ClosestColor(image,&cube,node_info->parent);
          cube.cache[i]=(ssize_t) cube.color_number;
        }
      /*
        Assign pixel to closest colormap entry.
      */
      index=(size_t) cube.cache[i];
      if (image->storage_class == PseudoClass)
        SetPixelIndex(indexes+u,index);
      if (cube.quantize_info->measure_error == MagickFalse)
        {
          SetPixelRgb(q+u,image->colormap+index);
          if (cube.associate_alpha != MagickFalse)
            SetPixelOpacity(q+u,image->colormap[index].opacity);
        }
      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
        status=MagickFalse;
      /*
        Store the error.
      */
      AssociateAlphaPixel(&cube,image->colormap+index,&color);
      current[u].red=pixel.red-color.red;
      current[u].green=pixel.green-color.green;
      current[u].blue=pixel.blue-color.blue;
      if (cube.associate_alpha != MagickFalse)
        current[u].opacity=pixel.opacity-color.opacity;
      if (image->progress_monitor != (MagickProgressMonitor) NULL)
        {
          MagickBooleanType
            proceed;

          proceed=SetImageProgress(image,DitherImageTag,(MagickOffsetType) y,
            image->rows);
          if (proceed == MagickFalse)
            status=MagickFalse;
        }
    }
  }
  image_view=DestroyCacheView(image_view);
  pixels=DestroyPixelThreadSet(pixels);
  return(MagickTrue);
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType GetImageQuantizeError(Image *image)
{
  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  IndexPacket
    *indexes;

  MagickRealType
    alpha,
    area,
    beta,
    distance,
    gamma,
    maximum_error,
    mean_error,
    mean_error_per_pixel;

  ssize_t
    index,
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  image->total_colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
  (void) memset(&image->error,0,sizeof(image->error));
  if (image->storage_class == DirectClass)
    return(MagickTrue);
  alpha=1.0;
  beta=1.0;
  area=3.0*image->columns*image->rows;
  maximum_error=0.0;
  mean_error_per_pixel=0.0;
  mean_error=0.0;
  exception=(&image->exception);
  image_view=AcquireVirtualCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      index=(ssize_t) GetPixelIndex(indexes+x);
      if (image->matte != MagickFalse)
        {
          alpha=(MagickRealType) (QuantumScale*(GetPixelAlpha(p)));
          beta=(MagickRealType) (QuantumScale*(QuantumRange-
            image->colormap[index].opacity));
        }
      distance=fabs((double) (alpha*GetPixelRed(p)-beta*
        image->colormap[index].red));
      mean_error_per_pixel+=distance;
      mean_error+=distance*distance;
      if (distance > maximum_error)
        maximum_error=distance;
      distance=fabs((double) (alpha*GetPixelGreen(p)-beta*
        image->colormap[index].green));
      mean_error_per_pixel+=distance;
      mean_error+=distance*distance;
      if (distance > maximum_error)
        maximum_error=distance;
      distance=fabs((double) (alpha*GetPixelBlue(p)-beta*
        image->colormap[index].blue));
      mean_error_per_pixel+=distance;
      mean_error+=distance*distance;
      if (distance > maximum_error)
        maximum_error=distance;
      p++;
    }
  }
  image_view=DestroyCacheView(image_view);
  gamma=PerceptibleReciprocal(area);
  image->error.mean_error_per_pixel=gamma*mean_error_per_pixel;
  image->error.normalized_mean_error=gamma*QuantumScale*QuantumScale*mean_error;
  image->error.normalized_maximum_error=QuantumScale*maximum_error;
  return(MagickTrue);
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
  const Image *image,ExceptionInfo *exception)
{
#define ClassifyImageTag  "Classify/Image"

  CacheView
    *image_view;

  DoublePixelPacket
    error,
    mid,
    midpoint,
    pixel;

  MagickBooleanType
    proceed;

  MagickRealType
    bisect;

  NodeInfo
    *node_info;

  size_t
    count,
    id,
    index,
    level;

  ssize_t
    y;

  /*
    Classify the first cube_info->maximum_colors colors to a tree depth of 8.
  */
  SetAssociatedAlpha(image,cube_info);
  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
      (cube_info->quantize_info->colorspace != CMYKColorspace))
    (void) TransformImageColorspace((Image *) image,
      cube_info->quantize_info->colorspace);
  else
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
      (void) TransformImageColorspace((Image *) image,sRGBColorspace);
  midpoint.red=(MagickRealType) QuantumRange/2.0;
  midpoint.green=(MagickRealType) QuantumRange/2.0;
  midpoint.blue=(MagickRealType) QuantumRange/2.0;
  midpoint.opacity=(MagickRealType) QuantumRange/2.0;
  midpoint.index=(MagickRealType) QuantumRange/2.0;
  error.opacity=0.0;
  image_view=AcquireVirtualCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      break;
    if (cube_info->nodes > MaxNodes)
      {
        /*
          Prune one level if the color tree is too large.
        */
        PruneLevel(cube_info,cube_info->root);
        cube_info->depth--;
      }
    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
    {
      /*
        Start at the root and descend the color cube tree.
      */
      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
        if (IsSameColor(image,p,p+count) == MagickFalse)
          break;
      AssociateAlphaPixel(cube_info,p,&pixel);
      index=MaxTreeDepth-1;
      bisect=((MagickRealType) QuantumRange+1.0)/2.0;
      mid=midpoint;
      node_info=cube_info->root;
      for (level=1; level <= MaxTreeDepth; level++)
      {
        double
          distance;

        bisect*=0.5;
        id=ColorToNodeId(cube_info,&pixel,index);
        mid.red+=(id & 1) != 0 ? bisect : -bisect;
        mid.green+=(id & 2) != 0 ? bisect : -bisect;
        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
        mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
        if (node_info->child[id] == (NodeInfo *) NULL)
          {
            /*
              Set colors of new node to contain pixel.
            */
            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
            if (node_info->child[id] == (NodeInfo *) NULL)
              {
                (void) ThrowMagickException(exception,GetMagickModule(),
                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
                  image->filename);
                continue;
              }
            if (level == MaxTreeDepth)
              cube_info->colors++;
          }
        /*
          Approximate the quantization error represented by this node.
        */
        node_info=node_info->child[id];
        error.red=QuantumScale*(pixel.red-mid.red);
        error.green=QuantumScale*(pixel.green-mid.green);
        error.blue=QuantumScale*(pixel.blue-mid.blue);
        if (cube_info->associate_alpha != MagickFalse)
          error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
        distance=(double) (error.red*error.red+error.green*error.green+
          error.blue*error.blue+error.opacity*error.opacity);
        if (IsNaN(distance) != MagickFalse)
          distance=0.0;
        node_info->quantize_error+=count*sqrt(distance);
        cube_info->root->quantize_error+=node_info->quantize_error;
        index--;
      }
      /*
        Sum RGB for this leaf for later derivation of the mean cube color.
      */
      node_info->number_unique+=count;
      node_info->total_color.red+=count*QuantumScale*ClampPixel(pixel.red);
      node_info->total_color.green+=count*QuantumScale*ClampPixel(pixel.green);
      node_info->total_color.blue+=count*QuantumScale*ClampPixel(pixel.blue);
      if (cube_info->associate_alpha != MagickFalse)
        node_info->total_color.opacity+=count*QuantumScale*
          ClampPixel(pixel.opacity);
      else
        node_info->total_color.opacity+=count*QuantumScale*
          ClampPixel(OpaqueOpacity);
      p+=count;
    }
    if (cube_info->colors > cube_info->maximum_colors)
      {
        PruneToCubeDepth(cube_info,cube_info->root);
        break;
      }
    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
      image->rows);
    if (proceed == MagickFalse)
      break;
  }
  for (y++; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      break;
    if (cube_info->nodes > MaxNodes)
      {
        /*
          Prune one level if the color tree is too large.
        */
        PruneLevel(cube_info,cube_info->root);
        cube_info->depth--;
      }
    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
    {
      /*
        Start at the root and descend the color cube tree.
      */
      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
        if (IsSameColor(image,p,p+count) == MagickFalse)
          break;
      AssociateAlphaPixel(cube_info,p,&pixel);
      index=MaxTreeDepth-1;
      bisect=((MagickRealType) QuantumRange+1.0)/2.0;
      mid=midpoint;
      node_info=cube_info->root;
      for (level=1; level <= cube_info->depth; level++)
      {
        double
          distance;

        bisect*=0.5;
        id=ColorToNodeId(cube_info,&pixel,index);
        mid.red+=(id & 1) != 0 ? bisect : -bisect;
        mid.green+=(id & 2) != 0 ? bisect : -bisect;
        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
        mid.opacity+=(id & 8) != 0 ? bisect : -bisect;
        if (node_info->child[id] == (NodeInfo *) NULL)
          {
            /*
              Set colors of new node to contain pixel.
            */
            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
            if (node_info->child[id] == (NodeInfo *) NULL)
              {
                (void) ThrowMagickException(exception,GetMagickModule(),
                  ResourceLimitError,"MemoryAllocationFailed","%s",
                  image->filename);
                  continue;
               }
            if (level == cube_info->depth)
              cube_info->colors++;
          }
        /*
          Approximate the quantization error represented by this node.
        */
        node_info=node_info->child[id];
        error.red=QuantumScale*(pixel.red-mid.red);
        error.green=QuantumScale*(pixel.green-mid.green);
        error.blue=QuantumScale*(pixel.blue-mid.blue);
        if (cube_info->associate_alpha != MagickFalse)
          error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
        distance=(double) (error.red*error.red+error.green*error.green+
          error.blue*error.blue+error.opacity*error.opacity);
        if (IsNaN(distance))
          distance=0.0;
        node_info->quantize_error+=count*sqrt(distance);
        cube_info->root->quantize_error+=node_info->quantize_error;
        index--;
      }
      /*
        Sum RGB for this leaf for later derivation of the mean cube color.
      */
      node_info->number_unique+=count;
      node_info->total_color.red+=count*QuantumScale*ClampPixel(pixel.red);
      node_info->total_color.green+=count*QuantumScale*ClampPixel(pixel.green);
      node_info->total_color.blue+=count*QuantumScale*ClampPixel(pixel.blue);
      if (cube_info->associate_alpha != MagickFalse)
        node_info->total_color.opacity+=count*QuantumScale*ClampPixel(
          pixel.opacity);
      else
        node_info->total_color.opacity+=count*QuantumScale*
          ClampPixel(OpaqueOpacity);
      p+=count;
    }
    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
      image->rows);
    if (proceed == MagickFalse)
      break;
  }
  image_view=DestroyCacheView(image_view);
  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
      (cube_info->quantize_info->colorspace != CMYKColorspace))
    (void) TransformImageColorspace((Image *) image,sRGBColorspace);
  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
  CubeInfo *cube_info,const unsigned int direction)
{
#define DitherImageTag  "Dither/Image"

  DoublePixelPacket
    color,
    pixel;

  MagickBooleanType
    proceed;

  register CubeInfo
    *p;

  size_t
    index;

  p=cube_info;
  if ((p->x >= 0) && (p->x < (ssize_t) image->columns) &&
      (p->y >= 0) && (p->y < (ssize_t) image->rows))
    {
      ExceptionInfo
        *exception;

      register IndexPacket
        *magick_restrict indexes;

      register PixelPacket
        *magick_restrict q;

      register ssize_t
        i;

      /*
        Distribute error.
      */
      exception=(&image->exception);
      q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
      if (q == (PixelPacket *) NULL)
        return(MagickFalse);
      indexes=GetCacheViewAuthenticIndexQueue(image_view);
      AssociateAlphaPixel(cube_info,q,&pixel);
      for (i=0; i < ErrorQueueLength; i++)
      {
        pixel.red+=p->weights[i]*p->error[i].red;
        pixel.green+=p->weights[i]*p->error[i].green;
        pixel.blue+=p->weights[i]*p->error[i].blue;
        if (cube_info->associate_alpha != MagickFalse)
          pixel.opacity+=p->weights[i]*p->error[i].opacity;
      }
      pixel.red=(MagickRealType) ClampPixel(pixel.red);
      pixel.green=(MagickRealType) ClampPixel(pixel.green);
      pixel.blue=(MagickRealType) ClampPixel(pixel.blue);
      if (cube_info->associate_alpha != MagickFalse)
        pixel.opacity=(MagickRealType) ClampPixel(pixel.opacity);
      i=CacheOffset(cube_info,&pixel);
      if (p->cache[i] < 0)
        {
          register NodeInfo
            *node_info;

          register size_t
            id;

          /*
            Identify the deepest node containing the pixel's color.
          */
          node_info=p->root;
          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
          {
            id=ColorToNodeId(cube_info,&pixel,index);
            if (node_info->child[id] == (NodeInfo *) NULL)
              break;
            node_info=node_info->child[id];
          }
          /*
            Find closest color among siblings and their children.
          */
          p->target=pixel;
          p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*((MagickRealType)
            QuantumRange+1.0)+1.0);
          ClosestColor(image,p,node_info->parent);
          p->cache[i]=(ssize_t) p->color_number;
        }
      /*
        Assign pixel to closest colormap entry.
      */
      index=(size_t) (1*p->cache[i]);
      if (image->storage_class == PseudoClass)
        *indexes=(IndexPacket) index;
      if (cube_info->quantize_info->measure_error == MagickFalse)
        {
          SetPixelRgb(q,image->colormap+index);
          if (cube_info->associate_alpha != MagickFalse)
            SetPixelOpacity(q,image->colormap[index].opacity);
        }
      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
        return(MagickFalse);
      /*
        Propagate the error as the last entry of the error queue.
      */
      (void) memmove(p->error,p->error+1,(ErrorQueueLength-1)*
        sizeof(p->error[0]));
      AssociateAlphaPixel(cube_info,image->colormap+index,&color);
      p->error[ErrorQueueLength-1].red=pixel.red-color.red;
      p->error[ErrorQueueLength-1].green=pixel.green-color.green;
      p->error[ErrorQueueLength-1].blue=pixel.blue-color.blue;
      if (cube_info->associate_alpha != MagickFalse)
        p->error[ErrorQueueLength-1].opacity=pixel.opacity-color.opacity;
      proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
      if (proceed == MagickFalse)
        return(MagickFalse);
      p->offset++;
    }
  switch (direction)
  {
    case WestGravity: p->x--; break;
    case EastGravity: p->x++; break;
    case NorthGravity: p->y--; break;
    case SouthGravity: p->y++; break;
  }
  return(MagickTrue);
}

Project: ImageMagick6
File: quantize.c

static CubeInfo *GetCubeInfo(const QuantizeInfo *quantize_info,
  const size_t depth,const size_t maximum_colors)
{
  CubeInfo
    *cube_info;

  MagickRealType
    sum,
    weight;

  register ssize_t
    i;

  size_t
    length;

  /*
    Initialize tree to describe color cube_info.
  */
  cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
  if (cube_info == (CubeInfo *) NULL)
    return((CubeInfo *) NULL);
  (void) memset(cube_info,0,sizeof(*cube_info));
  cube_info->depth=depth;
  if (cube_info->depth > MaxTreeDepth)
    cube_info->depth=MaxTreeDepth;
  if (cube_info->depth < 2)
    cube_info->depth=2;
  cube_info->maximum_colors=maximum_colors;
  /*
    Initialize root node.
  */
  cube_info->root=GetNodeInfo(cube_info,0,0,(NodeInfo *) NULL);
  if (cube_info->root == (NodeInfo *) NULL)
    return((CubeInfo *) NULL);
  cube_info->root->parent=cube_info->root;
  cube_info->quantize_info=CloneQuantizeInfo(quantize_info);
  if (cube_info->quantize_info->dither == MagickFalse)
    return(cube_info);
  /*
    Initialize dither resources.
  */
  length=(size_t) (1UL << (4*(8-CacheShift)));
  cube_info->memory_info=AcquireVirtualMemory(length,sizeof(*cube_info->cache));
  if (cube_info->memory_info == (MemoryInfo *) NULL)
    return((CubeInfo *) NULL);
  cube_info->cache=(ssize_t *) GetVirtualMemoryBlob(cube_info->memory_info);
  /*
    Initialize color cache.
  */
  (void) memset(cube_info->cache,(-1),sizeof(*cube_info->cache)*length);
  /*
    Distribute weights along a curve of exponential decay.
  */
  weight=1.0;
  for (i=0; i < ErrorQueueLength; i++)
  {
    cube_info->weights[ErrorQueueLength-i-1]=PerceptibleReciprocal(weight);
    weight*=exp(log(((double) QuantumRange+1.0))/(ErrorQueueLength-1.0));
  }
  /*
    Normalize the weighting factors.
  */
  weight=0.0;
  for (i=0; i < ErrorQueueLength; i++)
    weight+=cube_info->weights[i];
  sum=0.0;
  for (i=0; i < ErrorQueueLength; i++)
  {
    cube_info->weights[i]/=weight;
    sum+=cube_info->weights[i];
  }
  cube_info->weights[0]+=1.0-sum;
  return(cube_info);
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
  Image *images)
{
  CubeInfo
    *cube_info;

  Image
    *image;

  MagickBooleanType
    proceed,
    status;

  MagickProgressMonitor
    progress_monitor;

  register ssize_t
    i;

  size_t
    depth,
    maximum_colors,
    number_images;

  assert(quantize_info != (const QuantizeInfo *) NULL);
  assert(quantize_info->signature == MagickCoreSignature);
  assert(images != (Image *) NULL);
  assert(images->signature == MagickCoreSignature);
  if (images->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
  if (GetNextImageInList(images) == (Image *) NULL)
    {
      /*
        Handle a single image with QuantizeImage.
      */
      status=QuantizeImage(quantize_info,images);
      return(status);
    }
  status=MagickFalse;
  maximum_colors=quantize_info->number_colors;
  if (maximum_colors == 0)
    maximum_colors=MaxColormapSize;
  if (maximum_colors > MaxColormapSize)
    maximum_colors=MaxColormapSize;
  depth=quantize_info->tree_depth;
  if (depth == 0)
    {
      size_t
        colors;

      /*
        Depth of color tree is: Log4(colormap size)+2.
      */
      colors=maximum_colors;
      for (depth=1; colors != 0; depth++)
        colors>>=2;
      if (quantize_info->dither != MagickFalse)
        depth--;
    }
  /*
    Initialize color cube.
  */
  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
  if (cube_info == (CubeInfo *) NULL)
    {
      (void) ThrowMagickException(&images->exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
      return(MagickFalse);
    }
  number_images=GetImageListLength(images);
  image=images;
  for (i=0; image != (Image *) NULL; i++)
  {
    progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
      image->client_data);
    status=ClassifyImageColors(cube_info,image,&image->exception);
    if (status == MagickFalse)
      break;
    (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
    proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
      number_images);
    if (proceed == MagickFalse)
      break;
    image=GetNextImageInList(image);
  }
  if (status != MagickFalse)
    {
      /*
        Reduce the number of colors in an image sequence.
      */
      ReduceImageColors(images,cube_info);
      image=images;
      for (i=0; image != (Image *) NULL; i++)
      {
        progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor)
          NULL,image->client_data);
        status=AssignImageColors(image,cube_info);
        if (status == MagickFalse)
          break;
        (void) SetImageProgressMonitor(image,progress_monitor,
          image->client_data);
        proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
          number_images);
        if (proceed == MagickFalse)
          break;
        image=GetNextImageInList(image);
      }
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick6
File: quantize.c

static int IntensityCompare(const void *x,const void *y)
{
  PixelPacket
    *color_1,
    *color_2;

  ssize_t
    intensity;

  color_1=(PixelPacket *) x;
  color_2=(PixelPacket *) y;
  intensity=(ssize_t) ConstrainPixelIntensity(PixelPacketIntensity(color_1))-
    (ssize_t) ConstrainPixelIntensity(PixelPacketIntensity(color_2));
  return((int) intensity);
}

Project: ImageMagick6
File: quantize.c

static inline void SetAssociatedAlpha(const Image *image,CubeInfo *cube_info)
{
  MagickBooleanType
    associate_alpha;

  associate_alpha=image->matte;
  if ((cube_info->quantize_info->number_colors == 2) &&
      ((cube_info->quantize_info->colorspace == LinearGRAYColorspace) ||
       (cube_info->quantize_info->colorspace == GRAYColorspace)))
    associate_alpha=MagickFalse;
  cube_info->associate_alpha=associate_alpha;
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
  Image *image)
{
  CubeInfo
    *cube_info;

  MagickBooleanType
    status;

  size_t
    depth,
    maximum_colors;

  assert(quantize_info != (const QuantizeInfo *) NULL);
  assert(quantize_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  maximum_colors=quantize_info->number_colors;
  if (maximum_colors == 0)
    maximum_colors=MaxColormapSize;
  if (maximum_colors > MaxColormapSize)
    maximum_colors=MaxColormapSize;
  if (image->matte == MagickFalse)
    {
      if (SetImageGray(image,&image->exception) != MagickFalse)
        (void) SetGrayscaleImage(image);
    }
  if ((quantize_info->dither == MagickFalse) &&
      (image->storage_class == PseudoClass) &&
      (image->colors <= maximum_colors))
    {
      if ((quantize_info->colorspace != UndefinedColorspace) &&
          (quantize_info->colorspace != CMYKColorspace))
        (void) TransformImageColorspace(image,quantize_info->colorspace);
      return(MagickTrue);
    }
  depth=quantize_info->tree_depth;
  if (depth == 0)
    {
      size_t
        colors;

      /*
        Depth of color tree is: Log4(colormap size)+2.
      */
      colors=maximum_colors;
      for (depth=1; colors != 0; depth++)
        colors>>=2;
      if ((quantize_info->dither != MagickFalse) && (depth > 2))
        depth--;
      if ((image->matte != MagickFalse) && (depth > 5))
        depth--;
      if (SetImageGray(image,&image->exception) != MagickFalse)
        depth=MaxTreeDepth;
    }
  /*
    Initialize color cube.
  */
  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,image,&image->exception);
  if (status != MagickFalse)
    {
      /*
        Reduce the number of colors in the image.
      */
      if (cube_info->colors > cube_info->maximum_colors)
        ReduceImageColors(image,cube_info);
      status=AssignImageColors(image,cube_info);
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType CompressImageColormap(Image *image)
{
  QuantizeInfo
    quantize_info;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (IsPaletteImage(image,&image->exception) == MagickFalse)
    return(MagickFalse);
  GetQuantizeInfo(&quantize_info);
  quantize_info.number_colors=image->colors;
  quantize_info.tree_depth=MaxTreeDepth;
  return(QuantizeImage(&quantize_info,image));
}

Project: ImageMagick6
File: quantize.c

static MagickBooleanType SetGrayscaleImage(Image *image)
{
  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  PixelPacket
    *colormap;

  register ssize_t
    i;

  size_t
    extent;

  ssize_t
    *colormap_index,
    j,
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  exception=(&image->exception);
  if (image->type != GrayscaleType)
    (void) TransformImageColorspace(image,GRAYColorspace);
  extent=MagickMax(image->colors+1,MagickMax(MaxColormapSize,MaxMap+1));
  colormap_index=(ssize_t *) AcquireQuantumMemory(extent,
    sizeof(*colormap_index));
  if (colormap_index == (ssize_t *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  if (image->storage_class != PseudoClass)
    {
      (void) memset(colormap_index,(-1),extent*sizeof(*colormap_index));
      if (AcquireImageColormap(image,MaxColormapSize) == MagickFalse)
        {
          colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
            image->filename);
        }
      image->colors=0;
      status=MagickTrue;
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static) shared(status) \
        magick_number_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register IndexPacket
          *magick_restrict indexes;

        register PixelPacket
          *magick_restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        indexes=GetCacheViewAuthenticIndexQueue(image_view);
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          register size_t
            intensity;

          intensity=ScaleQuantumToMap(GetPixelRed(q));
          if (colormap_index[intensity] < 0)
            {
#if defined(MAGICKCORE_OPENMP_SUPPORT)
              #pragma omp critical (MagickCore_SetGrayscaleImage)
#endif
              if (colormap_index[intensity] < 0)
                {
                  colormap_index[intensity]=(ssize_t) image->colors;
                  image->colormap[image->colors].red=GetPixelRed(q);
                  image->colormap[image->colors].green=GetPixelGreen(q);
                  image->colormap[image->colors].blue=GetPixelBlue(q);
                  image->colors++;
               }
            }
          SetPixelIndex(indexes+x,colormap_index[intensity]);
          q++;
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
    }
  (void) memset(colormap_index,0,extent*sizeof(*colormap_index));
  for (i=0; i < (ssize_t) image->colors; i++)
    image->colormap[i].opacity=(Quantum) i;
  qsort((void *) image->colormap,image->colors,sizeof(PixelPacket),
    IntensityCompare);
  colormap=(PixelPacket *) AcquireQuantumMemory(image->colors,
    sizeof(*colormap));
  if (colormap == (PixelPacket *) NULL)
    {
      colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
    }
  j=0;
  colormap[j]=image->colormap[0];
  for (i=0; i < (ssize_t) image->colors; i++)
  {
    if (IsSameColor(image,&colormap[j],&image->colormap[i]) == MagickFalse)
      {
        j++;
        colormap[j]=image->colormap[i];
      }
    colormap_index[(ssize_t) image->colormap[i].opacity]=j;
  }
  image->colors=(size_t) (j+1);
  image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
  image->colormap=colormap;
  status=MagickTrue;
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static) shared(status) \
    magick_number_threads(image,image,image->rows,1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register IndexPacket
      *magick_restrict indexes;

    register const PixelPacket
      *magick_restrict q;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
      SetPixelIndex(indexes+x,colormap_index[ScaleQuantumToMap(GetPixelIndex(
        indexes+x))]);
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
  }
  image_view=DestroyCacheView(image_view);
  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
  image->type=GrayscaleType;
  if (SetImageMonochrome(image,&image->exception) != MagickFalse)
    image->type=BilevelType;
  return(status);
}

Project: ImageMagick6
File: quantize.c

MagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
  Image *images,const Image *remap_image)
{
  CubeInfo
    *cube_info;

  Image
    *image;

  MagickBooleanType
    status;

  assert(images != (Image *) NULL);
  assert(images->signature == MagickCoreSignature);
  if (images->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
  image=images;
  if (remap_image == (Image *) NULL)
    {
      /*
        Create a global colormap for an image sequence.
      */
      status=QuantizeImages(quantize_info,images);
      return(status);
    }
  /*
    Classify image colors from the reference image.
  */
  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
    quantize_info->number_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
  if (status != MagickFalse)
    {
      /*
        Classify image colors from the reference image.
      */
      cube_info->quantize_info->number_colors=cube_info->colors;
      image=images;
      for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
      {
        status=AssignImageColors(image,cube_info);
        if (status == MagickFalse)
          break;
      }
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick6
File: quantize.c

static inline double ConstrainPixelIntensity(double x)
{
  if (x < (double) -(SSIZE_MAX-512))
    return((double) -(SSIZE_MAX-512));
  if (x > (double) (SSIZE_MAX-512))
    return((double) (SSIZE_MAX-512));
  return(x);
}