Exemple #1
0
void __fastcall TForm1::BGuardarClick(TObject *Sender)
{
  fitsfile *fptr;       /* pointer to the FITS file, defined in fitsio.h */
  int status;
  AnsiString N;

  ejex = X2;
  ejey = Y2;
  long n = X2*Y2;
  if(SD1->Execute())
  {
    status = 0;
    N = SD1->FileName + ".fit";
    if(ffinit(&fptr, N.c_str(), &status))
    {
      printerror( status );
      status = 0;
      if ( fits_open_file(&fptr, N.c_str(), READWRITE, &status) )
      {
         printerror(status);
        return;
      }
    }
  }
  else
    return;

  long axes[2];
  axes[0] = ejex;
  axes[1] = ejey;
  if(ffcrim(fptr, 16, 2, axes, &status))
  {
    printerror(status);
    return;
  }

  unsigned short *datos;

  datos = new unsigned short [ejex*ejey];
  memset(datos, 0, ejex*ejey*2);
  for(int py = 0; py < ejey; py++)
  {
    for (int px = ejex; px > 0; px--)
    {
      datos[n--] = Foto[py][px];
    }
  }

  status = 0;
  if(fits_write_img(fptr, TSHORT, 1, ejex*ejey, datos, &status))
  {
    printerror( status );
  }
  delete datos;
  return;
}
Exemple #2
0
// ffhist3: same as ffhist2, but does not close the original file,
// and/or replace the original file pointer 
fitsfile *ffhist3(fitsfile *fptr, /* I - ptr to table with X and Y cols*/
           char *outfile,    /* I - name for the output histogram file      */
           int imagetype,    /* I - datatype for image: TINT, TSHORT, etc   */
           int naxis,        /* I - number of axes in the histogram image   */
           char colname[4][FLEN_VALUE],   /* I - column names               */
           double *minin,     /* I - minimum histogram value, for each axis */
           double *maxin,     /* I - maximum histogram value, for each axis */
           double *binsizein, /* I - bin size along each axis               */
           char minname[4][FLEN_VALUE], /* I - optional keywords for min    */
           char maxname[4][FLEN_VALUE], /* I - optional keywords for max    */
           char binname[4][FLEN_VALUE], /* I - optional keywords for binsize */
           double weightin,        /* I - binning weighting factor          */
           char wtcol[FLEN_VALUE], /* I - optional keyword or col for weight*/
           int recip,              /* I - use reciprocal of the weight?     */
           char *selectrow,        /* I - optional array (length = no. of   */
                             /* rows in the table).  If the element is true */
                             /* then the corresponding row of the table will*/
                             /* be included in the histogram, otherwise the */
                             /* row will be skipped.  Ingnored if *selectrow*/
                             /* is equal to NULL.                           */
           int *status)
{
    fitsfile *histptr;
    int   bitpix, colnum[4], wtcolnum;
    long haxes[4];
    float amin[4], amax[4], binsize[4],  weight;

    if (*status > 0)
        return(NULL);

    if (naxis > 4)
    {
        ffpmsg("histogram has more than 4 dimensions");
	*status = BAD_DIMEN;
        return(NULL);
    }

    /* reset position to the correct HDU if necessary */
    if ((fptr)->HDUposition != ((fptr)->Fptr)->curhdu)
        ffmahd(fptr, ((fptr)->HDUposition) + 1, NULL, status);

    if (imagetype == TBYTE)
        bitpix = BYTE_IMG;
    else if (imagetype == TSHORT)
        bitpix = SHORT_IMG;
    else if (imagetype == TINT)
        bitpix = LONG_IMG;
    else if (imagetype == TFLOAT)
        bitpix = FLOAT_IMG;
    else if (imagetype == TDOUBLE)
        bitpix = DOUBLE_IMG;
    else{
        *status = BAD_DATATYPE;
        return(NULL);
    }
    
    /*    Calculate the binning parameters:    */
    /*   columm numbers, axes length, min values,  max values, and binsizes.  */

    if (fits_calc_binning(
      fptr, naxis, colname, minin, maxin, binsizein, minname, maxname, binname,
      colnum, haxes, amin, amax, binsize, status) > 0)
    {
       ffpmsg("failed to determine binning parameters");
        return(NULL);
    }
 
    /* get the histogramming weighting factor, if any */
    if (*wtcol)
    {
        /* first, look for a keyword with the weight value */
        if (fits_read_key(fptr, TFLOAT, wtcol, &weight, NULL, status) )
        {
            /* not a keyword, so look for column with this name */
            *status = 0;

            /* get the column number in the table */
            if (ffgcno(fptr, CASEINSEN, wtcol, &wtcolnum, status) > 0)
            {
               ffpmsg(
               "keyword or column for histogram weights doesn't exist: ");
               ffpmsg(wtcol);
               return(NULL);
            }

            weight = FLOATNULLVALUE;
        }
    }
    else
        weight = (float) weightin;

    if (weight <= 0. && weight != FLOATNULLVALUE)
    {
        ffpmsg("Illegal histogramming weighting factor <= 0.");
	*status = URL_PARSE_ERROR;
        return(NULL);
    }

    if (recip && weight != FLOATNULLVALUE)
       /* take reciprocal of weight */
       weight = (float) (1.0 / weight);

    /* size of histogram is now known, so create temp output file */
    if (fits_create_file(&histptr, outfile, status) > 0)
    {
        ffpmsg("failed to create temp output file for histogram");
        return(NULL);
    }

    /* create output FITS image HDU */
    if (ffcrim(histptr, bitpix, naxis, haxes, status) > 0)
    {
        ffpmsg("failed to create output histogram FITS image");
        return(NULL);
    }

    /* copy header keywords, converting pixel list WCS keywords to image WCS form */
    if (fits_copy_pixlist2image(fptr, histptr, 9, naxis, colnum, status) > 0)
    {
        ffpmsg("failed to copy pixel list keywords to new histogram header");
        return(NULL);
    }

    /* if the table columns have no WCS keywords, then write default keywords */
    fits_write_keys_histo(fptr, histptr, naxis, colnum, status);
    
    /* update the WCS keywords for the ref. pixel location, and pixel size */
    fits_rebin_wcs(histptr, naxis, amin, binsize,  status);      
    
    /* now compute the output image by binning the column values */
    if (fits_make_hist(fptr, histptr, bitpix, naxis, haxes, colnum, amin, amax,
        binsize, weight, wtcolnum, recip, selectrow, status) > 0)
    {
        ffpmsg("failed to calculate new histogram values");
        return(NULL);
    }
              
    return(histptr);
}
Exemple #3
0
/*--------------------------------------------------------------------------*/
int mem_rawfile_open(char *filename, int rwmode, int *hdl)
/*
  This routine creates an empty memory buffer, writes a minimal
  image header, then copies the image data from the raw file into
  memory.  It will byteswap the pixel values if the raw array
  is in little endian byte order.
*/
{
    FILE *diskfile;
    fitsfile *fptr;
    short *sptr;
    int status, endian, datatype, bytePerPix, naxis;
    long dim[5] = {1,1,1,1,1}, ii, nvals, offset = 0;
    size_t filesize = 0, datasize;
    char rootfile[FLEN_FILENAME], *cptr = 0, *cptr2 = 0;
    void *ptr;

    if (rwmode != READONLY)
    {
        ffpmsg(
  "cannot open raw binary file with WRITE access (mem_rawfile_open)");
        ffpmsg(filename);
        return(READONLY_FILE);
    }

    cptr = strchr(filename, '[');   /* search for opening bracket [ */

    if (!cptr)
    {
        ffpmsg("binary file name missing '[' character (mem_rawfile_open)");
        ffpmsg(filename);
        return(URL_PARSE_ERROR);
    }

    *rootfile = '\0';
    strncat(rootfile, filename, cptr - filename);  /* store the rootname */

    cptr++;

    while (*cptr == ' ')
       cptr++;    /* skip leading blanks */

    /* Get the Data Type of the Image */

    if (*cptr == 'b' || *cptr == 'B')
    {
      datatype = BYTE_IMG;
      bytePerPix = 1;
    }
    else if (*cptr == 'i' || *cptr == 'I')
    {
      datatype = SHORT_IMG;
      bytePerPix = 2;
    }
    else if (*cptr == 'u' || *cptr == 'U')
    {
      datatype = USHORT_IMG;
      bytePerPix = 2;

    }
    else if (*cptr == 'j' || *cptr == 'J')
    {
      datatype = LONG_IMG;
      bytePerPix = 4;
    }  
    else if (*cptr == 'r' || *cptr == 'R' || *cptr == 'f' || *cptr == 'F')
    {
      datatype = FLOAT_IMG;
      bytePerPix = 4;
    }    
    else if (*cptr == 'd' || *cptr == 'D')
    {
      datatype = DOUBLE_IMG;
      bytePerPix = 8;
    }
    else
    {
        ffpmsg("error in raw binary file datatype (mem_rawfile_open)");
        ffpmsg(filename);
        return(URL_PARSE_ERROR);
    }

    cptr++;

    /* get Endian: Big or Little; default is same as the local machine */
    
    if (*cptr == 'b' || *cptr == 'B')
    {
        endian = 0;
        cptr++;
    }
    else if (*cptr == 'l' || *cptr == 'L')
    {
        endian = 1;
        cptr++;
    }
    else
        endian = BYTESWAPPED; /* byteswapped machines are little endian */

    /* read each dimension (up to 5) */

    naxis = 1;
    dim[0] = strtol(cptr, &cptr2, 10);
    
    if (cptr2 && *cptr2 == ',')
    {
      naxis = 2;
      dim[1] = strtol(cptr2+1, &cptr, 10);

      if (cptr && *cptr == ',')
      {
        naxis = 3;
        dim[2] = strtol(cptr+1, &cptr2, 10);

        if (cptr2 && *cptr2 == ',')
        {
          naxis = 4;
          dim[3] = strtol(cptr2+1, &cptr, 10);

          if (cptr && *cptr == ',')
            naxis = 5;
            dim[4] = strtol(cptr+1, &cptr2, 10);
        }
      }
    }

    cptr = maxvalue(cptr, cptr2);

    if (*cptr == ':')   /* read starting offset value */
        offset = strtol(cptr+1, 0, 10);

    nvals = dim[0] * dim[1] * dim[2] * dim[3] * dim[4];
    datasize = nvals * bytePerPix;
    filesize = nvals * bytePerPix + 2880;
    filesize = ((filesize - 1) / 2880 + 1) * 2880; 

    /* open the raw binary disk file */
    status = file_openfile(rootfile, READONLY, &diskfile);
    if (status)
    {
        ffpmsg("failed to open raw  binary file (mem_rawfile_open)");
        ffpmsg(rootfile);
        return(status);
    }

    /* create a memory file with corrct size for the FITS converted raw file */
    status = mem_createmem(filesize, hdl);
    if (status)
    {
        ffpmsg("failed to create memory file (mem_rawfile_open)");
        fclose(diskfile);
        return(status);
    }

    /* open this piece of memory as a new FITS file */
    ffimem(&fptr, (void **) memTable[*hdl].memaddrptr, &filesize, 0, 0, &status);

    /* write the required header keywords */
    ffcrim(fptr, datatype, naxis, dim, &status);

    /* close the FITS file, but keep the memory allocated */
    ffclos(fptr, &status);

    if (status > 0)
    {
        ffpmsg("failed to write basic image header (mem_rawfile_open)");
        fclose(diskfile);
        mem_close_free(*hdl);   /* free up the memory */
        return(status);
    }

    if (offset > 0)
       fseek(diskfile, offset, 0);   /* offset to start of the data */

    /* read the raw data into memory */
    ptr = *memTable[*hdl].memaddrptr + 2880;

    if (fread((char *) ptr, 1, datasize, diskfile) != datasize)
      status = READ_ERROR;

    fclose(diskfile);  /* close the raw binary disk file */

    if (status)
    {
        mem_close_free(*hdl);   /* free up the memory */
        ffpmsg("failed to copy raw file data into memory (mem_rawfile_open)");
        return(status);
    }

    if (datatype == USHORT_IMG)  /* have to subtract 32768 from each unsigned */
    {                            /* value to conform to FITS convention. More */
                                 /* efficient way to do this is to just flip  */
                                 /* the most significant bit.                 */

      sptr = (short *) ptr;

      if (endian == BYTESWAPPED)  /* working with native format */
      {
        for (ii = 0; ii < nvals; ii++, sptr++)
        {
          *sptr =  ( *sptr ) ^ 0x8000;
        }
      }
      else  /* pixels are byteswapped WRT the native format */
      {
        for (ii = 0; ii < nvals; ii++, sptr++)
        {
          *sptr =  ( *sptr ) ^ 0x80;
        }
      }
    }

    if (endian)  /* swap the bytes if array is in little endian byte order */
    {
      if (datatype == SHORT_IMG || datatype == USHORT_IMG)
      {
        ffswap2( (short *) ptr, nvals);
      }
      else if (datatype == LONG_IMG || datatype == FLOAT_IMG)
      {
        ffswap4( (INT32BIT *) ptr, nvals);
      }

      else if (datatype == DOUBLE_IMG)
      {
        ffswap8( (double *) ptr, nvals);
      }
    }

    memTable[*hdl].currentpos = 0;           /* save starting position */
    memTable[*hdl].fitsfilesize=filesize;    /* and initial file size  */

    return(0);
}
/*--------------------------------------------------------------------------*/
int ffcphd(fitsfile *infptr,    /* I - FITS file pointer to input file  */
           fitsfile *outfptr,   /* I - FITS file pointer to output file */
           int *status)         /* IO - error status     */
/*
  copy the header keywords from infptr to outfptr.
*/
{
    int nkeys, ii, inPrim = 0, outPrim = 0;
    long naxis, naxes[1];
    char *card, comm[FLEN_COMMENT];
    char *tmpbuff;

    if (*status > 0)
        return(*status);

    if (infptr == outfptr)
        return(*status = SAME_FILE);

    /* set the input pointer to the correct HDU */
    if (infptr->HDUposition != (infptr->Fptr)->curhdu)
        ffmahd(infptr, (infptr->HDUposition) + 1, NULL, status);

    if (ffghsp(infptr, &nkeys, NULL, status) > 0) /* get no. of keywords */
        return(*status);

    /* create a memory buffer to hold the header records */
    tmpbuff = (char*) malloc(nkeys*FLEN_CARD*sizeof(char));
    if (!tmpbuff)
        return(*status = MEMORY_ALLOCATION);

    /* read all of the header records in the input HDU */
    for (ii = 0; ii < nkeys; ii++)
      ffgrec(infptr, ii+1, tmpbuff + (ii * FLEN_CARD), status);

    if (infptr->HDUposition == 0)  /* set flag if this is the Primary HDU */
       inPrim = 1;

    /* if input is an image hdu, get the number of axes */
    naxis = -1;   /* negative if HDU is a table */
    if ((infptr->Fptr)->hdutype == IMAGE_HDU)
        ffgkyj(infptr, "NAXIS", &naxis, NULL, status);

    /* set the output pointer to the correct HDU */
    if (outfptr->HDUposition != (outfptr->Fptr)->curhdu)
        ffmahd(outfptr, (outfptr->HDUposition) + 1, NULL, status);

    /* check if output header is empty; if not create new empty HDU */
    if ((outfptr->Fptr)->headend !=
        (outfptr->Fptr)->headstart[(outfptr->Fptr)->curhdu] )
           ffcrhd(outfptr, status);   

    if (outfptr->HDUposition == 0)
    {
        if (naxis < 0)
        {
            /* the input HDU is a table, so we have to create */
            /* a dummy Primary array before copying it to the output */
            ffcrim(outfptr, 8, 0, naxes, status);
            ffcrhd(outfptr, status); /* create new empty HDU */
        }
        else
        {
            /* set flag that this is the Primary HDU */
            outPrim = 1;
        }
    }

    if (*status > 0)  /* check for errors before proceeding */
    {
        free(tmpbuff);
        return(*status);
    }
    if ( inPrim == 1 && outPrim == 0 )
    {
        /* copying from primary array to image extension */
        strcpy(comm, "IMAGE extension");
        ffpkys(outfptr, "XTENSION", "IMAGE", comm, status);

        /* copy BITPIX through NAXISn keywords */
        for (ii = 1; ii < 3 + naxis; ii++)
        {
            card = tmpbuff + (ii * FLEN_CARD);
            ffprec(outfptr, card, status);
        }

        strcpy(comm, "number of random group parameters");
        ffpkyj(outfptr, "PCOUNT", 0, comm, status);
  
        strcpy(comm, "number of random groups");
        ffpkyj(outfptr, "GCOUNT", 1, comm, status);


        /* copy remaining keywords, excluding EXTEND, and reference COMMENT keywords */
        for (ii = 3 + naxis ; ii < nkeys; ii++)
        {
            card = tmpbuff+(ii * FLEN_CARD);
            if (FSTRNCMP(card, "EXTEND  ", 8) &&
                FSTRNCMP(card, "COMMENT   FITS (Flexible Image Transport System) format is", 58) && 
                FSTRNCMP(card, "COMMENT   and Astrophysics', volume 376, page 3", 47) )
            {
                 ffprec(outfptr, card, status);
            }
        }
    }
    else if ( inPrim == 0 && outPrim == 1 )
    {
        /* copying between image extension and primary array */
        strcpy(comm, "file does conform to FITS standard");
        ffpkyl(outfptr, "SIMPLE", TRUE, comm, status);

        /* copy BITPIX through NAXISn keywords */
        for (ii = 1; ii < 3 + naxis; ii++)
        {
            card = tmpbuff + (ii * FLEN_CARD);
            ffprec(outfptr, card, status);
        }

        /* add the EXTEND keyword */
        strcpy(comm, "FITS dataset may contain extensions");
        ffpkyl(outfptr, "EXTEND", TRUE, comm, status);

      /* write standard block of self-documentating comments */
      ffprec(outfptr,
      "COMMENT   FITS (Flexible Image Transport System) format is defined in 'Astronomy",
      status);
      ffprec(outfptr,
      "COMMENT   and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H",
      status);

        /* copy remaining keywords, excluding pcount, gcount */
        for (ii = 3 + naxis; ii < nkeys; ii++)
        {
            card = tmpbuff+(ii * FLEN_CARD);
            if (FSTRNCMP(card, "PCOUNT  ", 8) && FSTRNCMP(card, "GCOUNT  ", 8))
            {
                 ffprec(outfptr, card, status);
            }
        }
    }
    else
    {
        /* input and output HDUs are same type; simply copy all keywords */
        for (ii = 0; ii < nkeys; ii++)
        {
            card = tmpbuff+(ii * FLEN_CARD);
            ffprec(outfptr, card, status);
        }
    }

    free(tmpbuff);
    return(*status);
}
Exemple #5
0
/*--------------------------------------------------------------------------*/
int ffhist(fitsfile **fptr,  /* IO - pointer to table with X and Y cols;    */
                             /*     on output, points to histogram image    */
           char *outfile,    /* I - name for the output histogram file      */
           int imagetype,    /* I - datatype for image: TINT, TSHORT, etc   */
           int naxis,        /* I - number of axes in the histogram image   */
           char colname[4][FLEN_VALUE],   /* I - column names               */
           double *minin,     /* I - minimum histogram value, for each axis */
           double *maxin,     /* I - maximum histogram value, for each axis */
           double *binsizein, /* I - bin size along each axis               */
           char minname[4][FLEN_VALUE], /* I - optional keywords for min    */
           char maxname[4][FLEN_VALUE], /* I - optional keywords for max    */
           char binname[4][FLEN_VALUE], /* I - optional keywords for binsize */
           double weightin,        /* I - binning weighting factor          */
           char wtcol[FLEN_VALUE], /* I - optional keyword or col for weight*/
           int recip,              /* I - use reciprocal of the weight?     */
           char *selectrow,        /* I - optional array (length = no. of   */
                             /* rows in the table).  If the element is true */
                             /* then the corresponding row of the table will*/
                             /* be included in the histogram, otherwise the */
                             /* row will be skipped.  Ingnored if *selectrow*/
                             /* is equal to NULL.                           */
           int *status)
{
    int ii, datatype, repeat, imin, imax, ibin, bitpix, tstatus, use_datamax = 0;
    long haxes[4];
    fitsfile *histptr;
    char errmsg[FLEN_ERRMSG], keyname[FLEN_KEYWORD], card[FLEN_CARD];
    tcolumn *colptr;
    iteratorCol imagepars[1];
    int n_cols = 1, nkeys;
    long  offset = 0;
    long n_per_loop = -1;  /* force whole array to be passed at one time */
    histType histData;    /* Structure holding histogram info for iterator */
    
    float amin[4], amax[4], binsize[4], maxbin[4];
    float datamin = FLOATNULLVALUE, datamax = FLOATNULLVALUE;
    char svalue[FLEN_VALUE];
    double dvalue;
    char cpref[4][FLEN_VALUE];
    char *cptr;

    if (*status > 0)
        return(*status);

    if (naxis > 4)
    {
        ffpmsg("histogram has more than 4 dimensions");
        return(*status = BAD_DIMEN);
    }

    /* reset position to the correct HDU if necessary */
    if ((*fptr)->HDUposition != ((*fptr)->Fptr)->curhdu)
        ffmahd(*fptr, ((*fptr)->HDUposition) + 1, NULL, status);

    histData.tblptr     = *fptr;
    histData.himagetype = imagetype;
    histData.haxis      = naxis;
    histData.rowselector = selectrow;

    if (imagetype == TBYTE)
        bitpix = BYTE_IMG;
    else if (imagetype == TSHORT)
        bitpix = SHORT_IMG;
    else if (imagetype == TINT)
        bitpix = LONG_IMG;
    else if (imagetype == TFLOAT)
        bitpix = FLOAT_IMG;
    else if (imagetype == TDOUBLE)
        bitpix = DOUBLE_IMG;
    else
        return(*status = BAD_DATATYPE);

    /* The CPREF keyword, if it exists, gives the preferred columns. */
    /* Otherwise, assume "X", "Y", "Z", and "T"  */

    tstatus = 0;
    ffgky(*fptr, TSTRING, "CPREF", cpref[0], NULL, &tstatus);

    if (!tstatus)
    {
        /* Preferred column names are given;  separate them */
        cptr = cpref[0];

        /* the first preferred axis... */
        while (*cptr != ',' && *cptr != '\0')
           cptr++;

        if (*cptr != '\0')
        {
           *cptr = '\0';
           cptr++;
           while (*cptr == ' ')
               cptr++;

           strcpy(cpref[1], cptr);
           cptr = cpref[1];

          /* the second preferred axis... */
          while (*cptr != ',' && *cptr != '\0')
             cptr++;

          if (*cptr != '\0')
          {
             *cptr = '\0';
             cptr++;
             while (*cptr == ' ')
                 cptr++;

             strcpy(cpref[2], cptr);
             cptr = cpref[2];

            /* the third preferred axis... */
            while (*cptr != ',' && *cptr != '\0')
               cptr++;

            if (*cptr != '\0')
            {
               *cptr = '\0';
               cptr++;
               while (*cptr == ' ')
                   cptr++;

               strcpy(cpref[3], cptr);

            }
          }
        }
    }

    for (ii = 0; ii < naxis; ii++)
    {

      /* get the min, max, and binsize values from keywords, if specified */

      if (*minname[ii])
      {
         if (ffgky(*fptr, TDOUBLE, minname[ii], &minin[ii], NULL, status) )
         {
             ffpmsg("error reading histogramming minimum keyword");
             ffpmsg(minname[ii]);
             return(*status);
         }
      }

      if (*maxname[ii])
      {
         if (ffgky(*fptr, TDOUBLE, maxname[ii], &maxin[ii], NULL, status) )
         {
             ffpmsg("error reading histogramming maximum keyword");
             ffpmsg(maxname[ii]);
             return(*status);
         }
      }

      if (*binname[ii])
      {
         if (ffgky(*fptr, TDOUBLE, binname[ii], &binsizein[ii], NULL, status) )
         {
             ffpmsg("error reading histogramming binsize keyword");
             ffpmsg(binname[ii]);
             return(*status);
         }
      }

      if (binsizein[ii] == 0.)
      {
        ffpmsg("error: histogram binsize = 0");
        return(*status = ZERO_SCALE);
      }

      if (*colname[ii] == '\0')
      {
         strcpy(colname[ii], cpref[ii]); /* try using the preferred column */
         if (*colname[ii] == '\0')
         {
           if (ii == 0)
              strcpy(colname[ii], "X");
           else if (ii == 1)
              strcpy(colname[ii], "Y");
           else if (ii == 2)
              strcpy(colname[ii], "Z");
           else if (ii == 3)
              strcpy(colname[ii], "T");
         }
      }

      /* get the column number in the table */
      if (ffgcno(*fptr, CASEINSEN, colname[ii], histData.hcolnum+ii, status)
              > 0)
      {
        strcpy(errmsg, "column for histogram axis doesn't exist: ");
        strcat(errmsg, colname[ii]);
        ffpmsg(errmsg);
        return(*status);
      }

      colptr = ((*fptr)->Fptr)->tableptr;
      colptr += (histData.hcolnum[ii] - 1);

      repeat = (int) colptr->trepeat;  /* vector repeat factor of the column */
      if (repeat > 1)
      {
        strcpy(errmsg, "Can't bin a vector column: ");
        strcat(errmsg, colname[ii]);
        ffpmsg(errmsg);
        return(*status = BAD_DATATYPE);
      }

      /* get the datatype of the column */
      fits_get_coltype(*fptr, histData.hcolnum[ii], &datatype,
         NULL, NULL, status);

      if (datatype < 0 || datatype == TSTRING)
      {
        strcpy(errmsg, "Inappropriate datatype; can't bin this column: ");
        strcat(errmsg, colname[ii]);
        ffpmsg(errmsg);
        return(*status = BAD_DATATYPE);
      }

      /* use TLMINn and TLMAXn keyword values if min and max were not given */
      /* else use actual data min and max if TLMINn and TLMAXn don't exist */
 
      if (minin[ii] == DOUBLENULLVALUE)
      {
        ffkeyn("TLMIN", histData.hcolnum[ii], keyname, status);
        if (ffgky(*fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0)
        {
            /* use actual data minimum value for the histogram minimum */
            *status = 0;
            if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], amin+ii, &datamax, status) > 0)
            {
                strcpy(errmsg, "Error calculating datamin and datamax for column: ");
                strcat(errmsg, colname[ii]);
                ffpmsg(errmsg);
                return(*status);
            }
         }
      }
      else
      {
        amin[ii] = (float) minin[ii];
      }

      if (maxin[ii] == DOUBLENULLVALUE)
      {
        ffkeyn("TLMAX", histData.hcolnum[ii], keyname, status);
        if (ffgky(*fptr, TFLOAT, keyname, &amax[ii], NULL, status) > 0)
        {
          *status = 0;
          if(datamax != FLOATNULLVALUE)  /* already computed max value */
          {
             amax[ii] = datamax;
          }
          else
          {
             /* use actual data maximum value for the histogram maximum */
             if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], &datamin, &amax[ii], status) > 0)
             {
                 strcpy(errmsg, "Error calculating datamin and datamax for column: ");
                 strcat(errmsg, colname[ii]);
                 ffpmsg(errmsg);
                 return(*status);
             }
          }
        }
        use_datamax = 1;  /* flag that the max was determined by the data values */
                          /* and not specifically set by the calling program */
      }
      else
      {
        amax[ii] = (float) maxin[ii];
      }

      /* use TDBINn keyword or else 1 if bin size is not given */
      if (binsizein[ii] == DOUBLENULLVALUE)
      {
         tstatus = 0;
         ffkeyn("TDBIN", histData.hcolnum[ii], keyname, &tstatus);

         if (ffgky(*fptr, TDOUBLE, keyname, binsizein + ii, NULL, &tstatus) > 0)
         {
	    /* make at least 10 bins */
            binsizein[ii] = (amax[ii] - amin[ii]) / 10. ;
            if (binsizein[ii] > 1.)
                binsizein[ii] = 1.;  /* use default bin size */
         }
      }

      if ( (amin[ii] > amax[ii] && binsizein[ii] > 0. ) ||
           (amin[ii] < amax[ii] && binsizein[ii] < 0. ) )
          binsize[ii] = (float) -binsizein[ii];  /* reverse the sign of binsize */
      else
          binsize[ii] =  (float) binsizein[ii];  /* binsize has the correct sign */

      ibin = (int) binsize[ii];
      imin = (int) amin[ii];
      imax = (int) amax[ii];

      /* Determine the range and number of bins in the histogram. This  */
      /* depends on whether the input columns are integer or floats, so */
      /* treat each case separately.                                    */

      if (datatype <= TLONG && (float) imin == amin[ii] &&
                               (float) imax == amax[ii] &&
                               (float) ibin == binsize[ii] )
      {
        /* This is an integer column and integer limits were entered. */
        /* Shift the lower and upper histogramming limits by 0.5, so that */
        /* the values fall in the center of the bin, not on the edge. */

        haxes[ii] = (imax - imin) / ibin + 1;  /* last bin may only */
                                               /* be partially full */
        maxbin[ii] = (float) (haxes[ii] + 1.);  /* add 1. instead of .5 to avoid roundoff */

        if (amin[ii] < amax[ii])
        {
          amin[ii] = (float) (amin[ii] - 0.5);
          amax[ii] = (float) (amax[ii] + 0.5);
        }
        else
        {
          amin[ii] = (float) (amin[ii] + 0.5);
          amax[ii] = (float) (amax[ii] - 0.5);
        }
      }
      else if (use_datamax)  
      {
        /* Either the column datatype and/or the limits are floating point, */
        /* and the histogram limits are being defined by the min and max */
        /* values of the array.  Add 1 to the number of histogram bins to */
        /* make sure that pixels that are equal to the maximum or are */
        /* in the last partial bin are included.  */

        maxbin[ii] = (amax[ii] - amin[ii]) / binsize[ii]; 
        haxes[ii] = (long) (maxbin[ii] + 1);
      }
      else  
      {
        /*  float datatype column and/or limits, and the maximum value to */
        /*  include in the histogram is specified by the calling program. */
        /*  The lower limit is inclusive, but upper limit is exclusive    */
        maxbin[ii] = (amax[ii] - amin[ii]) / binsize[ii];
        haxes[ii] = (long) maxbin[ii];

        if (amin[ii] < amax[ii])
        {
          if (amin[ii] + (haxes[ii] * binsize[ii]) < amax[ii])
            haxes[ii]++;   /* need to include another partial bin */
        }
        else
        {
          if (amin[ii] + (haxes[ii] * binsize[ii]) > amax[ii])
            haxes[ii]++;   /* need to include another partial bin */
        }
      }
    }

       /* get the histogramming weighting factor */
    if (*wtcol)
    {
        /* first, look for a keyword with the weight value */
        if (ffgky(*fptr, TFLOAT, wtcol, &histData.weight, NULL, status) )
        {
            /* not a keyword, so look for column with this name */
            *status = 0;

            /* get the column number in the table */
            if (ffgcno(*fptr, CASEINSEN, wtcol, &histData.wtcolnum, status) > 0)
            {
               ffpmsg(
               "keyword or column for histogram weights doesn't exist: ");
               ffpmsg(wtcol);
               return(*status);
            }

            histData.weight = FLOATNULLVALUE;
        }
    }
    else
        histData.weight = (float) weightin;

    if (histData.weight <= 0. && histData.weight != FLOATNULLVALUE)
    {
        ffpmsg("Illegal histogramming weighting factor <= 0.");
        return(*status = URL_PARSE_ERROR);
    }

    if (recip && histData.weight != FLOATNULLVALUE)
       /* take reciprocal of weight */
       histData.weight = (float) (1.0 / histData.weight);

    histData.wtrecip = recip;
        
    /* size of histogram is now known, so create temp output file */
    if (ffinit(&histptr, outfile, status) > 0)
    {
        ffpmsg("failed to create temp output file for histogram");
        return(*status);
    }

    if (ffcrim(histptr, bitpix, histData.haxis, haxes, status) > 0)
    {
        ffpmsg("failed to create primary array histogram in temp file");
        ffclos(histptr, status);
        return(*status);
    }

    /* copy all non-structural keywords from the table to the image */
    fits_get_hdrspace(*fptr, &nkeys, NULL, status);
    for (ii = 1; ii <= nkeys; ii++)
    {
       fits_read_record(*fptr, ii, card, status);
       if (fits_get_keyclass(card) >= 120)
           fits_write_record(histptr, card, status);
    }           

    /* Set global variables with histogram parameter values.    */
    /* Use separate scalar variables rather than arrays because */
    /* it is more efficient when computing the histogram.       */

    histData.amin1 = amin[0];
    histData.maxbin1 = maxbin[0];
    histData.binsize1 = binsize[0];
    histData.haxis1 = haxes[0];

    if (histData.haxis > 1)
    {
      histData.amin2 = amin[1];
      histData.maxbin2 = maxbin[1];
      histData.binsize2 = binsize[1];
      histData.haxis2 = haxes[1];

      if (histData.haxis > 2)
      {
        histData.amin3 = amin[2];
        histData.maxbin3 = maxbin[2];
        histData.binsize3 = binsize[2];
        histData.haxis3 = haxes[2];

        if (histData.haxis > 3)
        {
          histData.amin4 = amin[3];
          histData.maxbin4 = maxbin[3];
          histData.binsize4 = binsize[3];
          histData.haxis4 = haxes[3];
        }
      }
    }

    /* define parameters of image for the iterator function */
    fits_iter_set_file(imagepars, histptr);        /* pointer to image */
    fits_iter_set_datatype(imagepars, imagetype);  /* image datatype   */
    fits_iter_set_iotype(imagepars, OutputCol);    /* image is output  */

    /* call the iterator function to write out the histogram image */
    if (fits_iterate_data(n_cols, imagepars, offset, n_per_loop,
                          ffwritehisto, (void*)&histData, status) )
         return(*status);

    /* write the World Coordinate System (WCS) keywords */
    /* create default values if WCS keywords are not present in the table */
    for (ii = 0; ii < histData.haxis; ii++)
    {
     /*  CTYPEn  */
       tstatus = 0;
       ffkeyn("TCTYP", histData.hcolnum[ii], keyname, &tstatus);
       ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
       if (tstatus)
       {               /* just use column name as the type */
          tstatus = 0;
          ffkeyn("TTYPE", histData.hcolnum[ii], keyname, &tstatus);
          ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
       }

       if (!tstatus)
       {
        ffkeyn("CTYPE", ii + 1, keyname, &tstatus);
        ffpky(histptr, TSTRING, keyname, svalue, "Coordinate Type", &tstatus);
       }
       else
          tstatus = 0;

     /*  CUNITn  */
       ffkeyn("TCUNI", histData.hcolnum[ii], keyname, &tstatus);
       ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
       if (tstatus)
       {         /* use the column units */
          tstatus = 0;
          ffkeyn("TUNIT", histData.hcolnum[ii], keyname, &tstatus);
          ffgky(*fptr, TSTRING, keyname, svalue, NULL, &tstatus);
       }

       if (!tstatus)
       {
        ffkeyn("CUNIT", ii + 1, keyname, &tstatus);
        ffpky(histptr, TSTRING, keyname, svalue, "Coordinate Units", &tstatus);
       }
       else
         tstatus = 0;

     /*  CRPIXn  - Reference Pixel  */
       ffkeyn("TCRPX", histData.hcolnum[ii], keyname, &tstatus);
       ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
       if (tstatus)
       {
         dvalue = 1.0; /* choose first pixel in new image as ref. pix. */
         tstatus = 0;
       }
       else
       {
           /* calculate locate of the ref. pix. in the new image */
           dvalue = (dvalue - amin[ii]) / binsize[ii] + .5;
       }

       ffkeyn("CRPIX", ii + 1, keyname, &tstatus);
       ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Pixel", &tstatus);

     /*  CRVALn - Value at the location of the reference pixel */
       ffkeyn("TCRVL", histData.hcolnum[ii], keyname, &tstatus);
       ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
       if (tstatus)
       {
         /* calculate value at ref. pix. location (at center of 1st pixel) */
         dvalue = amin[ii] + binsize[ii]/2.;
         tstatus = 0;
       }

       ffkeyn("CRVAL", ii + 1, keyname, &tstatus);
       ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Value", &tstatus);

     /*  CDELTn - unit size of pixels  */
       ffkeyn("TCDLT", histData.hcolnum[ii], keyname, &tstatus);
       ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
       if (tstatus)
       {
         dvalue = 1.0;  /* use default pixel size */
         tstatus = 0;
       }

       dvalue = dvalue * binsize[ii];
       ffkeyn("CDELT", ii + 1, keyname, &tstatus);
       ffpky(histptr, TDOUBLE, keyname, &dvalue, "Pixel size", &tstatus);

     /*  CROTAn - Rotation angle (degrees CCW)  */
     /*  There should only be a CROTA2 keyword, and only for 2+ D images */
       if (ii == 1)
       {
         ffkeyn("TCROT", histData.hcolnum[ii], keyname, &tstatus);
         ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
         if (!tstatus && dvalue != 0.)  /* only write keyword if angle != 0 */
         {
           ffkeyn("CROTA", ii + 1, keyname, &tstatus);
           ffpky(histptr, TDOUBLE, keyname, &dvalue,
                 "Rotation angle", &tstatus);
         }
         else
         {
            /* didn't find CROTA for the 2nd axis, so look for one */
            /* on the first axis */
           tstatus = 0;
           ffkeyn("TCROT", histData.hcolnum[0], keyname, &tstatus);
           ffgky(*fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
           if (!tstatus && dvalue != 0.)  /* only write keyword if angle != 0 */
           {
             dvalue *= -1.;   /* negate the value, because mirror image */
             ffkeyn("CROTA", ii + 1, keyname, &tstatus);
             ffpky(histptr, TDOUBLE, keyname, &dvalue,
                   "Rotation angle", &tstatus);
           }
         }
       }
    }

    /* convert any TPn_k keywords to PCi_j; the value remains unchanged */
    /* also convert any TCn_k to CDi_j; the value is modified by n binning size */
    /* This is a bit of a kludge, and only works for 2D WCS */

    if (histData.haxis == 2) {

      /* PC1_1 */
      tstatus = 0;
      ffkeyn("TP", histData.hcolnum[0], card, &tstatus);
      strcat(card,"_");
      ffkeyn(card, histData.hcolnum[0], keyname, &tstatus);
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) 
         ffpky(histptr, TDOUBLE, "PC1_1", &dvalue, card, &tstatus);

      tstatus = 0;
      keyname[1] = 'C';
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) {
         dvalue *=  binsize[0];
         ffpky(histptr, TDOUBLE, "CD1_1", &dvalue, card, &tstatus);
      }

      /* PC1_2 */
      tstatus = 0;
      ffkeyn("TP", histData.hcolnum[0], card, &tstatus);
      strcat(card,"_");
      ffkeyn(card, histData.hcolnum[1], keyname, &tstatus);
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) 
         ffpky(histptr, TDOUBLE, "PC1_2", &dvalue, card, &tstatus);
 
      tstatus = 0;
      keyname[1] = 'C';
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) {
        dvalue *=  binsize[0];
        ffpky(histptr, TDOUBLE, "CD1_2", &dvalue, card, &tstatus);
      }
       
      /* PC2_1 */
      tstatus = 0;
      ffkeyn("TP", histData.hcolnum[1], card, &tstatus);
      strcat(card,"_");
      ffkeyn(card, histData.hcolnum[0], keyname, &tstatus);
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) 
         ffpky(histptr, TDOUBLE, "PC2_1", &dvalue, card, &tstatus);
 
      tstatus = 0;
      keyname[1] = 'C';
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) {
         dvalue *=  binsize[1];
         ffpky(histptr, TDOUBLE, "CD2_1", &dvalue, card, &tstatus);
      }
       
       /* PC2_2 */
      tstatus = 0;
      ffkeyn("TP", histData.hcolnum[1], card, &tstatus);
      strcat(card,"_");
      ffkeyn(card, histData.hcolnum[1], keyname, &tstatus);
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) 
         ffpky(histptr, TDOUBLE, "PC2_2", &dvalue, card, &tstatus);
        
      tstatus = 0;
      keyname[1] = 'C';
      ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
      if (!tstatus) {
         dvalue *=  binsize[1];
         ffpky(histptr, TDOUBLE, "CD2_2", &dvalue, card, &tstatus);
      }
    }   
       
    /* finally, close the original file and return ptr to the new image */
    ffclos(*fptr, status);
    *fptr = histptr;

    return(*status);
}