// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// imageutil.C
//
// Author:               Sameer Nene
// Date:                 05/23/94
// Version:              1.0
// Modification History:
// Bugs:
//
// Classes:
//   ImageUtil
//
// Notes:
//   This module contains implementation of classes declared in imageutil.h
//   
// ----------------------------------------------------------------------------

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <values.h>
#include "errorscope.h"
#include "vector.h"
#include "image.h"
#include "imageutil.h"

#ifdef XSUPPORT
#include <X11/Xlib.h>
#endif

#ifndef MAXDOUBLE
#define MAXDOUBLE 1.797693134862315708e+308
#endif

const double ImageUtil::A = -.5;
int ImageUtil::d_x1, ImageUtil::d_y1, ImageUtil::d_x2, ImageUtil::d_y2;
int ImageUtil::d_area;

ErrorScope::Error ImageUtil::PGMGetFromDisk(Image *img, const char *fileName)
{
  int c, xsize, ysize;
  char buf[256];
  
  FILE *handle = fopen(fileName, "r");
  if(handle == 0)
    return FILE_OPEN_ERROR;
  if(fgets(buf, 3, handle) == 0 || strcmp(buf, "P5")) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  int state = 0;
  do {
    if((c = fgetc(handle)) == EOF) {
      fclose(handle);
      return FILE_READ_ERROR;
    }
    switch(state) {
    case 0 :
      if(isspace(c))
	break;
      if(c == '#')
	state = 1;
      else if(isdigit(c)) {
	ungetc(c, handle);
	state = 2;
      }
      else
	state = 3;
      break;
    case 1:
      if(c == '\n')
	state = 0;
    }
  }
  while(state < 2);

  if(state == 3) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  if(fscanf(handle, "%u%u%u", &xsize, &ysize, &c) != 3) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  // Skip /n
  if(fgets(buf, 256, handle) == 0) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  if(xsize != img -> d_xsize || ysize != img -> d_ysize) {
    delete[] img -> d_data_p;
    img -> d_xsize = xsize;
    img -> d_ysize = ysize;
    img -> d_data_p = new unsigned char[xsize * ysize];
  }
  
  if(fread((char *)(img -> d_data_p), 1, xsize * ysize, handle) != xsize * ysize) {
    fclose(handle);
    return FILE_READ_ERROR;
  }

  fclose(handle);
  return OK;
}

ErrorScope::Error ImageUtil::PPMGetFromDisk(ColorImage *img,
					    const char *fileName)
{
  int c, xsize, ysize, j;
  char buf[256];
  
  FILE *handle = fopen(fileName, "r");
  if(handle == 0)
    return FILE_OPEN_ERROR;
  if(fgets(buf, 3, handle) == 0 || strcmp(buf, "P6")) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  int state = 0;
  do {
    if((c = fgetc(handle)) == EOF) {
      fclose(handle);
      return FILE_READ_ERROR;
    }
    switch(state) {
    case 0 :
      if(isspace(c))
	break;
      if(c == '#')
	state = 1;
      else if(isdigit(c)) {
	ungetc(c, handle);
	state = 2;
      }
      else
	state = 3;
      break;
    case 1:
      if(c == '\n')
	state = 0;
    }
  }
  while(state < 2);

  if(state == 3) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  if(fscanf(handle, "%u%u%u", &xsize, &ysize, &c) != 3) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  // Skip /n
  if(fgets(buf, 256, handle) == 0) {
    fclose(handle);
    return INCORRECT_FORMAT;
  }

  j = xsize * ysize;

  if(xsize != img -> d_xsize || ysize != img -> d_ysize) {
    delete[] img -> d_data_p;
    img -> d_xsize = xsize;
    img -> d_ysize = ysize;
    img -> d_data_p = new unsigned char[j * 3];
  }

  if(fread((char *)(img -> d_data_p), 3, j, handle) != j) {
    fclose(handle);
    return FILE_READ_ERROR;
  }

  fclose(handle);
  return OK;
}

ErrorScope::Error ImageUtil::PGMDumpToDisk(const Image &img,
					   const char *fileName)
{
  FILE *handle = fopen(fileName, "w");
  if(handle == 0)
    return FILE_OPEN_ERROR;

  if(fprintf(handle, "P5\n# Creator: SLAM V1.0 Rev: 07/02/94\n") == EOF) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }
  
  if(fprintf(handle, "%u %u\n255\n", img.d_xsize, img.d_ysize) == EOF) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }
 
  if(fwrite((char *)img.d_data_p, 1, img.d_xsize * img.d_ysize, handle) !=
     img.d_xsize * img.d_ysize) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }

  return fclose(handle) ? FILE_CLOSE_ERROR : OK;
}

ErrorScope::Error ImageUtil::PPMDumpToDisk(const ColorImage &img,
					   const char *fileName)
{
  int j;
  FILE *handle = fopen(fileName, "w");
  if(handle == 0)
    return FILE_OPEN_ERROR;

  if(fprintf(handle, "P6\n# Creator: SLAM V1.0 Rev: 07/02/94\n") == EOF) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }
  
  if(fprintf(handle, "%u %u\n255\n", img.d_xsize, img.d_ysize) == EOF) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }

  j = img.d_xsize * img.d_ysize;

  if(fwrite((char*)img.d_data_p, 3, j, handle) != j) {
    fclose(handle);
    return FILE_WRITE_ERROR;
  }
  
  return fclose(handle) ? FILE_CLOSE_ERROR : OK;
}

double ImageUtil::ckernel(double x)
{
  double x2;
  
  x = fabs(x);
  if(x >= 0. && x < 1.) {
    x2 = x * x;
    return (A + 2.) * x * x2 - (A + 3.) * x2 + 1.;
  }
  if(x >= 1. && x < 2.) {
    x2 = x * x;
    return A * x * x2 - 5. * A * x2 + 8. * A * x - 4. * A;
  }
  return 0.;
}

void ImageUtil::CropImage(const Image &img, Vector *v, int x1, int y1, int x2,
			  int y2)
{
  unsigned char *p;
  double *l;
  int i, j, x = x2 - x1 + 1, y = y2 - y1 + 1;

  v -> length(x * y);
  
  for(i = 0, l = v -> d_data_p, p = &img.d_data_p[y1 * img.d_xsize + x1]; i < y;
      ++i, p+= img.d_xsize)
    for(j = 0; j < x; *(l++) = p[j++]);
}

void ImageUtil::CropImage(const ColorImage &img, Vector *r, Vector *g,
			  Vector *b, int x1, int y1, int x2, int y2)
{
  unsigned char *p;
  double *lr, *lg, *lb;
  int i, j, x = x2 - x1 + 1, y = y2 - y1 + 1;

  r -> length(x * y);
  g -> length(x * y);
  b -> length(x * y);
  
  for(i = 0, lr = r -> d_data_p, lg = g -> d_data_p, lb = b -> d_data_p, p = &img.d_data_p[(y1 * img.d_xsize + x1) * 3]; i < y; ++i, p += img.d_xsize)
    for(j = 0; j < x; ++j) {
      *(lr++) = p[j++];
      *(lg++) = p[j++];
      *(lb++) = p[j];
    }
}

void ImageUtil::ImageToVector(const Image &img, Vector *v)
{
  int i, j;
  double *p;
  
  v -> length(img.d_xsize * img.d_ysize);
  for(i = 0, j = img.d_xsize * img.d_ysize, p = v -> d_data_p; i < j;
      *(p++) = img.d_data_p[i++]);
}

void ImageUtil::VectorToImage(const Vector &v, Image *i, int xsize, int ysize,
			      int flag)
{
  int j, k;
  double min, max, t;
  unsigned char *p;

  if(i -> d_xsize != xsize || i -> d_ysize != ysize) {
    delete[] i -> d_data_p;
    i -> d_data_p = new unsigned char[(i -> d_xsize = xsize) *
				      (i -> d_ysize = ysize)];
  }

  if(flag == GAMMA_CORRECT) {
    for(j = 0, k = v.d_size, min = MAXDOUBLE, max = 0.; j < k; ++j) {
      t = v.d_data_p[j];
      if(t < min)
	min = t;
      if(t > max)
	max = t;
    }
    
    for(j = 0, p = i -> d_data_p, max = 255. / (max - min); j < k;
	*(p++) = (unsigned char)((v.d_data_p[j++] - min) * max));
  }
  else
    for(j = 0, k = v.d_size, p = i -> d_data_p; j < k;
	*(p++) = (unsigned char)v.d_data_p[j++]);
}

void ImageUtil::VectorToImage(const Vector &red, const Vector &green,
			      const Vector &blue, ColorImage *i, int xsize,
			      int ysize, int flag)
{
  int j, k;
  double min, max, t;
  unsigned char *p;

  if(i -> d_xsize != xsize || i -> d_ysize != ysize) {
    delete[] i -> d_data_p;
    i -> d_data_p = new unsigned char[(i -> d_xsize = xsize) *
				      (i -> d_ysize = ysize) * 3];
  }

  if(flag == GAMMA_CORRECT) {
    for(j = 0, k = red.d_size, min = MAXDOUBLE, max = 0.; j < k; ++j) {
      t = red.d_data_p[j];
      if(t < min)
	min = t;
      if(t > max)
	max = t;
      t = green.d_data_p[j];
      if(t < min)
	min = t;
      if(t > max)
	max = t;
      t = blue.d_data_p[j];
      if(t < min)
	min = t;
      if(t > max)
	max = t;
    }
    
    for(j = 0, p = i -> d_data_p, max = 255. / (max - min); j < k; ++j) {
      *(p++) = (unsigned char)((red.d_data_p[j] - min) * max);
      *(p++) = (unsigned char)((green.d_data_p[j] - min) * max);
      *(p++) = (unsigned char)((blue.d_data_p[j] - min) * max);
    }
  }
  else
    for(j = 0, k = red.d_size, p = i -> d_data_p; j < k; ++j) {
      *(p++) = (unsigned char)red.d_data_p[j];
      *(p++) = (unsigned char)green.d_data_p[j];
      *(p++) = (unsigned char)blue.d_data_p[j];
    }
}

void ImageUtil::FindBoundingBox(const Image &img, int *x1, int *y1, int *x2,
				int *y2, int THRESHOLD)
{
  int i, j;
  unsigned char *p = img.d_data_p;

  *x1 = img.d_xsize - 1;
  *y1 = img.d_ysize - 1;
  *x2 = *y2 = 0;

  if(THRESHOLD >= 0) {
    for(i = 0; i < img.d_ysize; ++i)
      for(j = 0; j < img.d_xsize; ++j)
	if(*(p++) >= (unsigned char)THRESHOLD)
	  if(j < *x1) {
	    *x1 = j;
	    if(i < *y1)
	      *y1 = i;
	  }
	  else {
	    if(j > *x2)
	      *x2 = j;
	    if(i > *y2)
	      *y2 = i;
	  }
  }
  else {
    THRESHOLD += 255;
    for(i = 0; i < img.d_ysize; ++i)
      for(j = 0; j < img.d_xsize; ++j)
	if(*(p++) <= (unsigned char)THRESHOLD)
	  if(j < *x1) {
	    *x1 = j;
	    if(i < *y1)
	      *y1 = i;
	  }
	  else {
	    if(j > *x2)
	      *x2 = j;
	    if(i > *y2)
	      *y2 = i;
	  }
  }
}

void ImageUtil::FindBoundingBox(const ColorImage &img, int *x1, int *y1,
				int *x2, int *y2, int THRESHOLD)
{
  int i, j;
  unsigned char *p = img.d_data_p;

  *x1 = img.d_xsize - 1;
  *y1 = img.d_ysize - 1;
  *x2 = *y2 = 0;

  if(THRESHOLD >= 0) {
    for(i = 0; i < img.d_ysize; ++i)
      for(j = 0; j < img.d_xsize; ++j, p += 3)
	if((*p >= (unsigned char)THRESHOLD) || (*(p + 1) >= (unsigned char)THRESHOLD) || (*(p + 2) >= (unsigned char)THRESHOLD))
	  if(j < *x1) {
	    *x1 = j;
	    if(i < *y1)
	      *y1 = i;
	  }
	  else {
	    if(j > *x2)
	      *x2 = j;
	    if(i > *y2)
	      *y2 = i;
	  }
  }
  else {
    THRESHOLD += 255;
    for(i = 0; i < img.d_ysize; ++i)
      for(j = 0; j < img.d_xsize; ++j, p += 3)
	if((*p <= (unsigned char)THRESHOLD) || (*(p + 1) <= (unsigned char)THRESHOLD) || (*(p + 2) <= (unsigned char)THRESHOLD))
	  if(j < *x1) {
	    *x1 = j;
	    if(i < *y1)
	      *y1 = i;
	  }
	  else {
	    if(j > *x2)
	      *x2 = j;
	    if(i > *y2)
	      *y2 = i;
	  }
  }
}

void ImageUtil::NormalizeSize(const Image &img, Vector *img2, int x1, int y1,
			      int x2, int y2, int XSIZE, int YSIZE, int aflag)
{
  int dst2, i, j, n, l, m, t1, t2, t3, xsize, ysize, *nlut;
  double d, k, r, r1, r2, t, *base, *dst, *p, *p2, *lut[4];
  unsigned char *src;

  xsize = x2 - x1 + 1;
  ysize = y2 - y1 + 1;

  if(aflag == PRESERVE_ASPECT)
    YSIZE = XSIZE;

  r1 = (double)ysize / YSIZE;
  r2 = (double)xsize / XSIZE;

  if(aflag == PRESERVE_ASPECT)
    r = r1 < r2 ? r2 : r1;
  else
    r = r2;
  
  p = p2 = new double[(j = int(xsize / r)) * ysize];
  src = &img.d_data_p[y1 * img.d_xsize + x1];

  m = int(xsize / r);
  lut[0] = new double[m];
  lut[1] = new double[m];
  lut[2] = new double[m];
  lut[3] = new double[m];
  nlut = new int[m];

  for(k = 0., l = 0; l < m; k += r, ++l) {
    nlut[l] = int(t = floor(k));
    d = k - t;
    lut[0][l] = ckernel(-d - 1.);
    lut[1][l] = ckernel(-d);
    lut[2][l] = ckernel(1. - d);
    lut[3][l] = ckernel(2. - d);
  }

  for(i = 0, t1 = xsize - 1, t2 = xsize - 2; i < ysize; ++i) {
    for(k = 0., l = 0; l < m; k += r, ++l) {
      n = nlut[l];
      *(p2++) = (n > 0 ? src[n - 1] : 0.) * lut[0][l] + src[n] * lut[1][l] + (n < t1 ? src[n + 1] : 0.) * lut[2][l] + (n < t2 ? src[n + 2] : 0.) * lut[3][l];
    }
    src += img.d_xsize;
  }

  if(aflag == NOPRESERVE_ASPECT)
    r = r1;

  delete[] lut[0];
  delete[] lut[1];
  delete[] lut[2];
  delete[] lut[3];
  delete[] nlut;

  m = int(ysize / r);

  lut[0] = new double[m];
  lut[1] = new double[m];
  lut[2] = new double[m];
  lut[3] = new double[m];
  nlut = new int[m];

  img2 -> length(n = XSIZE * YSIZE);

  if(aflag == PRESERVE_ASPECT) {
    for(i = 0, base = img2 -> d_data_p; i < n; base[i++] = 0.);
    if(aflag == PRESERVE_ASPECT) {
      if(XSIZE > j) 
	dst2 = (XSIZE - j) >> 1;
      else
	dst2 = ((YSIZE - int(ysize / r)) >> 1) * XSIZE;
    }
  }
  else {
    base = img2 -> d_data_p;
    dst2 = 0;
  }

  p2 = p;

  for(k = 0., l = 0; l < m; k += r, ++l) {
    nlut[l] = int(t = floor(k)) * j;
    d = k - t;
    lut[0][l] = ckernel(-d - 1.);
    lut[1][l] = ckernel(-d);
    lut[2][l] = ckernel(1. - d);
    lut[3][l] = ckernel(2. - d);
  }

  for(i = 0, t1 = ysize * j - j, t2 = ysize * j - j * 2, t3 = j * 2; i < j; ++i) {
    dst = &base[dst2 + i];
    for(k = 0., l = 0; l < m; k += r, ++l) {
      n = nlut[l];
      d = (n > 0 ? p2[n - j] : 0.) * lut[0][l] + p2[n] * lut[1][l] + (n < t1 ? p2[n + j] : 0.) * lut[2][l] + (n < t2 ? p2[n + t3] : 0.) * lut[3][l];
      *dst = d < 0. ? 0. : (d > 255. ? 255. : floor(d));
      dst += XSIZE;
    }
    ++p2;
  }
  delete[] p;
  delete[] lut[0];
  delete[] lut[1];
  delete[] lut[2];
  delete[] lut[3];
  delete[] nlut;
}

void ImageUtil::NormalizeSize(const ColorImage &img, Vector *red,
			      Vector *green, Vector *blue, int x1, int y1,
			      int x2, int y2, int XSIZE, int YSIZE, int aflag)
{
  int c, dst2, i, j, n, l, m, t1, t2, t3, xsize, ysize, *nlut;
  double d, k, r, r1, r2, t, *base[3], *dst, *p[3], *p2[3], *lut[4];
  unsigned char *src;

  xsize = x2 - x1 + 1;
  ysize = y2 - y1 + 1;

  if(aflag == PRESERVE_ASPECT)
    YSIZE = XSIZE;

  r1 = (double)ysize / YSIZE;
  r2 = (double)xsize / XSIZE;

  if(aflag == PRESERVE_ASPECT)
    r = r1 < r2 ? r2 : r1;
  else
    r = r2;
  
  p[0] = p2[0] = new double[(j = int(xsize / r)) * ysize];
  p[1] = p2[1] = new double[j * ysize];
  p[2] = p2[2] = new double[j * ysize];
  src = &img.d_data_p[(y1 * img.d_xsize + x1) * 3];

  m = int(xsize / r);
  lut[0] = new double[m];
  lut[1] = new double[m];
  lut[2] = new double[m];
  lut[3] = new double[m];
  nlut = new int[m];

  for(k = 0., l = 0; l < m; k += r, ++l) {
    nlut[l] = int(t = floor(k)) * 3; // for RGB
    d = k - t;
    lut[0][l] = ckernel(-d - 1.);
    lut[1][l] = ckernel(-d);
    lut[2][l] = ckernel(1. - d);
    lut[3][l] = ckernel(2. - d);
  }

  for(i = 0, t1 = (xsize - 1) * 3, t2 = (xsize - 2) * 3; i < ysize; ++i) {
    for(k = 0., l = 0; l < m; k += r, ++l) {
      for(c = 0, n = nlut[l]; c < 3; ++c)
	*(p2[c]++) = (n > 0 ? src[n + c - 3] : 0.) * lut[0][l] + src[n + c] * lut[1][l] + (n < t1 ? src[n + c + 3] : 0.) * lut[2][l] + (n < t2 ? src[n + c + 6] : 0.) * lut[3][l];
    }
    src += img.d_xsize * 3;
  }

  if(aflag == NOPRESERVE_ASPECT)
    r = r1;

  delete[] lut[0];
  delete[] lut[1];
  delete[] lut[2];
  delete[] lut[3];
  delete[] nlut;

  m = int(ysize / r);

  lut[0] = new double[m];
  lut[1] = new double[m];
  lut[2] = new double[m];
  lut[3] = new double[m];
  nlut = new int[m];

  red -> length(n = XSIZE * YSIZE);
  base[0] = red -> d_data_p;
  green -> length(n);
  base[1] = green -> d_data_p;
  blue -> length(n);
  base[2] = blue -> d_data_p;

  if(aflag == PRESERVE_ASPECT) {
    for(c = 0; c < 3; ++c)
      for(i = 0; i < n; base[c][i++] = 25.); // For 100 object recog.
    if(aflag == PRESERVE_ASPECT) {
      if(XSIZE > j) 
	dst2 = (XSIZE - j) >> 1;
      else
	dst2 = ((YSIZE - int(ysize / r)) >> 1) * XSIZE;
    }
  }
  else
    dst2 = 0;

  p2[0] = p[0];
  p2[1] = p[1];
  p2[2] = p[2];

  for(k = 0., l = 0; l < m; k += r, ++l) {
    nlut[l] = int(t = floor(k)) * j;
    d = k - t;
    lut[0][l] = ckernel(-d - 1.);
    lut[1][l] = ckernel(-d);
    lut[2][l] = ckernel(1. - d);
    lut[3][l] = ckernel(2. - d);
  }

  for(c = 0; c < 3; ++c)
    for(i = 0, t1 = ysize * j - j, t2 = ysize * j - j * 2, t3 = j * 2; i < j; ++i) {
      dst = &(base[c][dst2 + i]);
      for(k = 0., l = 0; l < m; k += r, ++l) {
	n = nlut[l];
	d = (n > 0 ? p2[c][n - j] : 0.) * lut[0][l] + p2[c][n] * lut[1][l] + (n < t1 ? p2[c][n + j] : 0.) * lut[2][l] + (n < t2 ? p2[c][n + t3] : 0.) * lut[3][l];
	*dst = d < 0. ? 0. : (d > 255. ? 255. : floor(d));
	dst += XSIZE;
      }
      ++p2[c];
    }

  delete[] p[0];
  delete[] p[1];
  delete[] p[2];
  delete[] lut[0];
  delete[] lut[1];
  delete[] lut[2];
  delete[] lut[3];
  delete[] nlut;
}

void ImageUtil::colorImageToMono(const ColorImage &cim, Image *im)
{
  int i, j;
  unsigned char *p1, *p2;

  if(im -> d_xsize != cim.d_xsize || im -> d_ysize != cim.d_ysize) {
    delete[] im -> d_data_p;
    im -> d_xsize = cim.d_xsize;
    im -> d_ysize = cim.d_ysize;
    im -> d_data_p = new unsigned char[cim.d_xsize * cim.d_ysize];
  }
  for(i = 0, j = cim.d_xsize * cim.d_ysize, p2 = im -> d_data_p, p1 = cim.d_data_p; i < j; ++i, p1 += 3, ++p2)
    *p2 = (unsigned char)(p1[0] * .326 + p1[1] * .578 + p1[2] * .096);
}

void ImageUtil::rlabel(Image *img, int x, int y, int THRESHOLD)
{
  int i, j;

  if(x > 0 && x < img -> d_xsize - 1 && y > 0 && y < img -> d_ysize - 1) {
    img -> d_data_p[y * img -> d_xsize + x] = 0;
    if(x < d_x1)
      d_x1 = x;
    if(y < d_y1)
      d_y1 = y;
    if(x > d_x2)
      d_x2 = x;
    if(y > d_y2)
      d_y2 = y;
    for(i = -1; i < 2; ++i)
      for(j = -1; j < 2; ++j)
	if(img -> d_data_p[(y + i) * img -> d_xsize + x + j] > THRESHOLD) {
	   rlabel(img, x + j, y + i, THRESHOLD);
	   ++d_area;
	 }
  }
}

void ImageUtil::FindBoundingBoxReliable(const ColorImage &im,
					int *x1, int *y1, int *x2, int *y2,
					int THRESHOLD, int AREATHRESHOLD)
{
  int i, j;
  unsigned char *p;
  Image img;
  
  colorImageToMono(im, &img);
  
  for(i = 0, p  = img.d_data_p; i < img.d_ysize; ++i)
    for(j = 0; j < img.d_xsize; ++j)
      if(*(p++) > THRESHOLD) {
	d_x1 = img.d_xsize;
	d_y1 = img.d_ysize;
	d_x2 = d_y2 = 0;
	d_area = 1;
	rlabel(&img, j, i, THRESHOLD);
	if(d_area > AREATHRESHOLD) {
	  *x1 = d_x1;
	  *y1 = d_y1;
	  *x2 = d_x2;
	  *y2 = d_y2;
	  return;
	}
      }
  *x1 = *y1 = 0;
  *x2 = img.d_xsize - 1;
  *y2 = img.d_ysize - 1;
}

#ifdef XSUPPORT

void ImageUtil::setXImage(XImage *ximg, const Image &img,
			  const unsigned long *ctrans)
{
  int i, j = img.d_xsize * img.d_ysize;
  delete[] ximg -> data;
  ximg -> data = new char[j];
  for(i = 0; i < j; ++i)
    ximg -> data[i] = (unsigned char)ctrans[img.d_data_p[i]];
  ximg -> width = img.d_xsize;
  ximg -> height = img.d_ysize;
  ximg -> bytes_per_line = img.d_xsize;
}

void ImageUtil::imageToXImage(const Image &im, XImage *ximg)
{
  memcpy(ximg -> data, im.d_data_p, ximg -> width * ximg -> height);
}

void ImageUtil::imageToXImage(const ColorImage &im, XImage *ximg)
{
  unsigned char *p1, *p2;
  int i, j;

  for(i = 0, j = im.d_xsize * im.d_ysize, p1 = im.d_data_p, p2 = (unsigned char *)(ximg -> data); i < j; ++i, p1 += 3, p2 += 4) {
    p2[0] = p1[0];
    p2[1] = p1[1];
    p2[2] = p1[2];
  }
}

#endif
