#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	readint.c (Read Integer)
 * Purpose:	Scale fixed point image data to fit in a short (int*2) buffer
 * Subroutine:	scale_data_u1()			returns: void
 * Subroutine:	scale_data_i2()			returns: void
 * Subroutine:	scale_data_u2()			returns: void
 * Subroutine:	scale_data_i4()			returns: void
 * Xlib calls:	none
 * Copyright:	1998 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version	      31 October 1988
 *		{1} Juha Salo (kali@altair.utu.fi) scale_data_u1  17 Oct 1989
 *              {2} Stephan Jansen scale_data_i4 (overflow fix)    8 Dec 1989
 *                         jansen%madraf.decnet@vms.macc.wisc.edu
 *		{3} Martin Bly (Starlink) scale_data_i4 for OSF/1 31 Jan 1995
 *                          (ussc@star.rl.ac.uk)
 *		{4} Doug Mink (SAO) change ALPHA flag to LONG64    5 May 1995
 *		{5} Doug Mink (SAO) use bswap4 instead of nhtol   18 Jun 1995
 *		{6} Doug Mink (SAO) set min and max separately     2 Oct 1996
 *		{6} Doug Mink (SAO) declare bswap4()               9 Jul 1998
 *		{n} <who> -- <does what> -- <when>
 */

#include <sys/types.h>		/* needed for ntohl (net to host long) */
#ifndef VMS
#include <netinet/in.h>		/* needed for ntohl (net to host long) */
#endif
#include "hfiles/scale.h"	/* define SCALEWIDTH, etc. */
#include "hfiles/image.h"	/* image struct */

static void byte_swap();

/*
 * Subroutine:	scale_data_u1
 * Purpose:	Read an 8-bit array into a 16-bit buffer
 * Method:	Copy from end so byte data may occupy beginning of same buf
 */

void
scale_data_u1 ( image, imgbuf, databuf, vals )
     struct imageRec *image;
     register short *imgbuf;
     register unsigned char *databuf;
     int vals;
{
  databuf += (vals - 1);
  imgbuf += (vals - 1);
  /* and pad the picture */
  while( vals-- > 0 )
    *imgbuf-- = (short)*databuf--;
  image->fiscaled = 0;
  image->fibias = 0.0;
  image->fiscale = 1.0;
}

/*
 * Subroutine:	scale_data_i2
 * Purpose:	Scale 16-bit signed short data into the (short) img array
 * Method:	Data is assumed to be already in the buffer.  Only byte-swap
 *		might be needed.
 */

void
scale_data_i2 ( image, imgbuf, databuf, vals )
     struct imageRec *image;
     short *imgbuf;
     short *databuf;
     int vals;
{

  /* do byte swap if called for */
  if( image->byte_swap )
    byte_swap((char *)databuf, (char *)imgbuf, vals * sizeof(short));
  image->fiscaled = 0;
  image->fibias = 0.0;
  image->fiscale = 1.0;
}

/*
 * Subroutine:	scale_data_u2
 * Purpose:	Scale 16 bit unsigned short data into the (short) img array
 */

void
scale_data_u2 ( image, imgbuf, databuf, vals )
     struct imageRec *image;
     register short *imgbuf;
     register unsigned short *databuf;
     int vals;
{
  register unsigned short *dataend;
  register int bias;

  bias = -SCALEOFF;
  /* do byte swap if called for */
  if( image->byte_swap )
    byte_swap((char *)databuf, (char *)imgbuf, vals * sizeof(short));
  /* start from back end since data may occupy beginning of buf */
  dataend = databuf + vals;
  do {
    *imgbuf++ = (short)((int)*databuf + bias);
  } while( ++databuf < dataend );
  image->fiscaled = 1;
  image->fibias = -(double)bias;
  image->fiscale = 1.0;
}

/*
 * Subroutine:	scale_data_i4
 * Purpose:	Scale 32 bit integer data into the (short) img array
 */

void
scale_data_i4 ( image, imgbuf, databuf, vals, verbose )
     struct imageRec *image;
     short *imgbuf;
#ifdef LONG64
     int *databuf;
#else
     long *databuf;
#endif
     int vals;
     int verbose;		/* whether to print explanatory messages */
{
#ifdef LONG64
  register int *lbuf, *lbufend;
#else
  register long *lbuf, *lbufend;
#endif
  int datamin, datamax;
  void bswap4();

  {
    register int lmin, lmax;
    lbuf = databuf;
    lbufend = lbuf + vals;
    /* find the min and the max (byteswap if needed) */
    if( image->byte_swap ) {
      bswap4 ((char *)lbuf);
      lmin = lmax = *lbuf;
      /* skip the first val since we just used it */
      while( ++lbuf < lbufend ) {
        bswap4 ((char *)lbuf);
	if( *lbuf < lmin )
	  lmin = *lbuf;
	else if( *lbuf > lmax )
	  lmax = *lbuf;
      }
    } else {
      lmin = lmax = *lbuf;
      while( ++lbuf < lbufend ) {
	if( *lbuf < lmin )
	  lmin = *lbuf;
	else if( *lbuf > lmax )
	  lmax = *lbuf;
      }
    }
    datamin = lmin;
    datamax = lmax;
  }
  /* make announcement if requested */
  if (verbose)
    (void)printf("min and max as read: %d, %d\n", datamin, datamax);

  /* apply preset limits if given */
  if (image->fsmin ) {
    if( image->fimin < 0.0 )
      datamin = (int)(image->fimin - 0.5);
    else
      datamin = (int)(image->fimin + 0.5);
    }
  if (image->fsmax ) {
    if( image->fimax < 0.0 )
      datamax = (int)(image->fimax - 0.5);
    else
      datamax = (int)(image->fimax + 0.5);
    }  
  if (verbose && (image->fsmin || image->fsmax))
      (void)printf("using given limits: %d, %d\n", datamin, datamax);

  {
    register short *sbuf;
    register long bias;
    double scale;
    register int smin, smax;

    /*
     *  I inserted a number of (float) conversions to stop the problem
     *  with overflow.
     *  Stephan Jansen
     */

    smin = SCALEMIN;
    smax = SCALEMAX;
    /* reset buf pointer for another pass through lbuf */
    lbuf = databuf;
    sbuf = imgbuf;
    if( ((double)datamax - (double)datamin) <= (double)SCALEWIDTH ) {
      /* if a simple offset suffices */
      register long ltemp;
      if( (datamin >= SCALEMIN) && (datamax <= SCALEMAX) ) {
	/* if possible to truncate to short without bias, do so. */
	bias = 0;
	image->fiscaled = 0;
	image->fibias = 0.0;
      } else {
	/* offset by average to center within range */
	bias = -((datamin + datamax) / 2);
	image->fiscaled = 1;
	image->fibias = (double)(-bias);
      }
      image->fiscale = 1.0;
      do {
	ltemp = *lbuf + bias;
	if( ltemp < smin ) {
	  *sbuf++ = smin;
	} else if( ltemp > smax ) {
	  *sbuf++ = smax;
	} else
	  *sbuf++ = (short)ltemp;
      } while( ++lbuf < lbufend );
    } else {
      /* full-up scaling required. (+/- (tmax-tmin)/2) */
      double dtemp, dmin, dmax, dbias;
      /* offset values to be zero centered */
      dbias = -(((double)datamin + (double)datamax) * 0.5);
      /* get the scale factor (no divide by zero gets past prior test) */
      scale = (double)SCALEWIDTH / ((double)datamax - (double)datamin);
      /* use min and max to mark out limits as float values */
      dmin = (double)SCALEMIN;
      dmax = (double)SCALEMAX;
      /* scale the picture */
      do {
	dtemp = ((double)(*lbuf) + dbias) * scale;
	if( dtemp < 0.0 ) {
	  dtemp -= 0.5;
	  if( dtemp < dmin )
	    *sbuf++ = smin;
	  else
	    *sbuf++ = (short)dtemp;
	} else {
	  dtemp += 0.5;
	  if( dtemp > dmax )
	    *sbuf++ = smax;
	  else
	    *sbuf++ = (short)dtemp;
	}
      } while( ++lbuf < lbufend );
      image->fiscaled = 1;
      image->fibias = -dbias;
      image->fiscale = 1.0 / scale;
    }
  }
}

/*
 * Subroutine:	byte_swap
 * Purpose:	Equivalent of UNIX swab, but guaranteed to work in place
 *		and usable under VMS
 */

static void
byte_swap( inbuf, outbuf, nbytes )
     char *inbuf;
     char *outbuf;
     int nbytes;
{
  register char *from, *to, *last_byte;
  register unsigned temp;

  from = inbuf;
  to = outbuf;
  last_byte = from + nbytes;
  while( from < last_byte ) {
    temp = *from;
    ++from;
    *to = *from;
    ++to;
    *to = temp;
    ++to;
    ++from;
  }
}


syntax highlighted by Code2HTML, v. 0.9.1