1 /***************************************************************************
2 * This file is a part of CADS/UVS fits2jpeg conversion software *
3 * Copyright (C) 2012 by CADS/UV Software Team, *
4 * Indian Institute of Astrophysics *
5 * Bangalore 560034 *
6 * cads_AT_iiap.res.in *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 /*---------------------------------------------------------------------------
24 This program will write out FITS data into a jpeg file.
25 Assume that data are in first extension and are two dimensional
27 Libraries needed are CFITSIO, JPEG
28 Original author: Jayant Murthy
29 Last Modification: 11/05/02
31 Reconstruction and additional features: Reks
32 *---------------------------------------------------------------------------*/
34 /*---------------------------------------------------------------------------
35 Modification History
37 Reks, 5th October 2007: v0.01
38 1. configure checks for jpeglib.
39 optional extra arguments --with-jpeglib=<location>
40 --with-cfitsio=<location>
41 2. Makes blank images! datamin and max are not set..
43 Reks, 6th October 2007: v0.10
44 1. Added 2 functions to fetch max and min from image
45 2. user can choose various scales like log/square/square-root
46 3. Increased verbosity, added banner, help message, etc
47 4. Inputs through getopt. will Ask if mandatory input (fits file) is not
48 provided.
49 5. fitsio2
51 Reks, 10th October 2007: v0.9.0 (close to 1.0)
52 1. Found our niche :-) Can handle wild cards at command line,
53 batch processing.
54 2. Now users cannot specify the output file name though.. Its fixed to
55 <input_file_root>.jpg.
56 3. No getopt for input file.. getopt is limited to various image scaling
57 options.
59 Reks, 17th October 2007, v0.9.5
60 1. Merged all image scaling options into one input param: -s
61 optarg (from getopt) will decide scaling function. Now there is
62 enough room for additional flags (in future).
64 Reks, 22 June 2010 v1.0.0
65 1. Removed datamax() and datamin(). That was required only once!
66 2. option histoeq shifted to image enhancement option
67 3. Added "normalize" option
68 Now users can do scaling + enhance (if at all someone feels like it)
69 4. All options tested. First stable release :)
71 Reks 28 June 2012
72 1. rebranded to CADS/UVS
74 Reks 05-10 July 2012 v2.0
75 1. Merged scale & operations to single flag
76 2. added fits2jpeg.h, help/banner functions moved to messages.c
77 3. Options to clip image min/max
78 4. negate image option
79 5. jpeg quality factor
80 6. pixel scaling operations moved to image.c
81 7. Image resizing
82 8. moved fits read to image.c
83 9. Option to specify output directory
85 Reks Oct/Nov 2012 v2.1
86 1. Fixed a segfault on zero/blank fits images
87 *---------------------------------------------------------------------------*/
89 #include "fits2jpeg.h"
91 char *optarg;
92 int optindex;
94 /*--------------------------- Begin Main Progam -----------------------------*/
95 int main(int argc, char *argv[], char *envp[])
96 {
97 int scale = 0, jpgqual = 100, status = 0;
98 unsigned int i = 0, j = 0;
99 unsigned int customdir = 0, usrclip = 0, usrnegt = 0, usrzoom = 0;
100 long xdim = 0, ydim = 0, row_stride;
101 unsigned long npixels = 0;
102 float datamin = 0.0, datamax = 0.0, zoomfact = 1.0;
103 float *data;
104 char jpeg_file_name[MAX_TEXT] = "", fits_file_name[MAX_TEXT] = "";
105 char output_dir[MAX_TEXT] = "";
106 char *tmpstr, *sptr;
108 int opt; /* For getopt */
109 extern char *optarg;
110 extern int optindex;
111 mode_t mode = 0755;
112 FILE *jpeg_file;
113 struct jpeg_error_mgr jerr;
114 struct jpeg_compress_struct cinfo;
115 JSAMPROW row_pointer[1];
116 JSAMPLE *image_buffer;
117 /*---------------- End of variable initialization -----------------------*/
119 banner(); /* Header: Talks about program, version & purpose */
120 set_signals(); /* Trap un-natural exits */
122 /*-------------------- Parse command line inputs ------------------------*/
124 if (argc < 2) usage(); /* People who don't give any arguments need help */
125 while ( ( opt = my_getopt ( argc, argv, "d:e:hnq:r:s:z:" ) ) != EOF )
126 switch ( opt )
127 {
128 case 's':
129 if (strcmp(optarg, "linear") == 0) scale = 0;
130 else if (strcmp(optarg, "sqroot") == 0)
131 {
132 printinfo("Using square-root scale");
133 scale = 1;
134 }
135 else if (strcmp(optarg, "square") == 0)
136 {
137 printinfo("Using quadratic scale");
138 scale = 2;
139 }
140 else if (strcmp(optarg, "cubic") == 0)
141 {
142 printinfo("Using cubic scale");
143 scale = 3;
144 }
145 else if (strcmp(optarg, "log") == 0)
146 {
147 printinfo("Using log scale");
148 scale = 4;
149 }
150 else if (strcmp(optarg, "normalize") == 0)
151 {
152 printinfo("Performing histogram stretch (normalization)");
153 scale = 5;
154 }
155 else if (strcmp(optarg, "equalize") == 0)
156 {
157 printinfo("Performing Histogram Equalization");
158 scale = 6;
159 }
160 else
161 {
162 printwarn(strcat(optarg, " -- Unrecognized option"));
163 scale = 0;
164 }
165 break;
167 case 'e':
168 /* Need to preserve it for backward compatibility */
169 if (strcmp(optarg, "normalize") == 0) scale = 5;
170 else if (strcmp(optarg, "equalize") == 0) scale = 6;
171 else
172 printerro(strcat(optarg, " -- Unrecognized option"));
173 break;
175 case 'r':
176 tmpstr = optarg; /* make a copy.. and leave optarg alone */
177 sptr = strpbrk(tmpstr, ":"); /* Find the delimiter */
178 if (sptr == NULL)
179 printerro("Expected a ':' as separator for min/max");
181 if (sptr+1 == tmpstr + strlen(tmpstr)) /* -c <datamin>: */
182 datamax = FLT_MAX;
183 else
184 datamax = atof(sptr+1);
186 /* There should be an easier way to find datamin alongside datamax,
187 * but I am too sleepy to try anything now */
188 sptr = strchr(tmpstr, ':');
189 if (sptr == tmpstr) /* -c :<datamax> */
190 datamin = -1.0*FLT_MAX;
191 else
192 {
193 sptr = strtok(tmpstr, ":");
194 datamin = atof(sptr);
195 }
197 /* Remember.. now we have user specified range */
198 usrclip = 1;
199 break;
201 case 'n' :
202 usrnegt = 1;
203 break;
205 case 'q' :
206 jpgqual = atoi(optarg);
207 if (jpgqual < 0) jpgqual = 0;
208 if (jpgqual > 100) jpgqual = 100;
209 printf("INFO : jpeg quality factor changed to %d\n", jpgqual);
210 break;
212 case 'z' :
213 zoomfact = atof(optarg);
214 zoomfact = fabs(zoomfact);
215 if (zoomfact < 0.01) zoomfact = 0.01;
216 if (zoomfact > 4.0) zoomfact = 4.0;
217 usrzoom = 1;
218 break;
220 case 'd':
221 strcpy(output_dir, optarg);
222 printf("INFO : Output image directory is %s\n", output_dir);
223 customdir = 1;
224 status = make_tree(output_dir, mode);
225 if (status != 0) printerro("Unable to create output directory");
226 break;
228 case 'h':
229 usage();
230 break;
232 default :
233 printerro("You can try 'fits2jpeg -h' for valid options");
234 break;
235 }
236 if (scale == 0) printinfo("Using linear scale");
237 if ((argc - optindex) == 0) usage(); /* Someone gave only options */
239 /*---------------------- Begin processing files -------------------------*/
241 /* Getopt would have processed all argument with a "-" in front. optindex
242 is the counter, which keeps the number of options supplied. Whatever
243 remains in the list of command line arguments are the fits files.
244 NOTE: POSIX systems will do the regex matching and expand wild card
245 entries for us. Even windoze XP Pro is known to do that... */
246 for (j = optindex; j < argc; j++)
247 {
249 strcpy(fits_file_name, argv[j]);
251 strcpy(jpeg_file_name, fits_file_name);
252 strtok(jpeg_file_name, ".");
253 strcat(jpeg_file_name, ".jpg");
255 if (customdir == 1)
256 {
257 if (output_dir[strlen(output_dir) - 1] != '/')
258 strcat(output_dir, "/");
260 strcat(output_dir, basename(jpeg_file_name));
261 strcpy(jpeg_file_name, output_dir);
262 }
264 read_fits(fits_file_name, &xdim, &ydim, &data);
265 npixels = xdim * ydim;
267 printf("INFO : data input from %s\n", fits_file_name);
270 /* Now we need to look at user options.. */
271 /*-------------------------------------------------------------------*/
273 /* IF user has provided a range, fix them as min & max in image */
274 if (usrclip == 1)
275 {
276 printinfo("user defined pixel range");
277 for (i = 0; i < npixels; ++i)
278 {
279 if (data[i] > datamax) data[i] = datamax;
280 if (data[i] < datamin) data[i] = datamin;
281 } /*endfor*/
282 }
284 scale_pixels(scale, npixels, data, &image_buffer);
286 /* Before we write jpeg, check if there is any requirement to negate
287 * the image (usrnegt = 1) */
288 if (usrnegt == 1)
289 {
290 printinfo("Negating Image");
291 for (i = 0; i < npixels; ++i) image_buffer[i] ^= 0xff;
292 }
294 if (usrzoom == 1)
295 {
296 printf("INFO : Image zoom factor = %3.2f\n", zoomfact);
297 resize_image(&xdim, &ydim, zoomfact, &image_buffer);
298 }
300 /*Write out data into JPEG file*/
301 jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/
302 if (!jpeg_file) printerro("Unable to create output file");
303 cinfo.err = jpeg_std_error(&jerr); /* JPEG error handler */
304 jpeg_create_compress(&cinfo); /* JPEG initialization */
305 jpeg_stdio_dest(&cinfo, jpeg_file); /* Send compressed data to stdio */
306 cinfo.image_width = xdim; /* Image width */
307 cinfo.image_height = ydim; /* Image height */
308 cinfo.input_components = 1; /* Number of colors per pixel */
309 cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
310 jpeg_set_defaults(&cinfo); /* Set JPEG defaults */
311 jpeg_set_quality(&cinfo, jpgqual, TRUE); /* Set jpeg quality factor */
312 jpeg_start_compress(&cinfo, TRUE); /* default data compression */
313 row_stride = xdim; /* JSAMPLEs per row inimage buffer */
315 /* Now we have to turn the data upside down */
316 while (cinfo.next_scanline < cinfo.image_height)
317 {
318 row_pointer[0] = &image_buffer[(cinfo.image_height -
319 cinfo.next_scanline) *
320 row_stride];
322 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
323 }/*Loop through file writing one line at a time*/
325 jpeg_finish_compress(&cinfo); /* Finish compression */
326 fclose(jpeg_file); /* Close file */
327 jpeg_destroy_compress(&cinfo); /* Release memory */
329 free(data);
330 free(image_buffer);
331 printf("INFO : wrote output to %s\n", jpeg_file_name);
332 }
333 exit(EXIT_SUCCESS);
334 } /*End of program*/