From 43cf6bddbf02b21c68b405e267605b1b64cddd8d Mon Sep 17 00:00:00 2001 From: Rekhesh Mohan Date: Thu, 12 Jul 2012 21:28:07 +0530 Subject: [PATCH] Ready for v2.0 - several new features --- ChangeLog.txt | 32 ++++- README.txt | 148 +++++++++++++++------- configure.ac | 8 +- src/Makefile.am | 6 +- src/filesys.c | 87 +++++++++++++ src/fits2jpeg.c | 380 ++++++++++++++++++++++++-------------------------------- src/fits2jpeg.h | 61 +++++++++ src/image.c | 252 +++++++++++++++++++++++++++++++++++++ src/messages.c | 99 +++++++++++++++ 9 files changed, 800 insertions(+), 273 deletions(-) create mode 100644 src/filesys.c create mode 100644 src/fits2jpeg.h create mode 100644 src/image.c create mode 100644 src/messages.c diff --git a/ChangeLog.txt b/ChangeLog.txt index e557841..e10220c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,5 +3,35 @@ CHANGELOG for CADS/UVS fits2jpeg software ------------------------------------------------------------------------ NOTE: This file records the changes made after the release of the stable -version fits2jpeg-1.0 +version fits2jpeg-1.0 ------------------------------------------------------------------------ + + + +Updates in 2.0 Release +---------------------- + + 1. Merged scale & operations to single flag + v1.0 had normalize/equalize handled by "-e" flag and rest of + image operations by "-s" flag. Both are merged into "-s" in + this release. + + 2. New option to clip image min/max + You can limit the pixel-values in output image using the flag + "-r". For eg: -r 10:300 to generate jpegs with pixel values in + the range 10 to 300. + + 3. New option to negate image option + A negative image can be generated using "-n" flag. + + 4. New option to resize image + zoom or shrink output image by "-z ". + + 5. New option to choose jpeg quality factor + You can choose the jpeg quality factor by "-q " + Quality factor was fixed at 100 in previous release. + + 6. New option to specify output directory for saving jpeg images + Output location can be specified by "-d " + If the target directory does not exist, the whole tree will be + created. diff --git a/README.txt b/README.txt index 2164ec0..eeace20 100644 --- a/README.txt +++ b/README.txt @@ -6,12 +6,11 @@ README file for CADS/UVS fits2jpeg software 0. FEATURES ----------- -fits2jpeg is a tiny program to read FITS Images and convert them -to jpeg, which is more popular. This software supports various -type of intensity scaling and image enhancements. fits2jpeg do not -support coordinate axes overlay. fits2jpeg supports batch mode -operations - for instance, converting several fits files to jpeg -at once. +fits2jpeg is a tiny program to read FITS Images and convert them to jpeg, which +is more popular. This software supports various type of intensity scaling and +image enhancements. fits2jpeg do not support coordinate axes overlay. fits2jpeg +supports batch mode operations - for instance, converting several fits files to +jpeg at once. 1. BUILD/INSTALL @@ -26,9 +25,10 @@ Pre-requisites: http://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html b) JPEGLIB - jpeg library and headers. libjpeg is installed by default on most - platforms, but we need the header files too. Once you have cfitsio - and jpeglib installed, you may proceed with compiling jpeg2fits. + jpeg library and headers. libjpeg is installed by default on most platforms, + but we need the header files too. Once you have cfitsio and jpeglib + installed, you may proceed with compiling jpeg2fits. + Follow these 4 steps: @@ -61,45 +61,74 @@ Pre-requisites: 2. Type `make' to compile the package. 3. Type `make install' to install the programs and any data files and - documentation. By default, the binary is copied to /usr/local/bin. - You may change this destination by passing on the following - argument to configure: + documentation. By default, the binary is copied to /usr/local/bin. You may + change this destination by passing on the following argument to configure: --prefix=/your/chosen/destination Which would result in the binary in /your/chosen/destination/bin You may need to ensure that in $PATH to run the program. - 4. You can remove the program binaries and object files from the - source code directory by typing `make clean'. + 4. You can remove the program binaries and object files from the source code + directory by typing `make clean'. -You may read more about configure script and others in the accompanying -file named `INSTALL.txt'. +You may read more about configure script and others in the accompanying file +named `INSTALL.txt'. 2.USAGE ------- - fits2jpeg [options] + Usage: fits2jpeg [options] + You need to specify a fits image file for this program to + work. Everything else is optional. A brief description of them are + listed below: - Options are: -h help + Prints out a usage-help message, much like this section. -s - scale for output image intensity. Valid arguments are: - - linear for linear scaling, default + scale for output image, where can be: + linear Linear scale, default sqroot for square root scale square for quadratic scale cubic for cubic scale log for log scale - - -e - Imaghe enhancement operations. Valid arguments are: - - equalize perform histogram equalization - normalize perform a linear contrast stretch - (use cutoffs at 1% and 99% for image data) + normalize for linear histogram stretch + equalize for histogram equalization + + -n + Negate the image + + -q + quality factor. Defines the jpeg encoding quality + Valid range: 0-100, default value: 100, which means + best quality and largest file-size. + + -d + Write jpeg file to this specified directory. Will + create it if needed. Default is to write jpeg in the + same directory of fits image file + + -r : + Clip output image to min-max range. Eg: + 0:100 Use only values in the range 0-100 + 100:0 Same as above, but negative image + :10 Clip everything above 10 + 10: Clip everything below 10 + + -z + Resize/Scale output image by . Eg: + 0.5 Shrink output to half of input + 2.0 Magnify output to double the size + Allowed range: 0.01 to 4.0 + NOTE: Zooming will be carried out after all other + operations, before writing out jpeg image + + fits2jpeg uses a bilinear interpolation based algorithm + to scale the image. Allowed range: 0.01 to 4.0 + NOTE: Anything outside the allowed range will be clipped + to this range. Output will be written to .jpg. For eg., @@ -107,32 +136,55 @@ file named `INSTALL.txt'. writes output to jpeg file 30dor.jpg - Wild card entries allowed in . For eg: *.fits, - m31*.fits ngc???.fits etc. + Wild card entries allowed in . For eg: *.fits, m31*.fits + ngc???.fits etc. - More examples: - i. fits2jpeg -s cubic sirius.fits +3.1 Examples: +------------- + i. fits2jpeg -s log sirius.fits + will write out sirius.jpg, flux/intensity in log scale ii. fits2jpeg -s sqroot *.fits - Converts all fits files in the directory to jpegs, with - square-root scaling of flux/intensity - Good for very - high dynamic range images -iii. fits2jpeg -e normalize ngc4151.fits - Converts ngc4151.fits to ngc4151.jpg, contrast stretched. + Converts all fits files in the directory to jpegs, with square-root scaling + of flux/intensity - Good for very high dynamic range images + +iii. fits2jpeg -n ngc4151.fits + + Converts ngc4151.fits to ngc4151.jpg, negative image. -NOTE: You can perform scaling + enhancing on an image. Scaling will - always be performed first. In most cases combining these two - would lead to un-usable images :) + iv. fits2jpeg -s square -n -r 10:2000 m31.fits + + Write out m31.jpg, after square scaling of flux/intensity, negate image and + clip pixel values in the range 10 to 2000 units. + + v. fits2jpeg -s equalize -r 200: -d/path/to/mydir NGS253*.fits + + Reads all fits files in the present directory that matches the filename + patterm, performs a histogram equalization, drops pixel values below 200 + and write out all the corresponding jpeg files to directory /path/to/mydir + Will create the destination directory tree if it does not exist. + + +3.1. Sequence of operations +--------------------------- +Here is the sequence of operations, after reading the fits file: + + i. clip the image to user specified pixel limits, if it was requested + ii. Squeeze image pixel values to jpeg limits (0 - 255) + iii. image scaling function, default being linear pixel scale + iv. Negate the image, if requested + v. Image zoom - magnify or shrink the image + vi. Write out jpeg file 3. DOCUMENTATION ---------------- -An extensive coverage of how this program works along with line -by line account of the happenings within the code, are dealt with -in the user manual, which is yet to be written :( +An extensive coverage of how this program works along with line by line account +of the happenings within the code, are dealt with in the user manual, which is +yet to be written :( 4. LICENSE: GPL [See the file COPYING.txt for details] @@ -141,10 +193,9 @@ in the user manual, which is yet to be written :( 5. DISCLAIMER ------------- -You may encounter bugs in this software. If you do, please -report them. Your bug reports are valuable contributions, -since they allow us to notice and fix problems on -machines/platforms we don't have, and/or remained un-noticed. +You may encounter bugs in this software. If you do, please report them. Your bug +reports are valuable contributions, since they allow us to notice and fix +problems on machines/platforms we don't have, and/or remained un-noticed. 6. REPORTING BUGS @@ -157,6 +208,7 @@ If you are too lazy, drop in an email to: cads_AT_iiap.res.in Either way, please include as many details as possible. + ----------------------------------------------------------- Reks, 28 June 2012 - Last modified: 28 June 2012 + Last modified: 10 July 2012 diff --git a/configure.ac b/configure.ac index c63208d..0e27801 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([CADS_fits2jpeg], [1.0], [cads@iiap.res.in]) +AC_INIT([CADS_fits2jpeg], [2.0], [cads@iiap.res.in]) AC_LANG_C AM_INIT_AUTOMAKE([-Wall -Werror]) AC_CONFIG_SRCDIR([config.h.in]) @@ -13,15 +13,17 @@ AC_PROG_MAKE_SET # Checks for libraries. # Checks for header files. -AC_CHECK_HEADERS([stdio.h stdlib.h string.h math.h]) +#AC_CHECK_HEADERS([string.h math.h float.h ctype.h libgen.h dirent.h]) +#AC_CHECK_HEADERS([sys/stat.h sys/types.h]) # Checks for typedefs, structures, and compiler characteristics. + # Checks for library functions. AC_FUNC_MALLOC LIBS="$LIBS -L/usr/lib64 -L/usr/lib -lm -ljpeg -lcfitsio" -CFLAGS="-ansi $CFLAGS -I/usr/include -I/usr/include/cfitsio" +CFLAGS="-ansi -Wall $CFLAGS -I/usr/include -I/usr/include/cfitsio" #---------------------------------------------------------------------# # Now we check for cfitsio headers and library # #---------------------------------------------------------------------# diff --git a/src/Makefile.am b/src/Makefile.am index 4b35902..148dfb3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,5 @@ bin_PROGRAMS = fits2jpeg -fits2jpeg_SOURCES = fits2jpeg.c getopt.c signal_handler.c - +fits2jpeg_SOURCES = fits2jpeg.c image.c \ + messages.c filesys.c \ + getopt.c signal_handler.c +noinst_HEADERS = fits2jpeg.h \ No newline at end of file diff --git a/src/filesys.c b/src/filesys.c new file mode 100644 index 0000000..e7ff547 --- /dev/null +++ b/src/filesys.c @@ -0,0 +1,87 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +/*Header Definitions*/ +#include "fits2jpeg.h" +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + * MAKE_DIR: Wrapper to mkdir() with some basic error checks + *---------------------------------------------------------------------------*/ +int make_dir(char * folder, mode_t mode) +{ + struct stat st; + int status = 0; + + if (stat(folder, &st) != 0) + { + /* Directory does not exist - make it */ + status = mkdir(folder, mode); + if (status) return status; + } + else if (!S_ISDIR(st.st_mode)) + return status = -1; + return status; +} + +/*---------------------------------------------------------------------------* + * MAKE_TREE: moves through a directory path and creates directories and + * subdirectories using make_dir(), top-down. + *---------------------------------------------------------------------------*/ +int make_tree(char * folder, mode_t mode) +{ + char *pp; + char *sp; + int status = 0; + char *fpath = strdup(folder); + + pp = fpath; + + while (status == 0 && (sp = strchr(pp, '/')) != 0) + { + if (sp != pp) + { + *sp = '\0'; + status = make_dir(fpath, mode); + *sp = '/'; + } + pp = sp + 1; + } + + if (status == 0) status = make_dir(folder, mode); + return status; +} + +/*---------------------------------------------------------------------------* + * STRDUP: This one is not a part of ANSI-strict, so we had to write one + *---------------------------------------------------------------------------*/ +char *strdup(const char *str) +{ + int n = strlen(str) + 1; + char *dup = malloc(n); + if(dup) + { + strcpy(dup, str); + } + return dup; +} 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*/ diff --git a/src/fits2jpeg.h b/src/fits2jpeg.h new file mode 100644 index 0000000..accff93 --- /dev/null +++ b/src/fits2jpeg.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/*Header Definitions*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PROGRAM "fits2jpeg" +#define r2d (90./atan2(1,0)) +#define MAX_TEXT 1024 + +int my_getopt(int, char * const *, const char *); +int make_dir(char *, mode_t); +int make_tree(char *, mode_t); +void banner(void); +void usage(void); +void signals_handler(int); +void set_signals(void); +void printinfo(const char *); +void printwarn(const char *); +void printerro(const char *); +void read_fits(char *, long *, long *, float **); +void scale_pixels(int, unsigned int, float *, JSAMPLE **); +void resize_image(long *, long *, float, JSAMPLE **); +char *strdup(const char *); diff --git a/src/image.c b/src/image.c new file mode 100644 index 0000000..a47b9b7 --- /dev/null +++ b/src/image.c @@ -0,0 +1,252 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +/*Header Definitions*/ +#include "fits2jpeg.h" + +/*---------------------------------------------------------------------------* + * READ_FITS: To reads data from a fits image file.. (isn't that obvious?) + *---------------------------------------------------------------------------*/ +void read_fits(char * fits_file_name, long * xdim, long * ydim, float ** data) +{ + fitsfile *fptr; + int status = 0, nfound, anynull; + long naxes[2]; + long npixels; + float nullval = 0.0; + + fits_open_file(&fptr, fits_file_name, READONLY, &status); + fits_read_keys_lng(fptr, "NAXIS", 1, 2, naxes, &nfound, &status); + if (status) + printerro(strcat(fits_file_name, " <-- Failed to open the file")); + + /* Read in data */ + npixels = naxes[0] * naxes[1]; + (*data) = malloc(sizeof(float) * npixels); + + nullval = 0; + if (fits_read_img(fptr, TFLOAT, 1, npixels, &nullval, (*data), &anynull, + &status)) + printerro(strcat(fits_file_name, " has no valid fits image data")); + + *xdim = naxes[0]; + *ydim = naxes[1]; + + fits_close_file(fptr, &status); +} + +/*---------------------------------------------------------------------------* + * SCALE_PIXELS: Changes the pixel scale to linear/log/sqroot/etc.. + *---------------------------------------------------------------------------*/ +void scale_pixels(int scale, unsigned int npixels, float *data, + JSAMPLE ** image_buffer) +{ + unsigned int i = 0; + int JMAXVAL = 255; + float datamax = 0.0, datamin = 0.0, tmp = 0.0; + float hist[256] = {0.0}, cumhist[256] = {0.0}; + float scl_data = 0.0; + + + /* first find min & max in data */ + datamax = -1.0 * FLT_MAX; + datamin = FLT_MAX; + 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 */ + datamax = (float)JMAXVAL; + datamin = 0.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]; + + /* Allocate image buffer */ + (*image_buffer) = malloc(sizeof(unsigned char) * npixels); + + + /* Linear scale (min-max) : This is the default scaling + * histo-eq will fail if we dont generate image_buffer here */ + for (i = 0; i < npixels; ++i) + (*image_buffer)[i] = (int)(data[i]); + + /*-----------------------------------------------------------------------*/ + + + switch (scale) + { + case 1 : /* Square root */ + 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 */ + 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 */ + 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 */ + 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 */ + /* 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; + + case 6 : /* histogram equalization */ + for (i = 0; i < npixels; ++i) + (*image_buffer)[i] = cumhist[(*image_buffer)[i]] * JMAXVAL; + break; + default : + break; + } +} + +/*---------------------------------------------------------------------------* + * RESIZE_IMAGE: Scales down/up the image_buffer using bilinear scaling + * Based on an article by "John" at + * http://tech-algorithm.com/articles/bilinear-image-scaling/ + *---------------------------------------------------------------------------*/ +void resize_image(long *xdim, long *ydim, float zoomfact, + JSAMPLE ** image_buffer) +{ + int offset = 0, index = 0; + int A, B, C, D, x, y, gray; + JSAMPLE *buff; + unsigned int i = 0, j = 0; + unsigned long npixels = 0; + long w = *xdim, h = *ydim; + long zxdim = 0, zydim = 0; + float xdiff, ydiff, xratio, yratio; + + zxdim = (int)(w * zoomfact); + zydim = (int)(h * zoomfact); + + npixels= zxdim * zydim; + + xratio = ((float)(w - 1))/zxdim; + yratio = ((float)(h - 1))/zydim; + + /* allocate space for *buff */ + buff = malloc(sizeof(unsigned char) * zxdim * zydim); + + index = 0; + offset = 0; + for (i = 0; i < zydim; i++) + { + y = (int)(yratio * i); + ydiff = (yratio * i) - y; + + for (j = 0; j < zxdim; j++) + { + x = (int)(xratio * j); + + xdiff = (xratio * j) - x; + index = y * w + x; + + A = (*image_buffer)[index] & 0xff; + B = (*image_buffer)[index + 1] & 0xff; + C = (*image_buffer)[index + w] & 0xff; + D = (*image_buffer)[index + w + 1] & 0xff; + + gray = (int)(A * (1 - xdiff) * (1 - ydiff) + + B * (xdiff) * (1 - ydiff) + + C * (ydiff) * (1 - xdiff) + + D * (xdiff) * (ydiff) + ); + buff[offset++] = gray; + } + } + *xdim = zxdim; + *ydim = zydim; + (*image_buffer) = realloc((*image_buffer), sizeof(unsigned char) * npixels); + for (i = 0; i < npixels; ++i) + (*image_buffer)[i] = buff[i]; + free(buff); +} diff --git a/src/messages.c b/src/messages.c new file mode 100644 index 0000000..ed4063e --- /dev/null +++ b/src/messages.c @@ -0,0 +1,99 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +/*Header Definitions*/ +#include "fits2jpeg.h" + +/*---------------------------------------------------------------------------*/ +void 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 [options] \n"); + printf (" Name of fits image file is mandatory.\n"); + printf (" Optional parameters are listed below: \n\n"); + printf (" -h help \n"); + printf (" Print this help message and exit \n\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\n"); + printf (" -n \n"); + printf (" Negate the image \n\n"); + printf (" -q \n"); + printf (" quality factor. Defines the jpeg encoding quality \n"); + printf (" Valid range: 0-100, default value: 100 (max.quality)\n\n"); + printf (" -d \n"); + printf (" Write jpeg file to this specified directory. Will \n"); + printf (" create it if needed. Default is to write jpeg in the\n"); + printf (" same directory as fits image file \n\n"); + printf (" -r : \n"); + printf (" Clip output image to min-max range. Eg: \n"); + printf (" 0:100 Use only values in the range 0-100 \n"); + printf (" 100:0 Same as above, but negative image \n"); + printf (" :10 Clip everything above 10 \n"); + printf (" 10: Clip everything below 10 \n\n"); + printf (" -z \n"); + printf (" Resize/Scale output image by . Eg: \n"); + printf (" 0.5 Shrink output to half of input \n"); + printf (" 2.0 Magnify output to double the size \n"); + printf (" Allowed range: 0.01 to 4.0 \n"); + printf (" NOTE: Zooming will be carried out after all other \n"); + printf (" operations, before writing out jpeg image \n\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); +} + +void printinfo(const char * msg) +{ + fprintf(stdout, "INFO : %s\n", msg); +} + +void printwarn(const char * msg) +{ + fprintf(stdout, "WARNING: %s\n", msg); +} + +void printerro(const char * msg) +{ + fprintf(stderr, "ERROR : %s\n", msg); + exit(EXIT_FAILURE); +} + -- 2.12.1