/* #ident	"@(#)x11:contrib/clients/xloadimage/smooth.c 1.8 91/12/19 Labtam" */
/* smooth.c:
 *
 * this performs a smoothing convolution using a 3x3 area.
 *
 * jim frost 09.20.90
 *
 * Copyright 1990, 1991 Jim Frost.
 * See included file "copyright.h" for complete copyright information.
 */

#include "copyright.h"
#include "image.h"

static Image *doSmooth(image)
     Image *image;
{ Image *old, *new;
  int    x, y, x1, y1, linelen;
  int    xindex[3];
  byte  *yindex[3];
  byte  *srcptr, *destptr;
  unsigned long avgred, avggreen, avgblue;

  /* build true color image from old image and allocate new image
   */

  old= expand(image);
  new= newTrueImage(image->width, image->height);
  new->title= (char *)lmalloc(strlen(image->title) + 12);
  sprintf(new->title, "%s (smoothed)", image->title);
  new->gamma= image->gamma;

  /* run through image and take a guess as to what the color should
   * actually be.
   */

  destptr= new->data;
  linelen= old->pixlen * old->width;
  if(new->pixlen == 3 && old->pixlen == 3) {	/* usual case */
    for (y= 0; y < old->height; y++) {
      yindex[1]= old->data + (y * linelen);
      yindex[0]= yindex[1] - (y > 0 ? linelen : 0);
      yindex[2]= yindex[1] + (y < old->height - 1 ? linelen : 0);
      for (x= 0; x < old->width; x++) {
        avgred= avggreen= avgblue= 0;
        xindex[1]= x * 3;
        xindex[0]= xindex[1] - (x > 0 ? 3 : 0);
        xindex[2]= xindex[1] + (x < old->width - 1 ? 3 : 0);
        for (y1= 0; y1 < 3; y1++) {
          for (x1= 0; x1 < 3; x1++) {
            srcptr = yindex[y1] + xindex[x1];
            avgred += *srcptr;
            avggreen += *(srcptr + 1);
            avgblue += *(srcptr + 2);
          }
        }
  
        /* average the pixel values
         */
  
        *destptr++ = ((avgred + 8) / 9);
        *destptr++ = ((avggreen + 8) / 9);
        *destptr++ = ((avgblue + 8) / 9);
      }
    }
  } else {	/* less usual */
    Pixel  pixval;
    for (y= 0; y < old->height; y++) {
      yindex[1]= old->data + (y * linelen);
      yindex[0]= yindex[1] - (y > 0 ? linelen : 0);
      yindex[2]= yindex[1] + (y < old->height - 1 ? linelen : 0);
      for (x= 0; x < old->width; x++) {
        avgred= avggreen= avgblue= 0;
        xindex[1]= x * old->pixlen;
        xindex[0]= xindex[1] - (x > 0 ? old->pixlen : 0);
        xindex[2]= xindex[1] + (x < old->width - 1 ? old->pixlen : 0);
        for (y1= 0; y1 < 3; y1++) {
          for (x1= 0; x1 < 3; x1++) {
            pixval= memToVal(yindex[y1] + xindex[x1], old->pixlen);
            avgred += TRUE_RED(pixval);
            avggreen += TRUE_GREEN(pixval);
            avgblue += TRUE_BLUE(pixval);
          }
        }
  
        /* average the pixel values
         */
  
        avgred= ((avgred + 8) / 9);
        avggreen= ((avggreen + 8) / 9);
        avgblue= ((avgblue + 8) / 9);
        pixval= (avgred << 16) | (avggreen << 8) | avgblue;
        valToMem(pixval, destptr, new->pixlen);
        destptr += new->pixlen;
      }
    }
  }
  if (old != image)
    freeImage(old);
  return(new);
}

Image *smooth(iimage, iterations, verbose)
     Image *iimage;
     int    verbose;
{ int a;
  Image *image=iimage,*new;

  if(image->gamma != 1.0)
    gammacorrect(image, 1.0, verbose);

  if (verbose) {
    printf("  Smoothing...");
    fflush(stdout);
  }

  for (a= 0; a < iterations; a++) {
    new= doSmooth(image);
    if(new != image && image != iimage)	/* don't free the input image */
      freeImage(image);
    image= new;
  }

  if (verbose)
    printf("done\n");

  return(image);
}
