/*************************************************************************** * 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 * * cads_AT_iiap.res.in * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /*--------------------------------------------------------------------------- This program will write out FITS data into a jpeg file. Assume that data are in first extension and are two dimensional Libraries needed are CFITSIO, JPEG Original author: Jayant Murthy Last Modification: 11/05/02 Reconstruction and additional features: Reks *---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Modification History Reks, 5th October 2007: v0.01 1. configure checks for jpeglib. optional extra arguments --with-jpeglib= --with-cfitsio= 2. Makes blank images! datamin and max are not set.. Reks, 6th October 2007: v0.10 1. Added 2 functions to fetch max and min from image 2. user can choose various scales like log/square/square-root 3. Increased verbosity, added banner, help message, etc 4. Inputs through getopt. will Ask if mandatory input (fits file) is not provided. 5. fitsio2 Reks, 10th October 2007: v0.9.0 (close to 1.0) 1. Found our niche :-) Can handle wild cards at command line, batch processing. 2. Now users cannot specify the output file name though.. Its fixed to .jpg. 3. No getopt for input file.. getopt is limited to various image scaling options. Reks, 17th October 2007, v0.9.5 1. Merged all image scaling options into one input param: -s optarg (from getopt) will decide scaling function. Now there is enough room for additional flags (in future). Reks, 22 June 2010 v1.0.0 1. Removed datamax() and datamin(). That was required only once! 2. option histoeq shifted to image enhancement option 3. Added "normalize" option Now users can do scaling + enhance (if at all someone feels like it) 4. All options tested. First stable release :) Reks 28 June 2012 1. rebranded to CADS/UVS Reks 05-10 July 2012 v2.0 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 Reks Oct/Nov 2012 v2.1 1. Fixed a segfault on zero/blank fits images *---------------------------------------------------------------------------*/ #include "fits2jpeg.h" char *optarg; int optindex; /*--------------------------- Begin Main Progam -----------------------------*/ int main(int argc, char *argv[], char *envp[]) { 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; 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; JSAMPROW row_pointer[1]; JSAMPLE *image_buffer; /*---------------- End of variable initialization -----------------------*/ 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, "d:e:hnq:r:s:z:" ) ) != EOF ) switch ( opt ) { case 's': 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': /* 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; default : printerro("You can try 'fits2jpeg -h' for valid options"); break; } if (scale == 0) printinfo("Using linear scale"); if ((argc - optindex) == 0) usage(); /* Someone gave only options */ /*---------------------- Begin processing files -------------------------*/ /* Getopt would have processed all argument with a "-" in front. optindex is the counter, which keeps the number of options supplied. Whatever remains in the list of command line arguments are the fits files. NOTE: POSIX systems will do the regex matching and expand wild card entries for us. Even windoze XP Pro is known to do that... */ for (j = optindex; j < argc; j++) { strcpy(fits_file_name, argv[j]); strcpy(jpeg_file_name, fits_file_name); strtok(jpeg_file_name, "."); strcat(jpeg_file_name, ".jpg"); if (customdir == 1) { if (output_dir[strlen(output_dir) - 1] != '/') strcat(output_dir, "/"); strcat(output_dir, basename(jpeg_file_name)); strcpy(jpeg_file_name, output_dir); } read_fits(fits_file_name, &xdim, &ydim, &data); npixels = xdim * ydim; printf("INFO : data input from %s\n", fits_file_name); /* Now we need to look at user options.. */ /*-------------------------------------------------------------------*/ /* 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) { if (data[i] > datamax) data[i] = datamax; if (data[i] < datamin) data[i] = datamin; } /*endfor*/ } scale_pixels(scale, npixels, data, &image_buffer); /* 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; } 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_stdio_dest(&cinfo, jpeg_file); /* Send compressed data to stdio */ 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 = xdim; /* JSAMPLEs per row inimage buffer */ /* 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]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); }/*Loop through file writing one line at a time*/ jpeg_finish_compress(&cinfo); /* Finish compression */ fclose(jpeg_file); /* Close file */ jpeg_destroy_compress(&cinfo); /* Release memory */ free(data); free(image_buffer); printf("INFO : wrote output to %s\n", jpeg_file_name); } exit(EXIT_SUCCESS); } /*End of program*/