aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/ximtool/fitsio.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/ximtool/fitsio.c
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'vendor/x11iraf/ximtool/fitsio.c')
-rw-r--r--vendor/x11iraf/ximtool/fitsio.c923
1 files changed, 923 insertions, 0 deletions
diff --git a/vendor/x11iraf/ximtool/fitsio.c b/vendor/x11iraf/ximtool/fitsio.c
new file mode 100644
index 00000000..9bbd50c1
--- /dev/null
+++ b/vendor/x11iraf/ximtool/fitsio.c
@@ -0,0 +1,923 @@
+/*
+ * FITSIO.C -- Routines to load and save simple FITS files.
+ *
+ * ival = isFITS (fname)
+ * loadFITS (fname, pixels, w, h, r, g, b, ncolors,
+ * zsc, zr, &z1, &z2, nsample)
+ * writeFITS (fp, pixels, pixtype, w,h, r,g,b, ncolors)
+ * str = getFITSHdr (fname)
+
+ * LoadFITS(fname, numcols) - loads a FITS file
+ * WriteFITS(fp, pic, w, h, rmap, gmap, bmap, numcols)
+ *
+ * isFITS -- returns nonzero if the named file is a FITS file.
+ * loadFITS -- reads a FITS file and returns the decoded pixel array and gray-
+ * scale 8 bit colormap. The caller is responsible for freeing
+ * the pixels buffer.
+ * writeFITS -- performs the converse operation, writing the given pixel array
+ * and colormap to the output Sun rasterfile.
+ * Based on contributed FITS I/O software for XV by David Robinson.
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+
+#define NCARDS 36
+#define BLOCKSIZE 2880
+#define EPSILON 1.192e-7
+
+
+#define CONTRAST 0.25 /* zscaling parameters */
+#define NSAMPLE 1000
+
+
+/* MONO returns total intensity of r,g,b components */
+#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5) /*.33R+ .5G+ .17B*/
+
+/* data types */
+enum datatype { T_INT, T_LOG, T_REAL, T_NOVAL, T_STRING };
+
+typedef unsigned char byte;
+#ifndef AIXV3
+#ifndef OSF1
+typedef unsigned char uchar;
+#endif
+#endif
+
+typedef struct {
+ FILE *fp; /* file pointer */
+ int bitpix, size; /* bits per pixel, sizeof(unit) */
+ int naxis; /* number of axes */
+ long int axes[2]; /* size of each axis */
+ long int ndata; /* number of elements in data */
+ long int cpos; /* current position in data file */
+ char title[80]; /* image title */
+ int extend; /* image has extensions? */
+ int nextend; /* number of extensions */
+ float bscale, bzero; /* scaling parameters */
+} FITS;
+
+/* Function prototypes */
+#ifdef __STDC__
+
+#include <stddef.h>
+#include <stdlib.h>
+
+static char *ftopen2d (FITS *fs, char *file, int *nx, int *ny, int *bitpix);
+static void ftclose (FITS *fs);
+static char *ftgbyte (FITS *fs, uchar *buffer, int nelem, int zsc, int zr, float *z1, float *z2, int nsample);
+static char *rdheader (FITS *fs);
+static char *wrheader (FILE *fp, int nx, int ny);
+static char *rdcard (char *card, char *name, enum datatype dtype, long int *kvalue, float *rvalue);
+static void wrcard (char *card, char *name, enum datatype dtype, int kvalue);
+static char *ftgdata (FITS *fs, void *buffer, int nelem);
+static char *ftfixdata (FITS *fs, void *buffer, int nelem);
+#else
+static char *ftopen2d ();
+static void ftclose ();
+static char *ftgbyte ();
+static char *rdheader ();
+static char *wrheader ();
+static char *rdcard ();
+static void wrcard ();
+static char *ftgdata ();
+static char *ftfixdata ();
+#endif
+
+
+/* ----------------
+ * Public routines.
+ * ----------------*/
+
+
+/* loadFits - Load a simple FITS file.
+ */
+char *
+loadFITS (fname, pix, nx, ny, r,g,b, ncolors, zsc, zr, z1, z2, nsample)
+char *fname; /* input filename */
+uchar **pix; /* output pixels */
+int *nx, *ny; /* dimensions */
+uchar *r, *g, *b; /* colormap */
+int *ncolors; /* number of colors */
+int zsc, zr; /* z-scaling flags */
+float *z1, *z2; /* zscale values */
+int nsample; /* number of sample pts */
+
+{
+ FITS fs;
+ int i, w = 0, h = 0, bitpix, np;
+ byte *image;
+ char *error;
+
+ error = ftopen2d (&fs, fname, &w, &h, &bitpix);
+ if (error)
+ return error;
+ if (fs.extend)
+ return "Load support for MEF files\nis not currently implemented";
+
+ /* allocate memory for image and read it in */
+ np = w * h;
+ image = (byte *) malloc (np);
+ if (image == NULL)
+ return "Insufficient memory";
+
+ error = ftgbyte (&fs, image, np, zsc, zr, z1, z2, nsample);
+ ftclose (&fs);
+ if (error) {
+ free (image);
+ return error;
+ }
+
+ /* There seems to be a convention that fits files be displayed using
+ * a cartesian coordinate system. Thus the first pixel is in the lower
+ * left corner. Fix this by reflecting in the line y=h/2.
+ */
+ flip (image, w, h);
+
+ /* sucess ! */
+ *pix = (unsigned char *) image;
+ *nx = w;
+ *ny = h;
+ *ncolors = 256;
+ for (i = 0; i < 256; i++)
+ r[i] = g[i] = b[i] = i;
+
+ return NULL;
+}
+
+
+/* writeFITS -- Write the current frame buffer out as a FITS image.
+ */
+
+char *
+writeFITS (fp, image, w, h, rmap, gmap, bmap, numcols)
+FILE *fp;
+byte *image;
+int w, h;
+byte *rmap, *gmap, *bmap;
+int numcols;
+{
+ register int i, j, np, nend;
+ register byte *ptr;
+ char *error;
+ byte rgb[256];
+
+ error = wrheader(fp, w, h);
+ if (error != NULL)
+ return error;
+
+ for (i = 0; i < numcols; i++)
+ rgb[i] = MONO(rmap[i], gmap[i], bmap[i]);
+
+ /* flip line ordering when writing out */
+ for (i = h - 1; i >= 0; i--) {
+ ptr = &image[i*w];
+ for (j = 0; j < w; j++, ptr++)
+ putc(rgb[*ptr], fp);
+ }
+
+ np = w * h;
+ /* nend is the number of padding characters at the end of the last
+ * block.
+ */
+ nend = ((np + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE - np;
+
+ if (nend)
+ for (i = 0; i < nend; i++)
+ putc('\0', fp);
+
+ return NULL;
+}
+
+
+/* IsFITS -- Test a file to see if it is a FITS file.
+ */
+int
+isFITS (fname)
+char *fname; /* input filename */
+{
+ register FILE *fp;
+ int value = 0;
+ char keyw[8], val;
+
+ if (fp = fopen (fname, "r")) {
+ fscanf (fp, "%6s = %c", keyw, &val);
+ if (strcmp ("SIMPLE", keyw) == 0 && val == 'T')
+ value = 1;
+ fclose (fp);
+ }
+ return value;
+}
+
+
+/* getFITSHdr -- Get some set of header information for the GUI.
+ */
+
+char *
+getFITSHdr (fname)
+char *fname;
+{
+ FITS fs;
+ char *error, *title, *line;
+ int w, h, bitpix;
+
+ line = (char *) malloc (80);
+
+ error = ftopen2d (&fs, fname, &w, &h, &bitpix);
+ if (error) {
+ strcpy (line, error);
+ return (line);
+ }
+
+ if (fs.extend) {
+ sprintf (line, "%-16.16s %3d (%2d extns) %s",
+ fname, bitpix, fs.nextend, fs.title);
+ } else {
+ sprintf (line, "%-16.16s %3d %5dx%-5d %s",
+ fname, bitpix, w,h, fs.title);
+ }
+
+ ftclose (&fs);
+
+ return (line);
+}
+
+
+
+/*
+ * Private Procedures
+ * ------------------
+ */
+
+/* Writes a minimalist FITS file header */
+static char
+*wrheader (fp, nx, ny)
+FILE *fp;
+int nx, ny;
+{
+ char *block;
+ int i;
+
+ block = (char *) malloc (BLOCKSIZE);
+ if (block == NULL)
+ return "Insufficient memory for workspace";
+ memset(block, ' ', BLOCKSIZE);
+
+ i = 0;
+ wrcard(&block[80*i++], "SIMPLE", T_LOG, 1); /* SIMPLE keyword */
+ wrcard(&block[80*i++], "BITPIX", T_INT, 8); /* BITPIX keyword */
+ wrcard(&block[80*i++], "NAXIS", T_INT, 2); /* NAXIS keyword */
+ wrcard(&block[80*i++], "NAXIS1", T_INT, nx); /* NAXIS1 keyword */
+ wrcard(&block[80*i++], "NAXIS2", T_INT, ny); /* NAXIS2 keyword */
+ wrcard(&block[80*i++], "END", T_NOVAL, 0); /* END keyword */
+ i = fwrite(block, sizeof(char), BLOCKSIZE, fp);
+ if (i != BLOCKSIZE)
+ return "Error writing FITS file";
+ return NULL;
+}
+
+
+/* open a 2-dimensional fits file.
+ * Stores the dimensions of the file in nx and ny, and updates the FITS
+ * structure passed in fs.
+ * If successful, returns NULL otherwise returns an error message.
+ * Will return an error message if the primary data unit is not a 2-dimensional
+ * array.
+ */
+static char
+*ftopen2d(fs, file, nx, ny, bitpix)
+FITS *fs;
+char *file;
+int *nx, *ny, *bitpix;
+{
+ FILE *fp;
+ int naxis, i;
+ char *error;
+
+ fp = fopen(file, "rb");
+ if (fp == NULL)
+ return "Unable to open FITS file";
+
+ fs->fp = fp;
+ fs->bitpix = 0;
+ fs->naxis = 0;
+ fs->cpos = 0;
+
+ /* read header */
+ error = rdheader(fs);
+
+ if (error != NULL) {
+ ftclose(fs);
+ return error;
+ }
+
+ /* get number of data */
+ fs->ndata = 1;
+ for (i = 0; i < fs->naxis; i++)
+ fs->ndata = fs->ndata * fs->axes[i];
+
+ naxis = fs->naxis;
+
+ *nx = fs->axes[0];
+ *ny = fs->axes[1];
+ *bitpix = fs->bitpix;
+
+ return error;
+}
+
+
+/* closes a fits file */
+static void
+ftclose (fs)
+FITS *fs;
+{
+ if (fs == NULL)
+ return;
+ if (fs->fp != NULL)
+ fclose(fs->fp);
+}
+
+
+/* reads the fits header, and updates the FITS structure fs.
+ * Returns NULL on success, or an error message otherwise.
+ */
+static char *
+rdheader (fs)
+FITS *fs;
+{
+ int i, j, res;
+ char name[9];
+ char *block;
+ char *error;
+ long int val; /* the value */
+ float rval; /* floating point value */
+
+ block = (char *) malloc(BLOCKSIZE);
+ if (block == NULL)
+ return "Insufficient memory for workspace";
+
+ res = fread(block, sizeof(char), BLOCKSIZE, fs->fp);
+ if (res != BLOCKSIZE)
+ return "Error reading FITS file";
+ i = 0;
+
+ /* read SIMPLE key */
+ error = rdcard(block, "SIMPLE", T_LOG, &val, &rval);
+ if (error != NULL)
+ return error;
+ /*
+ if (val == 0)
+ return "Not a SIMPLE FITS file";
+ */
+ i++;
+
+ /* read BITPIX key */
+ error = rdcard(&block[80], "BITPIX", T_INT, &val, &rval);
+ if (error != NULL)
+ return error;
+ if (val != 8 && val != 16 && val != 32 && val != 64 && val != -32 &&
+ val != -64)
+ return "Bad BITPIX value in FITS file";
+ fs->bitpix = val;
+ j = fs->bitpix;
+ if (j < 0)
+ j = -j;
+ fs->size = j / 8;
+ i++;
+
+ /* read NAXIS key */
+ error = rdcard(&block[2*80], "NAXIS", T_INT, &val, &rval);
+ if (error != NULL)
+ return error;
+ if (val < 0 || val > 999)
+ return "Bad NAXIS value in FITS file";
+ if (val == 1 || val > 2)
+ return "FITS file is not a two-dimensional image";
+ fs->naxis = val;
+ i++;
+
+ /* Check for an EXTEND/NEXTEND keyword pair. */
+ error = rdcard(&block[3*80], "EXTEND", T_LOG, &val, &rval);
+ if (error == NULL) {
+ fs->extend = val; i++;
+ } else
+ fs->extend = 0;
+ error = rdcard(&block[4*80], "NEXTEND", T_INT, &val, &rval);
+ if (error == NULL) {
+ fs->nextend = val; i++;
+ } else
+ fs->nextend = 0;
+
+
+ /* read NAXISnnn keys.
+ * We allow NAXIS to be > 2 iff the dimensions of the extra axes are 1
+ */
+ for (j = 0; j < fs->naxis; j++) {
+ if (i == NCARDS) {
+ res = fread(block, sizeof(char), BLOCKSIZE, fs->fp);
+ if (res != BLOCKSIZE)
+ return "Error reading FITS file";
+ i = 0;
+ }
+
+ sprintf(name, "NAXIS%d", j + 1);
+ error = rdcard(&block[i*80], name, T_INT, &val, &rval);
+ if (error != NULL)
+ return error;
+ if (val < 0)
+ return "Bad NAXISn value in FITS file";
+ if (j < 2)
+ fs->axes[j] = val;
+ else if (val != 1)
+ return "FITS file is not a two-dimensional image";
+ i++;
+ }
+ fs->naxis = 2;
+
+ /* do remainder */
+ fs->bscale = 1.0;
+ fs->bzero = 0.0;
+ memset(fs->title, '\0', 80);
+ strcpy (fs->title, "No Title");
+ for (; ; ) {
+
+ if (block[i*80] == 'B') {
+ /* Try reading a BSCALE or BZERO keyword from this card. */
+ error = rdcard(&block[i*80], "BSCALE", T_REAL, &val, &rval);
+ if (error == NULL)
+ fs->bscale = rval;
+ error = rdcard(&block[i*80], "BZERO", T_REAL, &val, &rval);
+ if (error == NULL)
+ fs->bzero = rval;
+ }
+
+ if (i == NCARDS) {
+ res = fread(block, sizeof(char), BLOCKSIZE, fs->fp);
+ if (res != BLOCKSIZE)
+ return "Unexpected eof in FITS file";
+ i = 0;
+ }
+
+ if (strncmp(&block[i*80], "OBJECT ", 8) == 0) {
+ char *ip = &block[i*80];
+ int i = 0, j = 0;
+
+ /* Skip ahead to opening quote. */
+ while (*ip != '\'' && i < 80) ip++, i++;
+ ip++, i++;
+ for (j=0; j < 80 && *ip != '\''; j++) {
+ fs->title[j] = *ip;
+ ip++;
+ }
+ fs->title[j] = '\0';
+ }
+
+ if (strncmp(&block[i*80], "END ", 8) == 0)
+ break;
+ i++;
+ }
+ free(block);
+ return NULL;
+}
+
+
+/* write a header record into the 80 byte buffer card.
+ * The keyword name is passed in name. The value type is in dtype; this
+ * can have the following values:
+ * dtype = T_NOVAL
+ * no keyword value is written
+ * dtype = T_LOG
+ * a logical value, either 'T' or 'F' in column 30 is written
+ * dtype = T_INT
+ * an integer is written, right justified in columns 11-30
+ */
+static void
+wrcard (card, name, dtype, kvalue)
+char *card, *name;
+enum datatype dtype; /* type of value */
+int kvalue;
+{
+ int l;
+ memset(card, ' ', 80);
+ l = strlen(name);
+ if (l)
+ memcpy(card, name, l); /* copy name */
+
+ if (dtype == T_NOVAL)
+ return;
+
+ card[8] = '=';
+
+ if (dtype == T_LOG)
+ card[29] = kvalue ? 'T' : 'F';
+ else /* an integer */ {
+ sprintf(&card[10], "%20d", kvalue);
+ card[30] = ' ';
+ }
+
+}
+
+
+/* Read a header record, from the 80 byte buffer card.
+ * the keyword name must match 'name'; and parse its value according to
+ * dtype. This can have the following values:
+ * dtype = T_LOG
+ * value is logical, either 'T' or 'F' in column 30.
+ * dtype = T_INT
+ * value is an integer, right justified in columns 11-30.
+ * dtype = T_REAL
+ * value is a real
+ *
+ * The value is stored in kvalue.
+ * It returns NULL on success, or an error message otherwise.
+ */
+static char *
+rdcard (card, name, dtype, kvalue, rvalue)
+char *card, *name;
+enum datatype dtype; /* type of value */
+long int *kvalue;
+float *rvalue;
+{
+ int i, ptr;
+ char namestr[9];
+ static char error[45];
+
+ memcpy(namestr, card, 8);
+ i = 8;
+ do
+ i--;
+ while (i >= 0 && namestr[i] == ' ');
+ namestr[i+1] = '\0';
+
+ if (strcmp(namestr, name) != 0) {
+ sprintf(error, "Keyword %s not found in FITS file", name);
+ return error;
+ }
+
+ /* get start of value */
+ ptr = 10;
+ while (ptr < 80 && card[ptr] == ' ')
+ ptr++;
+ if (ptr == 80 || card[ptr] == '/')
+ return "FITS file has missing keyword value"; /* no value */
+
+ if (dtype == T_LOG) {
+ if ((card[ptr] != 'T' && card[ptr] != 'F'))
+ return "Keyword has bad logical value in FITS file";
+ *kvalue = (card[ptr] == 'T');
+
+ } else /* an integer or real */ {
+ int j, end;
+ long int ival;
+ float fval;
+ char num[21];
+
+ /*
+ if (ptr > 29)
+ return "Keyword has bad integer value in FITS file";
+ */
+ end = ptr;
+ while (end < 80 && (card[end] != ' ' && card[end] != '/'))
+ end++;
+ memcpy(num, &card[ptr], end - ptr);
+ num[end-ptr] = '\0';
+ if (dtype == T_INT) {
+ j = sscanf(num, "%ld", &ival);
+ if (j != 1)
+ return "Keyword has bad integer value in FITS file";
+ *kvalue = ival;
+ *rvalue = 0.0;
+ } else if (dtype == T_REAL) {
+ j = sscanf(num, "%g", &fval);
+ if (j != 1)
+ return "Keyword has bad real value in FITS file";
+ *kvalue = 0;
+ *rvalue = fval;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* reads nelem values into the buffer.
+ * returns NULL for success or an error message.
+ * Copes with the fact that the last 2880 byte record of the FITS file
+ * may be truncated, and should be padded out with zeros.
+ */
+static char *
+ftgdata (fs, buffer, nelem)
+FITS *fs;
+void *buffer;
+int nelem;
+{
+ int res;
+
+ if (nelem == 0)
+ return NULL;
+
+ res = fread(buffer, fs->size, nelem, fs->fp);
+ /* if failed to read all the data */
+ if (res != nelem) {
+ /* nblock is the number of elements in a record. size is
+ * always a factor of BLOCKSIZE */
+ int loffs, nblock = BLOCKSIZE / fs->size;
+
+ if (!feof(fs->fp))
+ return "I/O error reading FITS file";
+
+ /* The last record might be short; check this.
+ * loffs is the offset of the start of the last record from
+ * the current position.
+ */
+ loffs = ((fs->ndata + nblock - 1) / nblock - 1) * nblock - fs->cpos;
+
+ /* if we didn't read to the end of the penultimate record */
+ if (res < loffs)
+ return "Unexpected EOF reading FITS file";
+
+ /* pad with zeros */
+ memset((char *)buffer + res * fs->size, '\0',
+ (nelem - res) * fs->size);
+ }
+ fs->cpos += res;
+ return ftfixdata(fs, buffer, nelem);
+}
+
+
+/* convert the raw data, as stored in the FITS file, to the format
+ * appropiate for the data representation of the host computer.
+ * Assumes that
+ * short int = 2 byte integer
+ * int = 4 byte integer
+ */
+static char *
+ftfixdata (fs, buffer, nelem)
+FITS *fs;
+void *buffer;
+int nelem;
+{
+ register int i, n = nelem;
+ register uchar *ptr = buffer;
+
+ /* conversions. Although the data may be signed, reverse using unsigned
+ * variables. Convert from big-endian two-byte signed integer to
+ * native form
+ */
+ if (fs->bitpix == 16)
+ for (i = 0; i < n; i++, ptr += 2)
+ *(unsigned short int *)ptr = (((int)*ptr) << 8) | (int)(ptr[1]);
+
+ /* convert from big-endian four-byte signed integer to native form */
+ else if (fs->bitpix == 32)
+ for (i = 0; i < n; i++, ptr += 4)
+ *(unsigned int *)ptr = (((unsigned int)*ptr) << 24) |
+ ((unsigned int)ptr[1] << 16) |
+ ((unsigned int)ptr[2] << 8) |
+ (unsigned int)ptr[3];
+
+ /* convert from IEE 754 single precision to native form */
+ else if (fs->bitpix == -32) {
+ register int j, k, expo;
+ static float *exps = NULL;
+
+ if (exps == NULL) {
+ exps = (float *)calloc(256, sizeof(float));
+ if (exps == NULL)
+ return "Insufficient memory for workspace";
+ exps[150] = 1.;
+ for (i = 151; i < 256; i++)
+ exps[i] = 2. * exps[i-1];
+ for (i = 149; i >= 0; i--)
+ exps[i] = 0.5 * exps[i+1];
+ }
+
+
+ for (i = 0; i < n; i++, ptr += 4) {
+ k = (int)*ptr;
+ j = ((int)ptr[1] << 16) | ((int)ptr[2] << 8) | (int)ptr[3];
+ expo = ((k & 127) << 1) | (j >> 23);
+ if ((expo | j) == 0)
+ *(float *)ptr = 0.;
+ else
+ *(float *)ptr = exps[expo] * (float)(j | 0x800000);
+ if (k & 128)
+ *(float *)ptr = -*(float *)ptr;
+ }
+
+ /* convert from IEE 754 double precision to native form */
+ } else if (fs->bitpix == -64) {
+ register int expo, k, l;
+ register unsigned int j;
+ static double *exps = NULL;
+
+ if (exps == NULL) {
+ exps = (double *)calloc(2048, sizeof(double));
+ if (exps == NULL)
+ return "Insufficient memory for workspace";
+ exps[1075] = 1.;
+ for (i = 1076; i < 2048; i++)
+ exps[i] = 2. * exps[i-1];
+ for (i = 1074; i >= 0; i--)
+ exps[i] = 0.5 * exps[i+1];
+ }
+
+ for (i = 0; i < n; i++, ptr += 8) {
+ k = (int)*ptr;
+ j = ((unsigned int)ptr[1] << 24) | ((unsigned int)ptr[2] << 16) |
+ ((unsigned int)ptr[3] << 8) | (unsigned int)ptr[4];
+ l = ((int)ptr[5] << 16) | ((int)ptr[6] << 8) | (int)ptr[7];
+ expo = ((k & 127) << 4) | (j >> 28);
+ if ((expo | j | l) == 0)
+ *(double *)ptr = 0.;
+ else
+ *(double *)ptr = exps[expo] * (16777216. *
+ (double)((j & 0x0FFFFFFF) | 0x10000000) + (double)l);
+ if (k & 128)
+ *(double *)ptr = -*(double *)ptr;
+ }
+ }
+ return NULL;
+}
+
+
+#undef max
+#define f_max(a,b) ((a) > (b) ? (a) : (b))
+#undef min
+#define f_min(a,b) ((a) < (b) ? (a) : (b))
+
+
+/* Reads a byte image from the FITS file fs. The image contains nelem pixels.
+ * If bitpix = 8, then the image is loaded as stored in the file if not scaled.
+ * Otherwise, it is rescaled so that the minimum value is stored as 0, and
+ * the maximum is stored as 255
+ */
+static char *
+ftgbyte(fs, cbuff, nelem, zsc, zr, z1, z2, nsample)
+FITS *fs;
+uchar *cbuff;
+int nelem;
+int zsc, zr;
+float *z1, *z2;
+int nsample;
+{
+ char * voidbuff;
+ register int i, n = nelem;
+ char *error;
+ int pmin = 0, pmax = 255;
+ int npts, stdline;
+ extern void zscale();
+
+ /* if the data is uchar, then read it directly */
+ if (fs->bitpix == 8 && (fs->bscale == 1.0 && fs->bzero == 0.0)) {
+ *z1 = 0.0;
+ *z2 = 255.0;
+ return ftgdata(fs, cbuff, nelem);
+ }
+
+ /* allocate a buffer to store the image */
+ if (fabs((double)fs->bscale-1.0) > EPSILON ||
+ fabs((double)fs->bzero) > EPSILON)
+ voidbuff = (char * )malloc(nelem * f_max(fs->size,4));
+ else
+ voidbuff = (char * )malloc(nelem * fs->size);
+ if (voidbuff == NULL)
+ return "Insufficient memory for workspace";
+ error = ftgdata(fs, voidbuff, nelem);
+ if (error != NULL) {
+ printf ("ftgbyte: %s\n", error);
+ return error;
+ }
+
+ /* If we've got BSCALE/BZERO values compute the original pixel values
+ * and convert the buffer to floating point before processing it.
+ * The voidbuff was allocated above with this in mind so it should be
+ * large enough that we can fix the pixels in place.
+ */
+
+ npts = fs->axes[0] * fs->axes[1];
+ stdline = (int)((float)fs->axes[1] / sqrt((float)npts/(float)nsample));
+ if (fs->bscale != 1.0 || fs->bzero != 0.0) {
+ register float *buf;
+
+ buf = (float *)voidbuff;
+
+ if (fs->bitpix == 8) {
+ for (i=(nelem-1); i >= 0; i--)
+ buf[i] = (float) voidbuff[i] * fs->bscale + fs->bzero;
+ } else if (fs->bitpix == 16) {
+ register short *old;
+ for (i=(nelem-1); i >= 0; i--) {
+ old = (short *) &voidbuff[i * 2];
+ buf[i] = (float) *old * fs->bscale + fs->bzero;
+ }
+ } else if (fs->bitpix == 32) {
+ register int *old;
+ for (i=(nelem-1); i >= 0; i--) {
+ old = (int *) &voidbuff[i * 4];
+ buf[i] = (float) *old * fs->bscale + fs->bzero;
+ }
+ } else if (fs->bitpix == -32) {
+ register float *old;
+ for (i=(nelem-1); i >= 0; i--) {
+ old = (float *) &voidbuff[i * 4];
+ buf[i] = (float) *old * fs->bscale + fs->bzero;
+ }
+ } else if (fs->bitpix == -64) {
+ register double *old, *dbuf;
+ register float *fpix;
+
+ dbuf = (double *) malloc (nelem * sizeof(double));
+ for (i=(nelem-1); i >= 0; i--) {
+ old = (double *) &voidbuff[i * 8];
+ dbuf[i] = (float) *old * fs->bscale + fs->bzero;
+ }
+ fpix = (float *) voidbuff;
+ for (i=0; i<nelem; i++)
+ buf[i] = fpix[i] = (float) dbuf[i];
+ free ((double *) dbuf);
+ }
+
+ fs->size = 4;
+ fs->bitpix = -32;
+
+ /* compute the optimal zscale values */
+ if (zsc)
+ zscale ((char *)buf, fs->axes[0], fs->axes[1], fs->bitpix,
+ z1, z2, CONTRAST, nsample, stdline);
+ else if (zr)
+ min_max ((float *)buf, nelem, fs->bitpix, z1, z2);
+
+ } else {
+ /* compute the optimal zscale values */
+ if (zsc)
+ zscale (voidbuff, fs->axes[0], fs->axes[1], fs->bitpix,
+ z1, z2, CONTRAST, nsample, stdline);
+ else if (zr)
+ min_max ((float *)voidbuff, nelem, fs->bitpix, z1, z2);
+ }
+
+ /* convert short int to uchar */
+ if (fs->bitpix == 16) {
+ register short int *buffer = (short *)voidbuff;
+ register int max, min;
+ register float scale;
+
+ min = (int) *z1;
+ max = (int) *z2;
+ scale = (max == min) ? 0. : 255. / (*z2 -*z1);
+
+ /* rescale and convert */
+ for (i = 0, buffer = (short *)voidbuff; i < n; i++)
+ cbuff[i] = f_max (pmin, f_min (pmax,
+ (int)(scale * (float)((int)buffer[i] - min)) ));
+
+ /* convert long int to uchar */
+ } else if (fs->bitpix == 32) {
+ register int *buffer = (int *)voidbuff;
+ register int max, min;
+ register float scale;
+
+ min = (int) *z1;
+ max = (int) *z2;
+ scale = (max == min) ? 0. : 255. / (*z2 - *z1);
+
+ /* rescale and convert */
+ for (i = 0, buffer = (int *)voidbuff; i < n; i++)
+ cbuff[i] = f_max (pmin, f_min (pmax,
+ (int)(scale * (float)((int)buffer[i] - min)) ));
+
+ /* convert float to uchar */
+ } else if (fs->bitpix == -32) {
+ register float *buffer = (float *)voidbuff;
+ register float max, min, scale;
+
+ min = *z1;
+ max = *z2;
+ scale = (max == min) ? 0. : 255. / (*z2 - *z1);
+
+ /* rescale and convert */
+ for (i = 0, buffer = (float *)voidbuff; i < n; i++)
+ cbuff[i] = f_max (pmin, f_min (pmax,
+ (int)(scale * ((float)buffer[i] - min)) ));
+
+ /* convert double to uchar */
+ } else if (fs->bitpix == -64) {
+ register double *buffer = (double *)voidbuff;
+ register double max, min, scale;
+
+ min = (double) *z1;
+ max = (double) *z2;
+ scale = (max == min) ? 0. : 255. / (*z2 - *z1);
+
+ /* rescale and convert */
+ for (i = 0, buffer = (double *)voidbuff; i < n; i++)
+ cbuff[i] = f_max (pmin, f_min (pmax,
+ (int)(scale * ((double)buffer[i] - min)) ));
+ }
+
+ free( (char *)voidbuff);
+ return NULL;
+}