text: /*
   * The Python Imaging Library
   * $Id$
   *
   * histogram support
   *
   * history:
   * 1995-06-15 fl   Created.
   * 1996-04-05 fl   Fixed histogram for multiband images.
   * 1997-02-23 fl   Added mask support
   * 1998-07-01 fl   Added basic 32-bit float/integer support
   *
   * Copyright (c) 1997-2003 by Secret Labs AB.
   * Copyright (c) 1995-2003 by Fredrik Lundh.
   *
   * See the README file for information on usage and redistribution.
   */
  
  
  #include "Imaging.h"
  
  
  /* HISTOGRAM */
  /* --------------------------------------------------------------------
   * Take a histogram of an image. Returns a histogram object containing
   * 256 slots per band in the input image.
   */
  
  void
  ImagingHistogramDelete(ImagingHistogram h)
  {
      if (h->histogram)
  	free(h->histogram);
      free(h);
  }
  
  ImagingHistogram
  ImagingHistogramNew(Imaging im)
  {
      ImagingHistogram h;
  
      /* Create histogram descriptor */
      h = calloc(1, sizeof(struct ImagingHistogramInstance));
      strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH-1);
      h->mode[IMAGING_MODE_LENGTH-1] = 0;
  
      h->bands = im->bands;
      h->histogram = calloc(im->pixelsize, 256 * sizeof(long));
  
      return h;
  }
  
  ImagingHistogram
  ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
  {
      ImagingSectionCookie cookie;
      int x, y, i;
      ImagingHistogram h;
      INT32 imin, imax;
      FLOAT32 fmin, fmax, scale;
  
      if (!im)
  	return ImagingError_ModeError();
  
      if (imMask) {
  	/* Validate mask */
  	if (im->xsize != imMask->xsize || im->ysize != imMask->ysize)
  	    return ImagingError_Mismatch();
  	if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0)
  	    return ImagingError_ValueError("bad transparency mask");
      }
  
      h = ImagingHistogramNew(im);
  
      if (imMask) {
  	/* mask */
  	if (im->image8) {
              ImagingSectionEnter(&cookie);
  	    for (y = 0; y < im->ysize; y++)
  		for (x = 0; x < im->xsize; x++)
  		    if (imMask->image8[y][x] != 0)
  			h->histogram[im->image8[y][x]]++;
              ImagingSectionLeave(&cookie);
  	} else { /* yes, we need the braces. C isn't Python! */
              if (im->type != IMAGING_TYPE_UINT8) {
                  ImagingHistogramDelete(h);
                  return ImagingError_ModeError();
              }
              ImagingSectionEnter(&cookie);
  	    for (y = 0; y < im->ysize; y++) {
  		UINT8* in = (UINT8*) im->image32[y];
  		for (x = 0; x < im->xsize; x++)
  		    if (imMask->image8[y][x] != 0) {
  			h->histogram[(*in++)]++;
  			h->histogram[(*in++)+256]++;
  			h->histogram[(*in++)+512]++;
  			h->histogram[(*in++)+768]++;
  		    } else
  			in += 4;
  	    }
              ImagingSectionLeave(&cookie);
  	}
      } else {
  	/* mask not given; process pixels in image */
  	if (im->image8) {
              ImagingSectionEnter(&cookie);
  	    for (y = 0; y < im->ysize; y++)
  		for (x = 0; x < im->xsize; x++)
  		    h->histogram[im->image8[y][x]]++;
              ImagingSectionLeave(&cookie);
  	} else {
              switch (im->type) {
              case IMAGING_TYPE_UINT8:
                  ImagingSectionEnter(&cookie);
                  for (y = 0; y < im->ysize; y++) {
                      UINT8* in = (UINT8*) im->image[y];
                      for (x = 0; x < im->xsize; x++) {
                          h->histogram[(*in++)]++;
                          h->histogram[(*in++)+256]++;
                          h->histogram[(*in++)+512]++;
                          h->histogram[(*in++)+768]++;
                      }
                  }
                  ImagingSectionLeave(&cookie);
                  break;
              case IMAGING_TYPE_INT32:
                  if (!minmax) {
                      ImagingHistogramDelete(h);
                      return ImagingError_ValueError("min/max not given");
                  }
                  if (!im->xsize || !im->ysize)
                      break;
                  imin = ((INT32*) minmax)[0];
                  imax = ((INT32*) minmax)[1];
                  if (imin >= imax)
                      break;
                  ImagingSectionEnter(&cookie);
                  scale = 255.0F / (imax - imin);
                  for (y = 0; y < im->ysize; y++) {
                      INT32* in = im->image32[y];
                      for (x = 0; x < im->xsize; x++) {
                          i = (int) (((*in++)-imin)*scale);
                          if (i >= 0 && i < 256)
                              h->histogram[i]++;
                      }
                  }
                  ImagingSectionLeave(&cookie);
                  break;
              case IMAGING_TYPE_FLOAT32:
                  if (!minmax) {
                      ImagingHistogramDelete(h);
                      return ImagingError_ValueError("min/max not given");
                  }
                  if (!im->xsize || !im->ysize)
                      break;
                  fmin = ((FLOAT32*) minmax)[0];
                  fmax = ((FLOAT32*) minmax)[1];
                  if (fmin >= fmax)
                      break;
                  ImagingSectionEnter(&cookie);
                  scale = 255.0F / (fmax - fmin);
                  for (y = 0; y < im->ysize; y++) {
                      FLOAT32* in = (FLOAT32*) im->image32[y];
                      for (x = 0; x < im->xsize; x++) {
                          i = (int) (((*in++)-fmin)*scale);
                          if (i >= 0 && i < 256)
                              h->histogram[i]++;
                      }
                  }
                  ImagingSectionLeave(&cookie);
                  break;
              }
          }
      }
  
      return h;
  }
  