X-Git-Url: https://cads.iiap.res.in/gitview/?p=fits2jpeg.git;a=blobdiff_plain;f=src%2Ffits2jpeg.c;fp=src%2Ffits2jpeg.c;h=60420e2ff4b747eab5de0a89acaf84f7fa88cd3c;hp=116251b97dc00202b628bc3d69601ad72f4dd249;hb=60d065b23a2bdd48da5b8ef3ce591b7b0313c979;hpb=e31da38fa70e45758bd0c82b124c018c25e78e23 diff --git a/src/fits2jpeg.c b/src/fits2jpeg.c index 116251b..60420e2 100644 --- a/src/fits2jpeg.c +++ b/src/fits2jpeg.c @@ -29,6 +29,7 @@ Reconstruction and additional features: Reks *---------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------- Modification History @@ -69,87 +70,38 @@ Reks 28 June 2012 1. rebranded to CADS/UVS - Reks 05 July 2012 v2.0 plans + 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 works for reducing size. segfaults for zoom > 1 :( TODO - 1. New option to specify min-max for image + 1. move fits read to image.c 2. specify output directory - 3. output filename for single input file - 4. Image resizing options - - *-------------------------------------------------------------------------*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/*Header Definitions*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#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); + 3. Image resizing options + *---------------------------------------------------------------------------*/ + +#include "fits2jpeg.h" 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 ] \n"); - printf (" Options are: \n"); - printf (" -h help \n"); - printf (" -s \n"); - printf (" scale for output image, where can be: \n"); - printf (" linear Linear scale, default \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 (" normalize for linear histogram stretch \n"); - printf (" equalize for histogram equalization \n"); - printf (" Output will be written to .jpg. Wild card\n"); - printf (" entries allowed in ; 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; - 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, process = 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 tmp = 0.0; - float hist[256] = {0.0}, cumhist[256] = {0.0}; char jpeg_file_name[MAX_TEXT] = "", fits_file_name[MAX_TEXT] = ""; + char *tmpstr, *sptr; int opt; /* For getopt */ extern char *optarg; @@ -159,7 +111,6 @@ int main(int argc, char *argv[], char *envp[]) 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 -----------------------*/ @@ -170,41 +121,86 @@ int main(int argc, char *argv[], char *envp[]) /*-------------------- Parse command line inputs ------------------------*/ if (argc < 2) usage(); /* People who don't give any arguments need help */ - while ( ( opt = my_getopt ( argc, argv, "s:r:h" ) ) != EOF ) + while ( ( opt = my_getopt ( argc, argv, "e:hnq:r:s:z:" ) ) != EOF ) switch ( opt ) { case 's': - if (strcmp(optarg, "sqroot") ==0) scale = 1; + 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, "cube") ==0) scale = 3; + 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 + scale = 0; + break; + + case 'e': + /* 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 : */ + 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 : */ + datamin = -1.0*FLT_MAX; + else { - fprintf(stderr, "ERROR : Unrecognized option : %s\n", optarg); - exit(EXIT_FAILURE); + sptr = strtok(tmpstr, ":"); + datamin = atof(sptr); } + printinfo("User defined pixel range"); + + /* Remember.. now we have user specified range */ + usrclip = 1; break; - case 'r': - /* - * read a string like : - * set a flag. If this flag is on, do a 'reverse map' - * instead of search for datamin & datamax + 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); + if (zoomfact < 0.0) zoomfact = 1.0; + usrzoom = 1; break; case 'h': usage(); break; - case '*': - usage(); + default : + printerro("You can try 'fits2jpeg -h' for valid options"); break; } - if ((argc - optindex) == 0) usage(); /* Somebody gave only options */ + if ((argc - optindex) == 0) usage(); /* Someone gave only options */ /*---------------------- Begin processing files -------------------------*/ @@ -225,11 +221,7 @@ int main(int argc, char *argv[], char *envp[]) 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]; @@ -238,158 +230,55 @@ int main(int argc, char *argv[], char *envp[]) 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); - /* IF no range is provided, 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.. */ - /* 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; - - - /* 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]; - /*-------------------------------------------------------------------*/ - - - switch (scale) + /* IF user has provided a range, fix them as min & max in image */ + if (usrclip == 1) { - 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; - - case 5 : - /* contrast stretch */ - printf("INFO : Performing histogram 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; + if (data[i] > datamax) data[i] = datamax; + if (data[i] < datamin) data[i] = datamin; + } /*endfor*/ + } - case 6 : - /* histogram equalization */ - printf("INFO : Performing Histogram Equalization\n"); - for (i = 0; i < npixels; ++i) - image_buffer[i] = cumhist[image_buffer[i]]*255; - break; + /* Allocate image buffer */ + image_buffer = (unsigned char *) malloc(sizeof(char) * npixels); + scale_pixels(scale, npixels, data, image_buffer); - default: /* Linear scale (min-max) */ - for (i = 0; i < npixels; ++i) - image_buffer[i] = (int)(data[i]); - break; + /* Before we write jpeg, check if there is any requirement to negate + * the image (usrnegt = 1) */ + if (usrnegt == 1) + { + printinfo("Negating Image"); + for (i = 0; i < npixels; ++i) image_buffer[i] ^= 0xff; } + xdim = naxes[0]; + ydim = naxes[1]; + if (usrzoom == 1) resize_image(&xdim, &ydim, zoomfact, image_buffer); /*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 */ - jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/ 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 */ + jpeg_set_quality(&cinfo, jpgqual, TRUE); /* Set jpeg quality factor */ 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) @@ -397,6 +286,7 @@ int main(int argc, char *argv[], char *envp[]) 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*/