Commit message: https://github.com/ImageMagick/ImageMagick/issues/574
CVE: CVE-2017-12664
CWE: CWE-703
Vulnerability description: ImageMagick 7.0.6-2 has a memory leak vulnerability in WritePALMImage in coders/palm.c.

Project: ImageMagick
File: quantize.c

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

  ssize_t
    y;

  /*
    Allocate image colormap.
  */
  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
      (cube_info->quantize_info->colorspace != CMYKColorspace))
    (void) TransformImageColorspace(image,cube_info->quantize_info->colorspace,
      exception);
  else
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
  if (AcquireImageColormap(image,cube_info->colors,exception) == MagickFalse)
    ThrowBinaryException(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_method != NoDitherMethod)
    (void) DitherImage(image,cube_info,exception);
  else
    {
      CacheView
        *image_view;

      MagickBooleanType
        status;

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

        register Quantum
          *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 == (Quantum *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        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++)
          {
            PixelInfo
              packet;

            GetPixelInfoPixel(image,q+count*GetPixelChannels(image),&packet);
            if (IsPixelEquivalent(image,q,&packet) == MagickFalse)
              break;
          }
          AssociateAlphaPixel(image,&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=(double) (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(image,(Quantum) index,q);
            if (cube.quantize_info->measure_error == MagickFalse)
              {
                SetPixelRed(image,ClampToQuantum(
                  image->colormap[index].red),q);
                SetPixelGreen(image,ClampToQuantum(
                  image->colormap[index].green),q);
                SetPixelBlue(image,ClampToQuantum(
                  image->colormap[index].blue),q);
                if (cube.associate_alpha != MagickFalse)
                  SetPixelAlpha(image,ClampToQuantum(
                    image->colormap[index].alpha),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 critical (MagickCore_AssignImageColors)
#endif
            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,exception);
  if ((cube_info->quantize_info->number_colors == 2) &&
      (cube_info->quantize_info->colorspace == GRAYColorspace))
    {
      double
        intensity;

      /*
        Monochrome image.
      */
      intensity=0.0;
      if ((image->colors > 1) &&
          (GetPixelInfoLuma(image->colormap+0) >
           GetPixelInfoLuma(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,exception);
  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
      (cube_info->quantize_info->colorspace != CMYKColorspace))
    (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
  return(MagickTrue);
}

Project: ImageMagick
File: quantize.c

MagickExport QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
{
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(quantize_info != (QuantizeInfo *) NULL);
  assert(quantize_info->signature == MagickCoreSignature);
  quantize_info->signature=(~MagickCoreSignature);
  quantize_info=(QuantizeInfo *) RelinquishMagickMemory(quantize_info);
  return(quantize_info);
}

Project: ImageMagick
File: quantize.c

static DoublePixelPacket **AcquirePixelThreadSet(const size_t count)
{
  DoublePixelPacket
    **pixels;

  register ssize_t
    i;

  size_t
    number_threads;

  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
  pixels=(DoublePixelPacket **) AcquireQuantumMemory(number_threads,
    sizeof(*pixels));
  if (pixels == (DoublePixelPacket **) NULL)
    return((DoublePixelPacket **) NULL);
  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
  for (i=0; i < (ssize_t) number_threads; i++)
  {
    pixels[i]=(DoublePixelPacket *) AcquireQuantumMemory(count,2*
      sizeof(**pixels));
    if (pixels[i] == (DoublePixelPacket *) NULL)
      return(DestroyPixelThreadSet(pixels));
  }
  return(pixels);
}

Project: ImageMagick
File: quantize.c

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

  associate_alpha=image->alpha_trait == BlendPixelTrait ? MagickTrue :
    MagickFalse;
  if ((cube_info->quantize_info->number_colors == 2) &&
      (cube_info->quantize_info->colorspace == GRAYColorspace))
    associate_alpha=MagickFalse;
  cube_info->associate_alpha=associate_alpha;
}

Project: ImageMagick
File: quantize.c

static void PruneChild(CubeInfo *cube_info,const NodeInfo *node_info)
{
  NodeInfo
    *parent;

  register ssize_t
    i;

  size_t
    number_children;

  /*
    Traverse any children.
  */
  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
  for (i=0; i < (ssize_t) number_children; i++)
    if (node_info->child[i] != (NodeInfo *) NULL)
      PruneChild(cube_info,node_info->child[i]);
  /*
    Merge color statistics into parent.
  */
  parent=node_info->parent;
  parent->number_unique+=node_info->number_unique;
  parent->total_color.red+=node_info->total_color.red;
  parent->total_color.green+=node_info->total_color.green;
  parent->total_color.blue+=node_info->total_color.blue;
  parent->total_color.alpha+=node_info->total_color.alpha;
  parent->child[node_info->id]=(NodeInfo *) NULL;
  cube_info->nodes--;
}

Project: ImageMagick
File: quantize.c

static inline size_t ColorToNodeId(const CubeInfo *cube_info,
  const DoublePixelPacket *pixel,size_t index)
{
  size_t
    id;

  id=(size_t) (((ScaleQuantumToChar(ClampPixel(pixel->red)) >> index) & 0x01) |
    ((ScaleQuantumToChar(ClampPixel(pixel->green)) >> index) & 0x01) << 1 |
    ((ScaleQuantumToChar(ClampPixel(pixel->blue)) >> index) & 0x01) << 2);
  if (cube_info->associate_alpha != MagickFalse)
    id|=((ScaleQuantumToChar(ClampPixel(pixel->alpha)) >> index) & 0x1) << 3;
  return(id);
}

Project: ImageMagick
File: quantize.c

MagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
  Image *image,const Image *remap_image,ExceptionInfo *exception)
{
  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);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
    quantize_info->number_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,remap_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,exception);
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick
File: quantize.c

static MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
  CubeInfo *cube_info,const unsigned int direction,ExceptionInfo *exception)
{
#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))
    {
      register Quantum
        *magick_restrict q;

      register ssize_t
        i;

      /*
        Distribute error.
      */
      q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
      if (q == (Quantum *) NULL)
        return(MagickFalse);
      AssociateAlphaPixel(image,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.alpha+=p->weights[i]*p->error[i].alpha;
      }
      pixel.red=(double) ClampPixel(pixel.red);
      pixel.green=(double) ClampPixel(pixel.green);
      pixel.blue=(double) ClampPixel(pixel.blue);
      if (cube_info->associate_alpha != MagickFalse)
        pixel.alpha=(double) ClampPixel(pixel.alpha);
      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=(double) (4.0*(QuantumRange+1.0)*((double)
            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) p->cache[i];
      if (image->storage_class == PseudoClass)
        SetPixelIndex(image,(Quantum) index,q);
      if (cube_info->quantize_info->measure_error == MagickFalse)
        {
          SetPixelRed(image,ClampToQuantum(image->colormap[index].red),q);
          SetPixelGreen(image,ClampToQuantum(image->colormap[index].green),q);
          SetPixelBlue(image,ClampToQuantum(image->colormap[index].blue),q);
          if (cube_info->associate_alpha != MagickFalse)
            SetPixelAlpha(image,ClampToQuantum(image->colormap[index].alpha),q);
        }
      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
        return(MagickFalse);
      /*
        Propagate the error as the last entry of the error queue.
      */
      (void) CopyMagickMemory(p->error,p->error+1,(ErrorQueueLength-1)*
        sizeof(p->error[0]));
      AssociateAlphaPixelInfo(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].alpha=pixel.alpha-color.alpha;
      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: ImageMagick
File: palm.c

static Image *ReadPALMImage(const ImageInfo *image_info,
  ExceptionInfo *exception)
{
  Image
    *image;

  MagickBooleanType
    status;

  MagickOffsetType
    totalOffset,
    seekNextDepth;

  PixelInfo
    transpix;

  Quantum
    index;

  register ssize_t
    i,
    x;

  register Quantum
    *q;

  size_t
    bytes_per_row,
    flags,
    bits_per_pixel,
    version,
    nextDepthOffset,
    transparentIndex,
    compressionType,
    byte,
    mask,
    redbits,
    greenbits,
    bluebits,
    one,
    pad,
    size,
    bit;

  ssize_t
    count,
    y;

  unsigned char
    *last_row,
    *one_row,
    *ptr;

  unsigned short
    color16;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      (void) DestroyImageList(image);
      return((Image *) NULL);
    }
  totalOffset=0;
  do
  {
    image->columns=ReadBlobMSBShort(image);
    image->rows=ReadBlobMSBShort(image);
    if (EOFBlob(image) != MagickFalse)
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    if ((image->columns == 0) || (image->rows == 0))
      ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      return(DestroyImageList(image));
    bytes_per_row=ReadBlobMSBShort(image);
    flags=ReadBlobMSBShort(image);
    bits_per_pixel=(size_t) ReadBlobByte(image);
    if ((bits_per_pixel != 1) && (bits_per_pixel != 2) &&
        (bits_per_pixel != 4) && (bits_per_pixel != 8) &&
        (bits_per_pixel != 16))
      ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
    version=(size_t) ReadBlobByte(image);
    if ((version != 0) && (version != 1) && (version != 2))
      ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");
    nextDepthOffset=(size_t) ReadBlobMSBShort(image);
    transparentIndex=(size_t) ReadBlobByte(image);
    compressionType=(size_t) ReadBlobByte(image);
    if ((compressionType != PALM_COMPRESSION_NONE) &&
        (compressionType != PALM_COMPRESSION_SCANLINE ) &&
        (compressionType != PALM_COMPRESSION_RLE))
      ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
    pad=ReadBlobMSBShort(image);
    (void) pad;
    /*
      Initialize image colormap.
    */
    one=1;
    if ((bits_per_pixel < 16) &&
        (AcquireImageColormap(image,one << bits_per_pixel,exception) == MagickFalse))
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    GetPixelInfo(image,&transpix);
    if (bits_per_pixel == 16)  /* Direct Color */
      {
        redbits=(size_t) ReadBlobByte(image);  /* # of bits of red */
        (void) redbits;
        greenbits=(size_t) ReadBlobByte(image);  /* # of bits of green */
        (void) greenbits;
        bluebits=(size_t) ReadBlobByte(image);  /* # of bits of blue */
        (void) bluebits;
        ReadBlobByte(image);  /* reserved by Palm */
        ReadBlobByte(image);  /* reserved by Palm */
        transpix.red=(double) (QuantumRange*ReadBlobByte(image)/31);
        transpix.green=(double) (QuantumRange*ReadBlobByte(image)/63);
        transpix.blue=(double) (QuantumRange*ReadBlobByte(image)/31);
      }
    if (bits_per_pixel == 8)
      {
        ssize_t
          index;

        if (flags & PALM_HAS_COLORMAP_FLAG)
          {
            count=(ssize_t) ReadBlobMSBShort(image);
            for (i=0; i < (ssize_t) count; i++)
            {
              ReadBlobByte(image);
              index=ConstrainColormapIndex(image,255-i,exception);
              image->colormap[index].red=(MagickRealType)
                ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
              image->colormap[index].green=(MagickRealType)
                ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
              image->colormap[index].blue=(MagickRealType)
                ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
          }
        }
      else
        for (i=0; i < (ssize_t) (1L << bits_per_pixel); i++)
        {
          index=ConstrainColormapIndex(image,255-i,exception);
          image->colormap[index].red=(MagickRealType)
            ScaleCharToQuantum(PalmPalette[i][0]);
          image->colormap[index].green=(MagickRealType)
            ScaleCharToQuantum(PalmPalette[i][1]);
          image->colormap[index].blue=(MagickRealType)
            ScaleCharToQuantum(PalmPalette[i][2]);
        }
      }
    if (flags & PALM_IS_COMPRESSED_FLAG)
      size=ReadBlobMSBShort(image);
    (void) size;
    image->storage_class=DirectClass;
    if (bits_per_pixel < 16)
      {
        image->storage_class=PseudoClass;
        image->depth=8;
      }
    if (image_info->ping != MagickFalse)
      {
        (void) CloseBlob(image);
        return(image);
      }
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      return(DestroyImageList(image));
    one_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
      2*image->columns),sizeof(*one_row));
    if (one_row == (unsigned char *) NULL)
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    last_row=(unsigned char *) NULL;
    if (compressionType == PALM_COMPRESSION_SCANLINE)
      {
        last_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
          2*image->columns),sizeof(*last_row));
        if (last_row == (unsigned char *) NULL)
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
      }
    mask=(size_t) (1U << bits_per_pixel)-1;
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      if ((flags & PALM_IS_COMPRESSED_FLAG) == 0)
        {
          /* TODO move out of loop! */
          image->compression=NoCompression;
          count=ReadBlob(image,bytes_per_row,one_row);
          if (count != (ssize_t) bytes_per_row)
            break;
        }
      else
        {
          if (compressionType == PALM_COMPRESSION_RLE)
            { 
              /* TODO move out of loop! */
              image->compression=RLECompression;
              for (i=0; i < (ssize_t) bytes_per_row; )
              {
                count=(ssize_t) ReadBlobByte(image);
                if (count < 0)
                  break;
                count=MagickMin(count,(ssize_t) bytes_per_row-i);
                byte=(size_t) ReadBlobByte(image);
                (void) ResetMagickMemory(one_row+i,(int) byte,(size_t) count);
                i+=count;
              }
          }
        else
          if (compressionType == PALM_COMPRESSION_SCANLINE)
            {
              size_t
                one;

              /* TODO move out of loop! */
              one=1;
              image->compression=FaxCompression;
              for (i=0; i < (ssize_t) bytes_per_row; i+=8)
              {
                count=(ssize_t) ReadBlobByte(image);
                if (count < 0)
                  break;
                byte=(size_t) MagickMin((ssize_t) bytes_per_row-i,8);
                for (bit=0; bit < byte; bit++)
                {
                  if ((y == 0) || (count & (one << (7 - bit))))
                    one_row[i+bit]=(unsigned char) ReadBlobByte(image);
                  else
                    one_row[i+bit]=last_row[i+bit];
                }
              }
              (void) CopyMagickMemory(last_row, one_row, bytes_per_row);
            }
        }
      ptr=one_row;
      q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
      if (q == (Quantum *) NULL)
        break;
      if (bits_per_pixel == 16)
        {
          if (image->columns > (2*bytes_per_row))
            {
              one_row=(unsigned char *) RelinquishMagickMemory(one_row);
              if (compressionType == PALM_COMPRESSION_SCANLINE)
                last_row=(unsigned char *) RelinquishMagickMemory(last_row);
              ThrowReaderException(CorruptImageError,"CorruptImage");
            }
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            color16=(*ptr++ << 8);
            color16|=(*ptr++);
            SetPixelRed(image,(Quantum) ((QuantumRange*((color16 >> 11) &
              0x1f))/0x1f),q);
            SetPixelGreen(image,(Quantum) ((QuantumRange*((color16 >> 5) &
              0x3f))/0x3f),q);
            SetPixelBlue(image,(Quantum) ((QuantumRange*((color16 >> 0) &
              0x1f))/0x1f),q);
            SetPixelAlpha(image,OpaqueAlpha,q);
            q+=GetPixelChannels(image);
          }
        }
      else
        {
          bit=8-bits_per_pixel;
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            if ((size_t) (ptr-one_row) >= bytes_per_row)
              {
                one_row=(unsigned char *) RelinquishMagickMemory(one_row);
                if (compressionType == PALM_COMPRESSION_SCANLINE)
                  last_row=(unsigned char *) RelinquishMagickMemory(last_row);
                ThrowReaderException(CorruptImageError,"CorruptImage");
              }
            index=(Quantum) (mask-(((*ptr) & (mask << bit)) >> bit));
            SetPixelIndex(image,index,q);
            SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
            if (bit)
              bit-=bits_per_pixel;
            else
              {
                ptr++;
                bit=8-bits_per_pixel;
              }
            q+=GetPixelChannels(image);
          }
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
            break;
        }
        if (image->previous == (Image *) NULL)
          {
            status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
              image->rows);
            if (status == MagickFalse)
              break;
          }
      }
    if (flags & PALM_HAS_TRANSPARENCY_FLAG)
      {
        ssize_t index=ConstrainColormapIndex(image,(ssize_t) (mask-
          transparentIndex),exception);
        if (bits_per_pixel != 16)
          transpix=image->colormap[index];
        (void) TransparentPaintImage(image,&transpix,(Quantum) TransparentAlpha,
          MagickFalse,exception);
      }
    one_row=(unsigned char *) RelinquishMagickMemory(one_row);
    if (compressionType == PALM_COMPRESSION_SCANLINE)
      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
    /*
      Proceed to next image. Copied from coders/pnm.c
    */
    if (image_info->number_scenes != 0)
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
    if (nextDepthOffset != 0)
      { 
        /*
          Skip to next image. 
        */
        totalOffset+=(MagickOffsetType) (nextDepthOffset*4);
        if (totalOffset >= (MagickOffsetType) GetBlobSize(image))
          ThrowReaderException(CorruptImageError,"ImproperImageHeader")
        else
          seekNextDepth=SeekBlob(image,totalOffset,SEEK_SET);
        if (seekNextDepth != totalOffset)
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
        /*
          Allocate next image structure. Copied from coders/pnm.c
        */
        AcquireNextImage(image_info,image,exception);
        if (GetNextImageInList(image) == (Image *) NULL)
          {
            (void) DestroyImageList(image);
            return((Image *) NULL);
          }
        image=SyncNextImageInList(image);
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
          GetBlobSize(image));
        if (status == MagickFalse)
          break;
      }
  } while (nextDepthOffset != 0);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}

Project: ImageMagick
File: quantize.c

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

  double
    alpha,
    area,
    beta,
    distance,
    maximum_error,
    mean_error,
    mean_error_per_pixel;

  size_t
    index;

  ssize_t
    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,exception);
  (void) ResetMagickMemory(&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;
  image_view=AcquireVirtualCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const Quantum
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const Quantum *) NULL)
      break;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      index=GetPixelIndex(image,p);
      if (image->alpha_trait == BlendPixelTrait)
        {
          alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
          beta=(double) (QuantumScale*image->colormap[index].alpha);
        }
      distance=fabs((double) (alpha*GetPixelRed(image,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(image,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(image,p)-beta*
        image->colormap[index].blue));
      mean_error_per_pixel+=distance;
      mean_error+=distance*distance;
      if (distance > maximum_error)
        maximum_error=distance;
      p+=GetPixelChannels(image);
    }
  }
  image_view=DestroyCacheView(image_view);
  image->error.mean_error_per_pixel=(double) mean_error_per_pixel/area;
  image->error.normalized_mean_error=(double) QuantumScale*QuantumScale*
    mean_error/area;
  image->error.normalized_maximum_error=(double) QuantumScale*maximum_error;
  return(MagickTrue);
}

Project: ImageMagick
File: quantize.c

static size_t QuantizeErrorFlatten(const CubeInfo *cube_info,
  const NodeInfo *node_info,const ssize_t offset,double *quantize_error)
{
  register ssize_t
    i;

  size_t
    n,
    number_children;

  if (offset >= (ssize_t) cube_info->nodes)
    return(0);
  quantize_error[offset]=node_info->quantize_error;
  n=1;
  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
  for (i=0; i < (ssize_t) number_children ; i++)
    if (node_info->child[i] != (NodeInfo *) NULL)
      n+=QuantizeErrorFlatten(cube_info,node_info->child[i],offset+n,
        quantize_error);
  return(n);
}

Project: ImageMagick
File: quantize.c

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

  CacheView
    *image_view;

  DoublePixelPacket
    **pixels;

  MagickBooleanType
    status;

  ssize_t
    y;

  /*
    Distribute quantization error using Floyd-Steinberg.
  */
  pixels=AcquirePixelThreadSet(image->columns);
  if (pixels == (DoublePixelPacket **) NULL)
    return(MagickFalse);
  status=MagickTrue;
  image_view=AcquireAuthenticCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    const int
      id = GetOpenMPThreadId();

    CubeInfo
      cube;

    DoublePixelPacket
      *current,
      *previous;

    register Quantum
      *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 == (Quantum *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    cube=(*cube_info);
    current=pixels[id]+(y & 0x01)*image->columns;
    previous=pixels[id]+((y+1) & 0x01)*image->columns;
    v=(ssize_t) ((y & 0x01) != 0 ? -1 : 1);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      DoublePixelPacket
        color,
        pixel;

      register ssize_t
        i;

      ssize_t
        u;

      u=(y & 0x01) != 0 ? (ssize_t) image->columns-1-x : x;
      AssociateAlphaPixel(image,&cube,q+u*GetPixelChannels(image),&pixel);
      if (x > 0)
        {
          pixel.red+=7*current[u-v].red/16;
          pixel.green+=7*current[u-v].green/16;
          pixel.blue+=7*current[u-v].blue/16;
          if (cube.associate_alpha != MagickFalse)
            pixel.alpha+=7*current[u-v].alpha/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.alpha+=previous[u+v].alpha/16;
            }
          pixel.red+=5*previous[u].red/16;
          pixel.green+=5*previous[u].green/16;
          pixel.blue+=5*previous[u].blue/16;
          if (cube.associate_alpha != MagickFalse)
            pixel.alpha+=5*previous[u].alpha/16;
          if (x > 0)
            {
              pixel.red+=3*previous[u-v].red/16;
              pixel.green+=3*previous[u-v].green/16;
              pixel.blue+=3*previous[u-v].blue/16;
              if (cube.associate_alpha != MagickFalse)
                pixel.alpha+=3*previous[u-v].alpha/16;
            }
        }
      pixel.red=(double) ClampPixel(pixel.red);
      pixel.green=(double) ClampPixel(pixel.green);
      pixel.blue=(double) ClampPixel(pixel.blue);
      if (cube.associate_alpha != MagickFalse)
        pixel.alpha=(double) ClampPixel(pixel.alpha);
      i=CacheOffset(&cube,&pixel);
      if (cube.cache[i] < 0)
        {
          register NodeInfo
            *node_info;

          register size_t
            node_id;

          /*
            Identify the deepest node containing the pixel's color.
          */
          node_info=cube.root;
          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
          {
            node_id=ColorToNodeId(&cube,&pixel,index);
            if (node_info->child[node_id] == (NodeInfo *) NULL)
              break;
            node_info=node_info->child[node_id];
          }
          /*
            Find closest color among siblings and their children.
          */
          cube.target=pixel;
          cube.distance=(double) (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(image,(Quantum) index,q+u*GetPixelChannels(image));
      if (cube.quantize_info->measure_error == MagickFalse)
        {
          SetPixelRed(image,ClampToQuantum(image->colormap[index].red),
            q+u*GetPixelChannels(image));
          SetPixelGreen(image,ClampToQuantum(image->colormap[index].green),
            q+u*GetPixelChannels(image));
          SetPixelBlue(image,ClampToQuantum(image->colormap[index].blue),
            q+u*GetPixelChannels(image));
          if (cube.associate_alpha != MagickFalse)
            SetPixelAlpha(image,ClampToQuantum(image->colormap[index].alpha),
              q+u*GetPixelChannels(image));
        }
      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
        status=MagickFalse;
      /*
        Store the error.
      */
      AssociateAlphaPixelInfo(&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].alpha=pixel.alpha-color.alpha;
      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: ImageMagick
File: quantize.c

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

Project: ImageMagick
File: quantize.c

MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
  const DitherMethod dither_method,ExceptionInfo *exception)
{
#define PosterizeImageTag  "Posterize/Image"
#define PosterizePixel(pixel) (Quantum) (QuantumRange*(MagickRound( \
  QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))

  CacheView
    *image_view;

  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);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  if (image->storage_class == PseudoClass)
#if defined(MAGICKCORE_OPENMP_SUPPORT)
    #pragma omp parallel for schedule(static,4) shared(progress,status) \
      magick_threads(image,image,1,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);
      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
        image->colormap[i].green=(double)
          PosterizePixel(image->colormap[i].green);
      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
        image->colormap[i].blue=(double)
          PosterizePixel(image->colormap[i].blue);
      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
        image->colormap[i].alpha=(double)
          PosterizePixel(image->colormap[i].alpha);
    }
  /*
    Posterize image.
  */
  status=MagickTrue;
  progress=0;
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static,4) shared(progress,status) \
    magick_threads(image,image,image->rows,1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register Quantum
      *magick_restrict q;

    register 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++)
    {
      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
        SetPixelRed(image,PosterizePixel(GetPixelRed(image,q)),q);
      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
        SetPixelGreen(image,PosterizePixel(GetPixelGreen(image,q)),q);
      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
        SetPixelBlue(image,PosterizePixel(GetPixelBlue(image,q)),q);
      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
          (image->colorspace == CMYKColorspace))
        SetPixelBlack(image,PosterizePixel(GetPixelBlack(image,q)),q);
      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
          (image->alpha_trait == BlendPixelTrait))
        SetPixelAlpha(image,PosterizePixel(GetPixelAlpha(image,q)),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 critical (MagickCore_PosterizeImage)
#endif
        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_method=dither_method;
  quantize_info->tree_depth=MaxTreeDepth;
  status=QuantizeImage(quantize_info,image,exception);
  quantize_info=DestroyQuantizeInfo(quantize_info);
  return(status);
}

Project: ImageMagick
File: quantize.c

static inline void AssociateAlphaPixelInfo(const CubeInfo *cube_info,
  const PixelInfo *pixel,DoublePixelPacket *alpha_pixel)
{
  double
    alpha;

  if ((cube_info->associate_alpha == MagickFalse) ||
      (pixel->alpha == OpaqueAlpha))
    {
      alpha_pixel->red=(double) pixel->red;
      alpha_pixel->green=(double) pixel->green;
      alpha_pixel->blue=(double) pixel->blue;
      alpha_pixel->alpha=(double) pixel->alpha;
      return;
    }
  alpha=(double) (QuantumScale*pixel->alpha);
  alpha_pixel->red=alpha*pixel->red;
  alpha_pixel->green=alpha*pixel->green;
  alpha_pixel->blue=alpha*pixel->blue;
  alpha_pixel->alpha=(double) pixel->alpha;
}

Project: ImageMagick
File: quantize.c

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

  MagickBooleanType
    status;

  PixelInfo
    *colormap;

  register ssize_t
    i;

  ssize_t
    *colormap_index,
    j,
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->type != GrayscaleType)
    (void) TransformImageColorspace(image,GRAYColorspace,exception);
  colormap_index=(ssize_t *) AcquireQuantumMemory(MaxColormapSize,
    sizeof(*colormap_index));
  if (colormap_index == (ssize_t *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  if (image->storage_class != PseudoClass)
    {
      (void) ResetMagickMemory(colormap_index,(-1),MaxColormapSize*
        sizeof(*colormap_index));
      if (AcquireImageColormap(image,MaxColormapSize,exception) == 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,4) shared(status) \
        magick_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register Quantum
          *magick_restrict q;

        register 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++)
        {
          register size_t
            intensity;

          intensity=ScaleQuantumToMap(GetPixelRed(image,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=(double)
                    GetPixelRed(image,q);
                  image->colormap[image->colors].green=(double)
                    GetPixelGreen(image,q);
                  image->colormap[image->colors].blue=(double)
                    GetPixelBlue(image,q);
                  image->colors++;
               }
            }
          SetPixelIndex(image,(Quantum) colormap_index[intensity],q);
          q+=GetPixelChannels(image);
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
    }
  for (i=0; i < (ssize_t) image->colors; i++)
    image->colormap[i].alpha=(double) i;
  qsort((void *) image->colormap,image->colors,sizeof(PixelInfo),
    IntensityCompare);
  colormap=(PixelInfo *) AcquireQuantumMemory(image->colors,sizeof(*colormap));
  if (colormap == (PixelInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  j=0;
  colormap[j]=image->colormap[0];
  for (i=0; i < (ssize_t) image->colors; i++)
  {
    if (IsPixelInfoEquivalent(&colormap[j],&image->colormap[i]) == MagickFalse)
      {
        j++;
        colormap[j]=image->colormap[i];
      }
    colormap_index[(ssize_t) image->colormap[i].alpha]=j;
  }
  image->colors=(size_t) (j+1);
  image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
  image->colormap=colormap;
  status=MagickTrue;
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static,4) shared(status) \
    magick_threads(image,image,image->rows,1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register Quantum
      *magick_restrict q;

    register 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++)
    {
      SetPixelIndex(image,(Quantum) colormap_index[ScaleQuantumToMap(
        GetPixelIndex(image,q))],q);
      q+=GetPixelChannels(image);
    }
    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,exception) != MagickFalse)
    image->type=BilevelType;
  return(status);
}

Project: ImageMagick
File: quantize.c

static void Riemersma(Image *image,CacheView *image_view,CubeInfo *cube_info,
  const size_t level,const unsigned int direction,ExceptionInfo *exception)
{
  if (level == 1)
    switch (direction)
    {
      case WestGravity:
      {
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        break;
      }
      case EastGravity:
      {
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        break;
      }
      case NorthGravity:
      {
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        break;
      }
      case SouthGravity:
      {
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        break;
      }
      default:
        break;
    }
  else
    switch (direction)
    {
      case WestGravity:
      {
        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,WestGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,WestGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
          exception);
        break;
      }
      case EastGravity:
      {
        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,EastGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,EastGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
          exception);
        break;
      }
      case NorthGravity:
      {
        Riemersma(image,image_view,cube_info,level-1,WestGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,EastGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,NorthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,EastGravity,
          exception);
        break;
      }
      case SouthGravity:
      {
        Riemersma(image,image_view,cube_info,level-1,EastGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,WestGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,SouthGravity,
          exception);
        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity,
          exception);
        Riemersma(image,image_view,cube_info,level-1,WestGravity,
          exception);
        break;
      }
      default:
        break;
    }
}

Project: ImageMagick
File: quantize.c

static void ClosestColor(const Image *image,CubeInfo *cube_info,
  const NodeInfo *node_info)
{
  register ssize_t
    i;

  size_t
    number_children;

  /*
    Traverse any children.
  */
  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
  for (i=0; i < (ssize_t) number_children; i++)
    if (node_info->child[i] != (NodeInfo *) NULL)
      ClosestColor(image,cube_info,node_info->child[i]);
  if (node_info->number_unique != 0)
    {
      double
        pixel;

      register double
        alpha,
        beta,
        distance;

      register DoublePixelPacket
        *magick_restrict q;

      register PixelInfo
        *magick_restrict p;

      /*
        Determine if this color is "closest".
      */
      p=image->colormap+node_info->color_number;
      q=(&cube_info->target);
      alpha=1.0;
      beta=1.0;
      if (cube_info->associate_alpha != MagickFalse)
        {
          alpha=(double) (QuantumScale*p->alpha);
          beta=(double) (QuantumScale*q->alpha);
        }
      pixel=alpha*p->red-beta*q->red;
      distance=pixel*pixel;
      if (distance <= cube_info->distance)
        {
          pixel=alpha*p->green-beta*q->green;
          distance+=pixel*pixel;
          if (distance <= cube_info->distance)
            {
              pixel=alpha*p->blue-beta*q->blue;
              distance+=pixel*pixel;
              if (distance <= cube_info->distance)
                {
                  if (cube_info->associate_alpha != MagickFalse)
                    {
                      pixel=p->alpha-q->alpha;
                      distance+=pixel*pixel;
                    }
                  if (distance <= cube_info->distance)
                    {
                      cube_info->distance=distance;
                      cube_info->color_number=node_info->color_number;
                    }
                }
            }
        }
    }
}

Project: ImageMagick
File: quantize.c

static int QuantizeErrorCompare(const void *error_p,const void *error_q)
{
  double
    *p,
    *q;

  p=(double *) error_p;
  q=(double *) error_q;
  if (*p > *q)
    return(1);
  if (fabs(*q-*p) <= MagickEpsilon)
    return(0);
  return(-1);
}

Project: ImageMagick
File: quantize.c

MagickExport QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
{
  QuantizeInfo
    *quantize_info;

  quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
  if (quantize_info == (QuantizeInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  GetQuantizeInfo(quantize_info);
  if (image_info != (ImageInfo *) NULL)
    {
      const char
        *option;

      quantize_info->dither_method=image_info->dither == MagickFalse ?
        NoDitherMethod : RiemersmaDitherMethod;
      option=GetImageOption(image_info,"dither");
      if (option != (const char *) NULL)
        quantize_info->dither_method=(DitherMethod) ParseCommandOption(
          MagickDitherOptions,MagickFalse,option);
      quantize_info->measure_error=image_info->verbose;
    }
  return(quantize_info);
}

Project: ImageMagick
File: quantize.c

MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
  Image *image,ExceptionInfo *exception)
{
  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);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  maximum_colors=quantize_info->number_colors;
  if (maximum_colors == 0)
    maximum_colors=MaxColormapSize;
  if (maximum_colors > MaxColormapSize)
    maximum_colors=MaxColormapSize;
  if (image->alpha_trait != BlendPixelTrait)
    {
      if (SetImageGray(image,exception) != MagickFalse)
        (void) SetGrayscaleImage(image,exception);
    }
  if ((image->storage_class == PseudoClass) &&
      (image->colors <= maximum_colors))
    {
      if ((quantize_info->colorspace != UndefinedColorspace) &&
          (quantize_info->colorspace != CMYKColorspace))
        (void) TransformImageColorspace(image,quantize_info->colorspace,
          exception);
      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_method != NoDitherMethod) && (depth > 2))
        depth--;
      if ((image->alpha_trait == BlendPixelTrait) && (depth > 5))
        depth--;
      if (SetImageGray(image,exception) != MagickFalse)
        depth=MaxTreeDepth;
    }
  /*
    Initialize color cube.
  */
  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,image,exception);
  if (status != MagickFalse)
    {
      /*
        Reduce the number of colors in the image if it contains more than the
        maximum, otherwise we can disable dithering to improve the performance.
      */
      if (cube_info->colors > cube_info->maximum_colors)
        ReduceImageColors(image,cube_info);
      else
        cube_info->quantize_info->dither_method=NoDitherMethod;
      status=AssignImageColors(image,cube_info,exception);
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick
File: palm.c

static ssize_t FindColor(PixelInfo *packet)
{
  register ssize_t
    i;

  for (i=0; i < 256; i++)
    if (ScaleQuantumToChar(ClampToQuantum(packet->red)) == PalmPalette[i][0] &&
        ScaleQuantumToChar(ClampToQuantum(packet->green)) == PalmPalette[i][1] &&
        ScaleQuantumToChar(ClampToQuantum(packet->blue)) == PalmPalette[i][2])
      return(i);
  return(-1);
}

Project: ImageMagick
File: quantize.c

MagickExport QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
{
  QuantizeInfo
    *clone_info;

  clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
  if (clone_info == (QuantizeInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  GetQuantizeInfo(clone_info);
  if (quantize_info == (QuantizeInfo *) NULL)
    return(clone_info);
  clone_info->number_colors=quantize_info->number_colors;
  clone_info->tree_depth=quantize_info->tree_depth;
  clone_info->dither_method=quantize_info->dither_method;
  clone_info->colorspace=quantize_info->colorspace;
  clone_info->measure_error=quantize_info->measure_error;
  return(clone_info);
}

Project: ImageMagick
File: quantize.c

MagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
  Image *images,ExceptionInfo *exception)
{
  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);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  if (GetNextImageInList(images) == (Image *) NULL)
    {
      /*
        Handle a single image with QuantizeImage.
      */
      status=QuantizeImage(quantize_info,images,exception);
      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_method != NoDitherMethod)
        depth--;
    }
  /*
    Initialize color cube.
  */
  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
  if (cube_info == (CubeInfo *) NULL)
    {
      (void) ThrowMagickException(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,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,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);
      }
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick
File: quantize.c

static inline void AssociateAlphaPixel(const Image *image,
  const CubeInfo *cube_info,const Quantum *pixel,DoublePixelPacket *alpha_pixel)
{
  double
    alpha;

  if ((cube_info->associate_alpha == MagickFalse) ||
      (GetPixelAlpha(image,pixel) == OpaqueAlpha))
    {
      alpha_pixel->red=(double) GetPixelRed(image,pixel);
      alpha_pixel->green=(double) GetPixelGreen(image,pixel);
      alpha_pixel->blue=(double) GetPixelBlue(image,pixel);
      alpha_pixel->alpha=(double) GetPixelAlpha(image,pixel);
      return;
    }
  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixel));
  alpha_pixel->red=alpha*GetPixelRed(image,pixel);
  alpha_pixel->green=alpha*GetPixelGreen(image,pixel);
  alpha_pixel->blue=alpha*GetPixelBlue(image,pixel);
  alpha_pixel->alpha=(double) GetPixelAlpha(image,pixel);
}

Project: ImageMagick
File: quantize.c

static size_t DefineImageColormap(Image *image,CubeInfo *cube_info,
  NodeInfo *node_info)
{
  register ssize_t
    i;

  size_t
    number_children;

  /*
    Traverse any children.
  */
  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
  for (i=0; i < (ssize_t) number_children; i++)
    if (node_info->child[i] != (NodeInfo *) NULL)
      (void) DefineImageColormap(image,cube_info,node_info->child[i]);
  if (node_info->number_unique != 0)
    {
      register double
        alpha;

      register PixelInfo
        *magick_restrict q;

      /*
        Colormap entry is defined by the mean color in this cube.
      */
      q=image->colormap+image->colors;
      alpha=(double) ((MagickOffsetType) node_info->number_unique);
      alpha=PerceptibleReciprocal(alpha);
      if (cube_info->associate_alpha == MagickFalse)
        {
          q->red=(double) ClampToQuantum(alpha*QuantumRange*
            node_info->total_color.red);
          q->green=(double) ClampToQuantum(alpha*QuantumRange*
            node_info->total_color.green);
          q->blue=(double) ClampToQuantum(alpha*QuantumRange*
            node_info->total_color.blue);
          q->alpha=(double) OpaqueAlpha;
        }
      else
        {
          double
            opacity;

          opacity=(double) (alpha*QuantumRange*node_info->total_color.alpha);
          q->alpha=(double) ClampToQuantum(opacity);
          if (q->alpha == OpaqueAlpha)
            {
              q->red=(double) ClampToQuantum(alpha*QuantumRange*
                node_info->total_color.red);
              q->green=(double) ClampToQuantum(alpha*QuantumRange*
                node_info->total_color.green);
              q->blue=(double) ClampToQuantum(alpha*QuantumRange*
                node_info->total_color.blue);
            }
          else
            {
              double
                gamma;

              gamma=(double) (QuantumScale*q->alpha);
              gamma=PerceptibleReciprocal(gamma);
              q->red=(double) ClampToQuantum(alpha*gamma*QuantumRange*
                node_info->total_color.red);
              q->green=(double) ClampToQuantum(alpha*gamma*QuantumRange*
                node_info->total_color.green);
              q->blue=(double) ClampToQuantum(alpha*gamma*QuantumRange*
                node_info->total_color.blue);
              if (node_info->number_unique > cube_info->transparent_pixels)
                {
                  cube_info->transparent_pixels=node_info->number_unique;
                  cube_info->transparent_index=(ssize_t) image->colors;
                }
            }
        }
      node_info->color_number=image->colors++;
    }
  return(image->colors);
}

Project: ImageMagick
File: palm.c

ModuleExport size_t RegisterPALMImage(void)
{
  MagickInfo
    *entry;

  entry=AcquireMagickInfo("PALM","PALM","Palm pixmap");
  entry->decoder=(DecodeImageHandler *) ReadPALMImage;
  entry->encoder=(EncodeImageHandler *) WritePALMImage;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  entry->flags|=CoderEncoderSeekableStreamFlag;
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}

Project: ImageMagick
File: quantize.c

static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info,
  ExceptionInfo *exception)
{
  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,exception));
  /*
    Distribute quantization error along a Hilbert curve.
  */
  (void) ResetMagickMemory(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,exception);
  if (depth > 1)
    Riemersma(image,image_view,cube_info,depth-1,NorthGravity,exception);
  status=RiemersmaDither(image,image_view,cube_info,ForgetGravity,exception);
  image_view=DestroyCacheView(image_view);
  return(status);
}

Project: ImageMagick
File: quantize.c

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

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

Project: ImageMagick
File: quantize.c

MagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
  Image *images,const Image *remap_image,ExceptionInfo *exception)
{
  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);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=images;
  if (remap_image == (Image *) NULL)
    {
      /*
        Create a global colormap for an image sequence.
      */
      status=QuantizeImages(quantize_info,images,exception);
      return(status);
    }
  /*
    Classify image colors from the reference image.
  */
  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
    quantize_info->number_colors);
  if (cube_info == (CubeInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  status=ClassifyImageColors(cube_info,remap_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,exception);
        if (status == MagickFalse)
          break;
      }
    }
  DestroyCubeInfo(cube_info);
  return(status);
}

Project: ImageMagick
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;

  double
    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,exception);
  else
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
      (void) TransformImageColorspace((Image *) image,sRGBColorspace,exception);
  midpoint.red=(double) QuantumRange/2.0;
  midpoint.green=(double) QuantumRange/2.0;
  midpoint.blue=(double) QuantumRange/2.0;
  midpoint.alpha=(double) QuantumRange/2.0;
  error.alpha=0.0;
  image_view=AcquireVirtualCacheView(image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const Quantum
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const Quantum *) 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++)
      {
        PixelInfo
          packet;

        GetPixelInfoPixel(image,p+count*GetPixelChannels(image),&packet);
        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
          break;
      }
      AssociateAlphaPixel(image,cube_info,p,&pixel);
      index=MaxTreeDepth-1;
      bisect=((double) 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.alpha+=(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.alpha=QuantumScale*(pixel.alpha-mid.alpha);
        distance=(double) (error.red*error.red+error.green*error.green+
          error.blue*error.blue+error.alpha*error.alpha);
        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.alpha+=count*QuantumScale*
          ClampPixel(pixel.alpha);
      else
        node_info->total_color.alpha+=count*QuantumScale*
          ClampPixel(OpaqueAlpha);
      p+=count*GetPixelChannels(image);
    }
    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 Quantum
      *magick_restrict p;

    register ssize_t
      x;

    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const Quantum *) 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++)
      {
        PixelInfo
          packet;

        GetPixelInfoPixel(image,p+count*GetPixelChannels(image),&packet);
        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
          break;
      }
      AssociateAlphaPixel(image,cube_info,p,&pixel);
      index=MaxTreeDepth-1;
      bisect=((double) 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.alpha+=(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.alpha=QuantumScale*(pixel.alpha-mid.alpha);
        distance=(double) (error.red*error.red+error.green*error.green+
          error.blue*error.blue+error.alpha*error.alpha);
        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.alpha+=count*QuantumScale*
          ClampPixel(pixel.alpha);
      else
        node_info->total_color.alpha+=count*QuantumScale*
          ClampPixel(OpaqueAlpha);
      p+=count*GetPixelChannels(image);
    }
    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,exception);
  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
}

Project: ImageMagick
File: palm.c

static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
  Image *image,ExceptionInfo *exception)
{
  MagickBooleanType
    status;

  MagickOffsetType
    currentOffset,
    offset,
    scene;

  MagickSizeType
    cc;

  PixelInfo
    transpix;

  QuantizeInfo
    *quantize_info;

  register ssize_t
    x;

  register const Quantum
    *p;

  register Quantum
    *q;

  ssize_t
    y;

  size_t
    count,
    bits_per_pixel,
    bytes_per_row,
    nextDepthOffset,
    one;

  unsigned char
    bit,
    byte,
    color,
    *last_row,
    *one_row,
    *ptr,
    version;

  unsigned int
    transparentIndex;

  unsigned short
    color16,
    flags;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  quantize_info=AcquireQuantizeInfo(image_info);
  flags=0;
  currentOffset=0;
  transparentIndex=0;
  transpix.red=0.0;
  transpix.green=0.0;
  transpix.blue=0.0;
  transpix.alpha=0.0;
  one=1;
  version=0;
  scene=0;
  do
  {
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
    count=GetNumberColors(image,NULL,exception);
    for (bits_per_pixel=1;  (one << bits_per_pixel) < count; bits_per_pixel*=2) ;
    if (bits_per_pixel > 16)
      bits_per_pixel=16;
    else
      if (bits_per_pixel < 16)
        (void) TransformImageColorspace(image,image->colorspace,exception);
    if (bits_per_pixel < 8)
      {
        (void) TransformImageColorspace(image,GRAYColorspace,exception);
        (void) SetImageType(image,PaletteType,exception);
        (void) SortColormapByIntensity(image,exception);
      }
    if ((image->storage_class == PseudoClass) && (image->colors > 256))
      (void) SetImageStorageClass(image,DirectClass,exception);
    if (image->storage_class == PseudoClass)
      flags|=PALM_HAS_COLORMAP_FLAG;
    else
      flags|=PALM_IS_DIRECT_COLOR;
    (void) WriteBlobMSBShort(image,(unsigned short) image->columns); /* width */
    (void) WriteBlobMSBShort(image,(unsigned short) image->rows);  /* height */
    bytes_per_row=((image->columns+(16/bits_per_pixel-1))/(16/
      bits_per_pixel))*2;
    (void) WriteBlobMSBShort(image,(unsigned short) bytes_per_row);
    if ((image_info->compression == RLECompression) ||
        (image_info->compression == FaxCompression))
      flags|=PALM_IS_COMPRESSED_FLAG;
    (void) WriteBlobMSBShort(image, flags);
    (void) WriteBlobByte(image,(unsigned char) bits_per_pixel);
    if (bits_per_pixel > 1)
      version=1;
    if ((image_info->compression == RLECompression) ||
        (image_info->compression == FaxCompression))
      version=2;
    (void) WriteBlobByte(image,version);
    (void) WriteBlobMSBShort(image,0);  /* nextDepthOffset */
    (void) WriteBlobByte(image,(unsigned char) transparentIndex);
    if (image_info->compression == RLECompression)
      (void) WriteBlobByte(image,PALM_COMPRESSION_RLE);
    else
      if (image_info->compression == FaxCompression)
        (void) WriteBlobByte(image,PALM_COMPRESSION_SCANLINE);
      else
        (void) WriteBlobByte(image,PALM_COMPRESSION_NONE);
    (void) WriteBlobMSBShort(image,0);  /* reserved */
    offset=16;
    if (bits_per_pixel == 16)
      {
        (void) WriteBlobByte(image,5);  /* # of bits of red */
        (void) WriteBlobByte(image,6);  /* # of bits of green */
        (void) WriteBlobByte(image,5);  /* # of bits of blue */
        (void) WriteBlobByte(image,0);  /* reserved by Palm */
        (void) WriteBlobMSBLong(image,0);  /* no transparent color, YET */
        offset+=8;
      }
    if (bits_per_pixel == 8)
      {
        if (flags & PALM_HAS_COLORMAP_FLAG)  /* Write out colormap */
          {
            quantize_info->dither_method=IdentifyPaletteImage(image,exception)
              == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod;
            quantize_info->number_colors=image->colors;
            (void) QuantizeImage(quantize_info,image,exception);
            (void) WriteBlobMSBShort(image,(unsigned short) image->colors);
            for (count = 0; count < image->colors; count++)
            {
              (void) WriteBlobByte(image,(unsigned char) count);
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].red)));
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].green)));
              (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
                image->colormap[count].blue)));
            }
            offset+=2+count*4;
          }
      else  /* Map colors to Palm standard colormap */
        {
          Image
            *affinity_image;

          affinity_image=ConstituteImage(256,1,"RGB",CharPixel,&PalmPalette,
            exception);
          (void) TransformImageColorspace(affinity_image,
            affinity_image->colorspace,exception);
          (void) RemapImage(quantize_info,image,affinity_image,exception);
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              SetPixelIndex(image,(Quantum) FindColor(&image->colormap[(ssize_t)
                GetPixelIndex(image,q)]),q);
              q+=GetPixelChannels(image);
            }
          }
          affinity_image=DestroyImage(affinity_image);
        }
      }
    if (flags & PALM_IS_COMPRESSED_FLAG)
      (void) WriteBlobMSBShort(image,0);  /* fill in size later */
    last_row=(unsigned char *) NULL;
    if (image_info->compression == FaxCompression)
      {
        last_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
          sizeof(*last_row));
        if (last_row == (unsigned char *) NULL)
          {
            quantize_info=DestroyQuantizeInfo(quantize_info);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
      }
    one_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
      sizeof(*one_row));
    if (one_row == (unsigned char *) NULL)
      {
        quantize_info=DestroyQuantizeInfo(quantize_info);
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
      }
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      ptr=one_row;
      (void) ResetMagickMemory(ptr,0,bytes_per_row);
      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
      if (p == (const Quantum *) NULL)
        break;
      if (bits_per_pixel == 16)
        {
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            color16=(unsigned short) ((((31*(size_t) GetPixelRed(image,p))/
              (size_t) QuantumRange) << 11) | (((63*(size_t)
              GetPixelGreen(image,p))/(size_t) QuantumRange) << 5) |
              ((31*(size_t) GetPixelBlue(image,p))/(size_t) QuantumRange));
            if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
              {
                transpix.red=(MagickRealType) GetPixelRed(image,p);
                transpix.green=(MagickRealType) GetPixelGreen(image,p);
                transpix.blue=(MagickRealType) GetPixelBlue(image,p);
                transpix.alpha=(MagickRealType) GetPixelAlpha(image,p);
                flags|=PALM_HAS_TRANSPARENCY_FLAG;
              }
            *ptr++=(unsigned char) ((color16 >> 8) & 0xff);
            *ptr++=(unsigned char) (color16 & 0xff);
            p+=GetPixelChannels(image);
          }
        }
      else
        {
          byte=0x00;
          bit=(unsigned char) (8-bits_per_pixel);
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            if (bits_per_pixel >= 8)
              color=(unsigned char) GetPixelIndex(image,p);
            else
              color=(unsigned char) (GetPixelIndex(image,p)*
                ((one << bits_per_pixel)-1)/MagickMax(1*image->colors-1,1));
            byte|=color << bit;
            if (bit != 0)
              bit-=(unsigned char) bits_per_pixel;
            else
              {
                *ptr++=byte;
                byte=0x00;
                bit=(unsigned char) (8-bits_per_pixel);
              }
            p+=GetPixelChannels(image);
          }
          if ((image->columns % (8/bits_per_pixel)) != 0)
            *ptr++=byte;
        }
      if (image_info->compression == RLECompression)
        {
          x=0;
          while (x < (ssize_t) bytes_per_row)
          {
            byte=one_row[x];
            count=1;
            while ((one_row[++x] == byte) && (count < 255) &&
                   (x < (ssize_t) bytes_per_row))
              count++;
            (void) WriteBlobByte(image,(unsigned char) count);
            (void) WriteBlobByte(image,(unsigned char) byte);
          }
        }
      else
        if (image_info->compression == FaxCompression)
          {
            char
              tmpbuf[8],
              *tptr;
  
            for (x = 0;  x < (ssize_t) bytes_per_row;  x += 8)
            {
              tptr = tmpbuf;
              for (bit=0, byte=0; bit < (unsigned char) MagickMin(8,(ssize_t) bytes_per_row-x); bit++)
              {
                if ((y == 0) || (last_row[x + bit] != one_row[x + bit]))
                  {
                    byte |= (1 << (7 - bit));
                    *tptr++ = (char) one_row[x + bit];
                  }
              }
              (void) WriteBlobByte(image, byte);
              (void) WriteBlob(image,tptr-tmpbuf,(unsigned char *) tmpbuf);
            }
            (void) CopyMagickMemory(last_row,one_row,bytes_per_row);
          }
        else
          (void) WriteBlob(image,bytes_per_row,one_row);
      }
    if (flags & PALM_HAS_TRANSPARENCY_FLAG)
      {
        offset=SeekBlob(image,currentOffset+6,SEEK_SET);
        (void) WriteBlobMSBShort(image,flags);
        offset=SeekBlob(image,currentOffset+12,SEEK_SET);
        (void) WriteBlobByte(image,(unsigned char) transparentIndex);  /* trans index */
      }
    if (bits_per_pixel == 16)
      {
        offset=SeekBlob(image,currentOffset+20,SEEK_SET);
        (void) WriteBlobByte(image,0);  /* reserved by Palm */
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/
          QuantumRange));
      }
    if (flags & PALM_IS_COMPRESSED_FLAG)  /* fill in size now */
      {
        offset=SeekBlob(image,currentOffset+offset,SEEK_SET);
        (void) WriteBlobMSBShort(image,(unsigned short) (GetBlobSize(image)-
          currentOffset-offset));
      }
    if (one_row != (unsigned char *) NULL) 
      one_row=(unsigned char *) RelinquishMagickMemory(one_row);
    if (last_row != (unsigned char *) NULL) 
      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
    if (GetNextImageInList(image) == (Image *) NULL)
      break;
    /* padding to 4 byte word */
    for (cc=(GetBlobSize(image)) % 4; cc > 0; cc--)
      (void) WriteBlobByte(image,0);
    /* write nextDepthOffset and return to end of image */
    offset=SeekBlob(image,currentOffset+10,SEEK_SET);
    nextDepthOffset=(size_t) ((GetBlobSize(image)-currentOffset)/4);
    (void) WriteBlobMSBShort(image,(unsigned short) nextDepthOffset);
    currentOffset=(MagickOffsetType) GetBlobSize(image);
    offset=SeekBlob(image,currentOffset,SEEK_SET);
    image=SyncNextImageInList(image);
    status=SetImageProgress(image,SaveImagesTag,scene++,
      GetImageListLength(image));
    if (status == MagickFalse)
      break;
  } while (image_info->adjoin != MagickFalse);
  quantize_info=DestroyQuantizeInfo(quantize_info);
  (void) CloseBlob(image);
  return(MagickTrue);
}

Project: ImageMagick
File: quantize.c

static void ReduceImageColors(const Image *image,CubeInfo *cube_info)
{
#define ReduceImageTag  "Reduce/Image"

  MagickBooleanType
    proceed;

  MagickOffsetType
    offset;

  size_t
    span;

  cube_info->next_threshold=0.0;
  if (cube_info->colors > cube_info->maximum_colors)
    {
      double
        *quantize_error;

      /*
        Enable rapid reduction of the number of unique colors.
      */
      quantize_error=(double *) AcquireQuantumMemory(cube_info->nodes,
        sizeof(*quantize_error));
      if (quantize_error != (double *) NULL)
        {
          (void) QuantizeErrorFlatten(cube_info,cube_info->root,0,
            quantize_error);
          qsort(quantize_error,cube_info->nodes,sizeof(double),
            QuantizeErrorCompare);
          if (cube_info->nodes > (110*(cube_info->maximum_colors+1)/100))
            cube_info->next_threshold=quantize_error[cube_info->nodes-110*
              (cube_info->maximum_colors+1)/100];
          quantize_error=(double *) RelinquishMagickMemory(quantize_error);
        }
  }
  for (span=cube_info->colors; cube_info->colors > cube_info->maximum_colors; )
  {
    cube_info->pruning_threshold=cube_info->next_threshold;
    cube_info->next_threshold=cube_info->root->quantize_error-1;
    cube_info->colors=0;
    Reduce(cube_info,cube_info->root);
    offset=(MagickOffsetType) span-cube_info->colors;
    proceed=SetImageProgress(image,ReduceImageTag,offset,span-
      cube_info->maximum_colors+1);
    if (proceed == MagickFalse)
      break;
  }
}

Project: ImageMagick
File: quantize.c

static inline ssize_t CacheOffset(CubeInfo *cube_info,
  const DoublePixelPacket *pixel)
{
#define RedShift(pixel) (((pixel) >> CacheShift) << (0*(8-CacheShift)))
#define GreenShift(pixel) (((pixel) >> CacheShift) << (1*(8-CacheShift)))
#define BlueShift(pixel) (((pixel) >> CacheShift) << (2*(8-CacheShift)))
#define AlphaShift(pixel) (((pixel) >> CacheShift) << (3*(8-CacheShift)))

  ssize_t
    offset;

  offset=(ssize_t) (RedShift(ScaleQuantumToChar(ClampPixel(pixel->red))) |
    GreenShift(ScaleQuantumToChar(ClampPixel(pixel->green))) |
    BlueShift(ScaleQuantumToChar(ClampPixel(pixel->blue))));
  if (cube_info->associate_alpha != MagickFalse)
    offset|=AlphaShift(ScaleQuantumToChar(ClampPixel(pixel->alpha)));
  return(offset);
}

Project: ImageMagick
File: quantize.c

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

  double
    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) ResetMagickMemory(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_method == NoDitherMethod)
    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) ResetMagickMemory(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);
}