X-Git-Url: https://cads.iiap.res.in/gitview/?p=fits2jpeg.git;a=blobdiff_plain;f=src%2Ffits2jpeg.c;fp=src%2Ffits2jpeg.c;h=73903306c12cd52aa2c77b7418babe8e401fb357;hp=b387ff0105cda70d120b37d1960057156c4d9715;hb=43cf6bddbf02b21c68b405e267605b1b64cddd8d;hpb=e9b7faa7d8a84a6a7f0e1b65c8859b7405568890 diff --git a/src/fits2jpeg.c b/src/fits2jpeg.c index b387ff0..7390330 100644 --- a/src/fits2jpeg.c +++ b/src/fits2jpeg.c @@ -1,4 +1,5 @@ /*************************************************************************** + * This file is a part of CADS/UVS fits2jpeg conversion software * * Copyright (C) 2012 by CADS/UV Software Team, * * Indian Institute of Astrophysics * * Bangalore 560034 * @@ -29,6 +30,7 @@ Reconstruction and additional features: Reks *---------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------- Modification History @@ -68,126 +70,168 @@ Reks 28 June 2012 1. rebranded to CADS/UVS - *-------------------------------------------------------------------------*/ - -#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); + + 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 + 8. moved fits read to image.c + 9. Option to specify output directory + *---------------------------------------------------------------------------*/ + +#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\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 \n"); - printf (" Image enhancements, where can be: \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, jpgqual = 100, status = 0; + unsigned int i = 0, j = 0; + unsigned int customdir = 0, usrclip = 0, usrnegt = 0, usrzoom = 0; + long xdim = 0, ydim = 0, row_stride; + unsigned long npixels = 0; + float datamin = 0.0, datamax = 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 output_dir[MAX_TEXT] = ""; + char *tmpstr, *sptr; int opt; /* For getopt */ extern char *optarg; extern int optindex; - + mode_t mode = 0755; FILE *jpeg_file; - 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 -----------------------*/ - PRINT_BANNER(); /* Header: Talks about program, version & purpose */ + banner(); /* Header: Talks about program, version & purpose */ set_signals(); /* Trap un-natural exits */ /*-------------------- 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, "d:e:hnq:r:s:z:" ) ) != EOF ) 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) + { + printinfo("Using square-root scale"); + scale = 1; + } + else if (strcmp(optarg, "square") == 0) + { + printinfo("Using quadratic scale"); + scale = 2; + } + else if (strcmp(optarg, "cubic") == 0) + { + printinfo("Using cubic scale"); + scale = 3; + } + else if (strcmp(optarg, "log") == 0) + { + printinfo("Using log scale"); + scale = 4; + } + else if (strcmp(optarg, "normalize") == 0) + { + printinfo("Performing histogram stretch (normalization)"); + scale = 5; + } + else if (strcmp(optarg, "equalize") == 0) + { + printinfo("Performing Histogram Equalization"); + scale = 6; + } + else + { + printwarn(strcat(optarg, " -- Unrecognized option")); + scale = 0; + } 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 : */ + 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 + { + 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' : + zoomfact = atof(optarg); + zoomfact = fabs(zoomfact); + if (zoomfact < 0.01) zoomfact = 0.01; + if (zoomfact > 4.0) zoomfact = 4.0; + usrzoom = 1; + break; + + case 'd': + strcpy(output_dir, optarg); + printf("INFO : Output image directory is %s\n", output_dir); + customdir = 1; + status = make_tree(output_dir, mode); + if (status != 0) printerro("Unable to create output directory"); 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 (scale == 0) printinfo("Using linear scale"); + if ((argc - optindex) == 0) usage(); /* Someone gave only options */ /*---------------------- Begin processing files -------------------------*/ @@ -205,168 +249,65 @@ int main(int argc, char *argv[], char *envp[]) strtok(jpeg_file_name, "."); strcat(jpeg_file_name, ".jpg"); - 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*/ - - /* Read in data */ - npixels = naxes[0] * naxes[1]; - data = (float *) malloc(sizeof(float) * npixels); - - nullval = 0; - if (fits_read_img(fptr, TFLOAT, 1, npixels, &nullval, data, &anynull, - &status)) + if (customdir == 1) { - fprintf(stderr, "ERROR : No valid fits image data in %s\n", - fits_file_name); - exit(EXIT_FAILURE); - }/*Endif*/ + if (output_dir[strlen(output_dir) - 1] != '/') + strcat(output_dir, "/"); - 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*/ + strcat(output_dir, basename(jpeg_file_name)); + strcpy(jpeg_file_name, output_dir); + } - /* 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; + read_fits(fits_file_name, &xdim, &ydim, &data); + npixels = xdim * ydim; - /* All data is now squeezed into the range 0 - 255 */ - /* NOTE: At this point onwards min & max is 0 and 255 respectively */ + printf("INFO : data input from %s\n", fits_file_name); /* 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) - 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; + scale_pixels(scale, npixels, data, &image_buffer); - /* 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 (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; + 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*/ + jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/ + if (!jpeg_file) printerro("Unable to create output file"); 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) @@ -374,6 +315,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*/