diff --git a/src/fits2jpeg.c b/src/fits2jpeg.c
--- a/src/fits2jpeg.c
+++ b/src/fits2jpeg.c
Reconstruction and additional features: Reks
*---------------------------------------------------------------------------*/
Reconstruction and additional features: Reks
*---------------------------------------------------------------------------*/
+
/*---------------------------------------------------------------------------
Modification History
/*---------------------------------------------------------------------------
Modification History
Reks 28 June 2012
1. rebranded to CADS/UVS
Reks 28 June 2012
1. rebranded to CADS/UVS
- *-------------------------------------------------------------------------*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-/*Header Definitions*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <libgen.h>
-#include <dirent.h>
-#include <fitsio2.h>
-#include <jpeglib.h>
-
-#define PROGRAM "fits2jpeg"
-#define r2d (90./atan2(1,0))
-#define MAX_TEXT 150
-int my_getopt(int, char * const *, const char *);
-void signals_handler(int);
-void set_signals(void);
+
+ Reks 05-10 July 2012 v2.0 plans
+ 1. Merged scale & operations to single flag
+ 2. added fits2jpeg.h, help/banner functions moved to messages.c
+ 3. Options to clip image min/max
+ 4. negate image option
+ 5. jpeg quality factor
+ 6. pixel scaling operations moved to image.c
+ 7. Image resizing
+ TODO
+ 1. move fits read to image.c
+ 2. specify output directory
+ *---------------------------------------------------------------------------*/
+
+#include "fits2jpeg.h"
char *optarg;
int optindex;
char *optarg;
int optindex;
-/*---------------------------------------------------------------------------*/
-void PRINT_BANNER()
-{
- printf("\n");
- printf(" %s %s\n", PROGRAM, VERSION);
- printf(" Converts fits image files to jpeg\n");
- printf("-----------------------------------------------------------\n");
-}
-/*---------------------------------------------------------------------------*/
-void usage()
-{
- printf ("\n Usage: fits2jpeg [-s <options>] <fits_file> \n");
- printf (" Options are: \n");
- printf (" -h help \n");
- printf (" -s <scale_type> \n");
- printf (" scale for output image, where <scale_type> can be: \n");
- printf (" linear Linear scale, default \n\n");
- printf (" sqroot for square root scale \n");
- printf (" square for quadratic scale \n");
- printf (" cubic for cubic scale \n");
- printf (" log for log scale \n");
- printf (" -e <operation> \n");
- printf (" Image enhancements, where <operation> can be: \n");
- printf (" normalize for linear histogram stretch \n");
- printf (" equalize for histogram equalization \n");
- printf (" Output will be written to <fits_file_root>.jpg. Wild card\n");
- printf (" entries allowed in <fits_file>; For eg: *.fits, m31*.fits\n");
- printf (" ngc???.fits etc. \n");
- printf ("-----------------------------------------------------------\n");
- printf ("Copyright (c) 2012 The CADS Team, IIAp. [GPL v3.0 or later]\n");
- printf ("Report Bugs to: http://cads.iiap.res.in/bugzilla \n");
- printf ("Documentation : http://cads.iiap.res.in/software \n\n");
- exit(1);
-}
-/*---------------------------------------------------------------------------*/
/*--------------------------- Begin Main Progam -----------------------------*/
int main(int argc, char *argv[], char *envp[])
{
fitsfile *fptr;
/*--------------------------- Begin Main Progam -----------------------------*/
int main(int argc, char *argv[], char *envp[])
{
fitsfile *fptr;
- int scale = 0, process = 0, status = 0, nfound, anynull;
- unsigned int i = 0, j = 0, npixels = 0;
- long naxes[2], row_stride;
- float datamin = 0.0, datamax = 0.0;
- float nullval = 0.0, scl_data;
+ int scale = 0, status = 0, jpgqual = 100, nfound, anynull;
+ unsigned int i = 0, j = 0, usrclip = 0, usrnegt = 0, usrzoom = 0;
+ long xdim = 0, ydim = 0, naxes[2], row_stride;
+ unsigned long npixels = 0;
+ float datamin = 0.0, datamax = 0.0, nullval = 0.0, zoomfact = 1.0;
float *data;
float *data;
- float tmp = 0.0;
- float hist[256] = {0.0}, cumhist[256] = {0.0};
char jpeg_file_name[MAX_TEXT] = "", fits_file_name[MAX_TEXT] = "";
char jpeg_file_name[MAX_TEXT] = "", fits_file_name[MAX_TEXT] = "";
+ char *tmpstr, *sptr;
int opt; /* For getopt */
extern char *optarg;
int opt; /* For getopt */
extern char *optarg;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct cinfo;
- int JMAXVAL = 255; /* Max value for greyscale in jpeg */
JSAMPROW row_pointer[1];
JSAMPLE *image_buffer;
/*---------------- End of variable initialization -----------------------*/
JSAMPROW row_pointer[1];
JSAMPLE *image_buffer;
/*---------------- End of variable initialization -----------------------*/
/*-------------------- Parse command line inputs ------------------------*/
if (argc < 2) usage(); /* People who don't give any arguments need help */
/*-------------------- Parse command line inputs ------------------------*/
if (argc < 2) usage(); /* People who don't give any arguments need help */
- while ( ( opt = my_getopt ( argc, argv, "s:e:h" ) ) != EOF )
+ while ( ( opt = my_getopt ( argc, argv, "e:hnq:r:s:z:" ) ) != EOF )
switch ( opt )
{
case 's':
switch ( opt )
{
case 's':
- if (strcmp(optarg, "sqroot") ==0) scale = 1;
- if (strcmp(optarg, "square") ==0) scale = 2;
- if (strcmp(optarg, "cube") ==0) scale = 3;
- if (strcmp(optarg, "log") ==0) scale = 4;
+ if (strcmp(optarg, "linear") ==0) scale = 0;
+ else if (strcmp(optarg, "sqroot") ==0) scale = 1;
+ else if (strcmp(optarg, "square") ==0) scale = 2;
+ else if (strcmp(optarg, "cubic") ==0) scale = 3;
+ else if (strcmp(optarg, "log") ==0) scale = 4;
+ else if (strcmp(optarg, "normalize")==0) scale = 5;
+ else if (strcmp(optarg, "equalize") ==0) scale = 6;
+ else
+ printwarn(strcat(optarg, " -- Unrecognized option"));
+ scale = 0;
break;
case 'e':
break;
case 'e':
- if (strcmp(optarg, "normalize")==0) process = 1;
- if (strcmp(optarg, "equalize") ==0) process = 2;
+ /* Need to preserve it for backward compatibility */
+ if (strcmp(optarg, "normalize")==0) scale = 5;
+ else if (strcmp(optarg, "equalize") ==0) scale = 6;
+ else
+ printerro(strcat(optarg, " -- Unrecognized option"));
+ break;
+
+ case 'r':
+ tmpstr = optarg; /* make a copy.. and leave optarg alone */
+ sptr = strpbrk(tmpstr, ":"); /* Find the delimiter */
+ if (sptr == NULL)
+ printerro("Expected a ':' as separator for min/max");
+
+ if (sptr+1 == tmpstr + strlen(tmpstr)) /* -c <datamin>: */
+ datamax = FLT_MAX;
+ else
+ datamax = atof(sptr+1);
+
+ /* There should be an easier way to find datamin alongside datamax,
+ * but I am too sleepy to try anything now */
+ sptr = strchr(tmpstr, ':');
+ if (sptr == tmpstr) /* -c :<datamax> */
+ datamin = -1.0*FLT_MAX;
+ else
+ {
+ sptr = strtok(tmpstr, ":");
+ datamin = atof(sptr);
+ }
+
+ /* Remember.. now we have user specified range */
+ usrclip = 1;
+ break;
+
+ case 'n' :
+ usrnegt = 1;
+ break;
+
+ case 'q' :
+ jpgqual = atoi(optarg);
+ if (jpgqual < 0) jpgqual = 0;
+ if (jpgqual > 100) jpgqual = 100;
+ printf("INFO : jpeg quality factor changed to %d\n", jpgqual);
+ break;
+
+ case 'z' :
+
+ /* Do something to scale image
+ */
+ zoomfact = atof(optarg);
+ zoomfact = abs(zoomfact);
+ if (zoomfact < 0.01) zoomfact = 0.01;
+ if (zoomfact > 4.0) zoomfact = 4.0;
+ usrzoom = 1;
break;
case 'h':
usage();
break;
break;
case 'h':
usage();
break;
- case '*':
- usage();
+ default :
+ printerro("You can try 'fits2jpeg -h' for valid options");
break;
}
break;
}
- if ((argc - optindex) == 0) usage(); /* Somebody gave only options */
+ if ((argc - optindex) == 0) usage(); /* Someone gave only options */
/*---------------------- Begin processing files -------------------------*/
/*---------------------- Begin processing files -------------------------*/
fits_open_file(&fptr, fits_file_name, READONLY, &status);
fits_read_keys_lng(fptr, "NAXIS", 1, 2, naxes, &nfound, &status);
if (status)
fits_open_file(&fptr, fits_file_name, READONLY, &status);
fits_read_keys_lng(fptr, "NAXIS", 1, 2, naxes, &nfound, &status);
if (status)
- {
- fprintf(stderr, "ERROR : Could not open file: %s\n",
- fits_file_name);
- exit(EXIT_FAILURE);
- }/*Endif*/
+ printerro(strcat(fits_file_name, " <-- Failed to open the file"));
/* Read in data */
npixels = naxes[0] * naxes[1];
/* Read in data */
npixels = naxes[0] * naxes[1];
- data = (float *) malloc(sizeof(float) * npixels);
+ data = malloc(sizeof(float) * npixels);
nullval = 0;
if (fits_read_img(fptr, TFLOAT, 1, npixels, &nullval, data, &anynull,
&status))
nullval = 0;
if (fits_read_img(fptr, TFLOAT, 1, npixels, &nullval, data, &anynull,
&status))
- {
- fprintf(stderr, "ERROR : No valid fits image data in %s\n",
- fits_file_name);
- exit(EXIT_FAILURE);
- }/*Endif*/
+ printerro(strcat(fits_file_name, " has no valid fits image data"));
fits_close_file(fptr, &status);
/*Close data file*/
printf("INFO : data input from %s\n", fits_file_name);
fits_close_file(fptr, &status);
/*Close data file*/
printf("INFO : data input from %s\n", fits_file_name);
- /* find min & max in image */
- datamax = -1.0e9;
- datamin = +1.0e9;
- for (i = 0; i < npixels; ++i)
- {
- if (data[i] > datamax) datamax = data[i];
- if (data[i] < datamin) datamin = data[i];
- } /*endfor*/
-
- /* Convert data into bytscaled values for jpeg file */
- /* the dynamic range is reduced to 255 for jpeg */
- scl_data = (datamax - datamin)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- data[i] = (data[i] - datamin)/scl_data;
-
- /* All data is now squeezed into the range 0 - 255 */
- /* NOTE: At this point onwards min & max is 0 and 255 respectively */
-
/* Now we need to look at user options.. */
/* Now we need to look at user options.. */
- /* 1. scale it as per user's requirement. */
- /* 2. image enhancing operations */
- /* Allocate image buffer */
- image_buffer = (unsigned char *) malloc(sizeof(char) * npixels);
- scl_data = 1.0;
- switch (scale)
- {
- case 1 : /* Square root */
- printf("INFO : Using square-root scale\n");
- scl_data = sqrt((float)JMAXVAL)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- image_buffer[i] = (int)(sqrt(data[i])/scl_data);
- break;
+ /*-------------------------------------------------------------------*/
- case 2 : /* Square */
- printf("INFO : Using quadratic scale\n");
- scl_data = pow((float)JMAXVAL,2)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- image_buffer[i] = (int)abs((pow(data[i],2) - 1.0)/scl_data);
- break;
-
- case 3 : /* Cubic */
- printf("INFO : Using cubic scale\n");
- scl_data = pow((float)JMAXVAL,3)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- image_buffer[i] = (int)abs((pow(data[i],3) - 1.0)/scl_data);
- break;
-
- case 4 : /* log */
- printf("INFO : Using log scale\n");
- scl_data = log(1.0 + (float)JMAXVAL)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- image_buffer[i] = (int)((log(abs(data[i]) + 1.0))/scl_data);
- break;
-
- default: /* Linear scale (min-max) */
+ /* IF user has provided a range, fix them as min & max in image */
+ if (usrclip == 1)
+ {
+ printinfo("user defined pixel range");
for (i = 0; i < npixels; ++i)
for (i = 0; i < npixels; ++i)
- image_buffer[i] = (int)(data[i]);
- break;
+ {
+ if (data[i] > datamax) data[i] = datamax;
+ if (data[i] < datamin) data[i] = datamin;
+ } /*endfor*/
}
}
- /* initialize image histogram. ensure all are zeroes in hist[] */
- for (i = 0; i <= JMAXVAL; ++i) hist[i] = 0;
-
- /* construct the image histogram */
- tmp = 1.0/(float)npixels;
- for (i = 0; i <= npixels; ++i)
- hist[(int)floor(data[i])] += tmp;
-
- /* And the cumulative histogram */
- cumhist[0] = hist[0];
- for (i = 1; i <= JMAXVAL; ++i)
- cumhist[i] += cumhist[i - 1] + hist[i];
+ scale_pixels(scale, npixels, data, &image_buffer);
- switch (process)
+ /* Before we write jpeg, check if there is any requirement to negate
+ * the image (usrnegt = 1) */
+ if (usrnegt == 1)
{
{
- case 1 : /* contrast stretch */
- printf("INFO : Performing contrast stretch (normalization) \n");
-
- datamax = (float)JMAXVAL;
- datamin = 0.0;
-
- /* We need to go through the cumulative histogram to pick the
- appropriate values for datamin and datamax */
- i = 0;
- while (i < JMAXVAL)
- {
- if (cumhist[i] >= 0.01)
- {
- datamin = (float) i;
- break;
- }
- i++;
- }
- i = JMAXVAL;
- while (i > 0)
- {
- if (cumhist[i] <= 0.99)
- {
- datamax = (float) i;
- break;
- }
- i--;
- }
- scl_data = (datamax - datamin)/(float)JMAXVAL;
- for (i = 0; i < npixels; ++i)
- {
- if (image_buffer[i] >= datamax)
- image_buffer[i] = JMAXVAL;
- else if (image_buffer[i] <= datamin)
- image_buffer[i] = 0;
- else
- image_buffer[i]=(int)abs((image_buffer[i]-datamin)/scl_data);
- }
- break;
-
+ printinfo("Negating Image");
+ for (i = 0; i < npixels; ++i) image_buffer[i] ^= 0xff;
+ }
- case 2 : /* histogram equalization */
- printf("INFO : Performing Histogram Equalization\n");
- for (i = 0; i < npixels; ++i)
- image_buffer[i] = cumhist[image_buffer[i]]*255;
- break;
+ xdim = naxes[0];
+ ydim = naxes[1];
+ if (usrzoom == 1)
+ {
+ printf("INFO : Image zoom factor = %3.2f\n", zoomfact);
+ resize_image(&xdim, &ydim, zoomfact, &image_buffer);
}
/*Write out data into JPEG file*/
}
/*Write out data into JPEG file*/
+ jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/
cinfo.err = jpeg_std_error(&jerr); /* JPEG error handler */
jpeg_create_compress(&cinfo); /* JPEG initialization */
cinfo.err = jpeg_std_error(&jerr); /* JPEG error handler */
jpeg_create_compress(&cinfo); /* JPEG initialization */
- jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/
jpeg_stdio_dest(&cinfo, jpeg_file); /* Send compressed data to stdio */
jpeg_stdio_dest(&cinfo, jpeg_file); /* Send compressed data to stdio */
- cinfo.image_width = naxes[0]; /* Image width */
- cinfo.image_height = naxes[1]; /* Image height */
+ cinfo.image_width = xdim; /* Image width */
+ cinfo.image_height = ydim; /* Image height */
cinfo.input_components = 1; /* Number of colors per pixel */
cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
jpeg_set_defaults(&cinfo); /* Set JPEG defaults */
cinfo.input_components = 1; /* Number of colors per pixel */
cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
jpeg_set_defaults(&cinfo); /* Set JPEG defaults */
+ jpeg_set_quality(&cinfo, jpgqual, TRUE); /* Set jpeg quality factor */
jpeg_start_compress(&cinfo, TRUE); /* default data compression */
jpeg_start_compress(&cinfo, TRUE); /* default data compression */
- row_stride = naxes[0]; /* JSAMPLEs per row inimage buffer */
+ row_stride = xdim; /* JSAMPLEs per row inimage buffer */
/* Now we have to turn the data upside down */
while (cinfo.next_scanline < cinfo.image_height)
/* Now we have to turn the data upside down */
while (cinfo.next_scanline < cinfo.image_height)
row_pointer[0] = &image_buffer[(cinfo.image_height -
cinfo.next_scanline) *
row_stride];
row_pointer[0] = &image_buffer[(cinfo.image_height -
cinfo.next_scanline) *
row_stride];
+
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}/*Loop through file writing one line at a time*/
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}/*Loop through file writing one line at a time*/