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 plans
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
84 *---------------------------------------------------------------------------*/
86 #include "fits2jpeg.h"
88 char *optarg;
89 int optindex;
91 /*--------------------------- Begin Main Progam -----------------------------*/
92 int main(int argc, char *argv[], char *envp[])
93 {
94 int scale = 0, jpgqual = 100, status = 0;
95 unsigned int i = 0, j = 0;
96 unsigned int customdir = 0, usrclip = 0, usrnegt = 0, usrzoom = 0;
97 long xdim = 0, ydim = 0, row_stride;
98 unsigned long npixels = 0;
99 float datamin = 0.0, datamax = 0.0, zoomfact = 1.0;
100 float *data;
101 char jpeg_file_name[MAX_TEXT] = "", fits_file_name[MAX_TEXT] = "";
102 char output_dir[MAX_TEXT] = "";
103 char *tmpstr, *sptr;
105 int opt; /* For getopt */
106 extern char *optarg;
107 extern int optindex;
108 mode_t mode = 0755;
109 FILE *jpeg_file;
110 struct jpeg_error_mgr jerr;
111 struct jpeg_compress_struct cinfo;
112 JSAMPROW row_pointer[1];
113 JSAMPLE *image_buffer;
114 /*---------------- End of variable initialization -----------------------*/
116 banner(); /* Header: Talks about program, version & purpose */
117 set_signals(); /* Trap un-natural exits */
119 /*-------------------- Parse command line inputs ------------------------*/
121 if (argc < 2) usage(); /* People who don't give any arguments need help */
122 while ( ( opt = my_getopt ( argc, argv, "d:e:hnq:r:s:z:" ) ) != EOF )
123 switch ( opt )
124 {
125 case 's':
126 if (strcmp(optarg, "linear") == 0) scale = 0;
127 else if (strcmp(optarg, "sqroot") == 0)
128 {
129 printinfo("Using square-root scale");
130 scale = 1;
131 }
132 else if (strcmp(optarg, "square") == 0)
133 {
134 printinfo("Using quadratic scale");
135 scale = 2;
136 }
137 else if (strcmp(optarg, "cubic") == 0)
138 {
139 printinfo("Using cubic scale");
140 scale = 3;
141 }
142 else if (strcmp(optarg, "log") == 0)
143 {
144 printinfo("Using log scale");
145 scale = 4;
146 }
147 else if (strcmp(optarg, "normalize") == 0)
148 {
149 printinfo("Performing histogram stretch (normalization)");
150 scale = 5;
151 }
152 else if (strcmp(optarg, "equalize") == 0)
153 {
154 printinfo("Performing Histogram Equalization");
155 scale = 6;
156 }
157 else
158 {
159 printwarn(strcat(optarg, " -- Unrecognized option"));
160 scale = 0;
161 }
162 break;
164 case 'e':
165 /* Need to preserve it for backward compatibility */
166 if (strcmp(optarg, "normalize") == 0) scale = 5;
167 else if (strcmp(optarg, "equalize") == 0) scale = 6;
168 else
169 printerro(strcat(optarg, " -- Unrecognized option"));
170 break;
172 case 'r':
173 tmpstr = optarg; /* make a copy.. and leave optarg alone */
174 sptr = strpbrk(tmpstr, ":"); /* Find the delimiter */
175 if (sptr == NULL)
176 printerro("Expected a ':' as separator for min/max");
178 if (sptr+1 == tmpstr + strlen(tmpstr)) /* -c <datamin>: */
179 datamax = FLT_MAX;
180 else
181 datamax = atof(sptr+1);
183 /* There should be an easier way to find datamin alongside datamax,
184 * but I am too sleepy to try anything now */
185 sptr = strchr(tmpstr, ':');
186 if (sptr == tmpstr) /* -c :<datamax> */
187 datamin = -1.0*FLT_MAX;
188 else
189 {
190 sptr = strtok(tmpstr, ":");
191 datamin = atof(sptr);
192 }
194 /* Remember.. now we have user specified range */
195 usrclip = 1;
196 break;
198 case 'n' :
199 usrnegt = 1;
200 break;
202 case 'q' :
203 jpgqual = atoi(optarg);
204 if (jpgqual < 0) jpgqual = 0;
205 if (jpgqual > 100) jpgqual = 100;
206 printf("INFO : jpeg quality factor changed to %d\n", jpgqual);
207 break;
209 case 'z' :
210 zoomfact = atof(optarg);
211 zoomfact = fabs(zoomfact);
212 if (zoomfact < 0.01) zoomfact = 0.01;
213 if (zoomfact > 4.0) zoomfact = 4.0;
214 usrzoom = 1;
215 break;
217 case 'd':
218 strcpy(output_dir, optarg);
219 printf("INFO : Output image directory is %s\n", output_dir);
220 customdir = 1;
221 status = make_tree(output_dir, mode);
222 if (status != 0) printerro("Unable to create output directory");
223 break;
225 case 'h':
226 usage();
227 break;
229 default :
230 printerro("You can try 'fits2jpeg -h' for valid options");
231 break;
232 }
233 if (scale == 0) printinfo("Using linear scale");
234 if ((argc - optindex) == 0) usage(); /* Someone gave only options */
236 /*---------------------- Begin processing files -------------------------*/
238 /* Getopt would have processed all argument with a "-" in front. optindex
239 is the counter, which keeps the number of options supplied. Whatever
240 remains in the list of command line arguments are the fits files.
241 NOTE: POSIX systems will do the regex matching and expand wild card
242 entries for us. Even windoze XP Pro is known to do that... */
243 for (j = optindex; j < argc; j++)
244 {
246 strcpy(fits_file_name, argv[j]);
248 strcpy(jpeg_file_name, fits_file_name);
249 strtok(jpeg_file_name, ".");
250 strcat(jpeg_file_name, ".jpg");
252 if (customdir == 1)
253 {
254 if (output_dir[strlen(output_dir) - 1] != '/')
255 strcat(output_dir, "/");
257 strcat(output_dir, basename(jpeg_file_name));
258 strcpy(jpeg_file_name, output_dir);
259 }
261 read_fits(fits_file_name, &xdim, &ydim, &data);
262 npixels = xdim * ydim;
264 printf("INFO : data input from %s\n", fits_file_name);
267 /* Now we need to look at user options.. */
268 /*-------------------------------------------------------------------*/
270 /* IF user has provided a range, fix them as min & max in image */
271 if (usrclip == 1)
272 {
273 printinfo("user defined pixel range");
274 for (i = 0; i < npixels; ++i)
275 {
276 if (data[i] > datamax) data[i] = datamax;
277 if (data[i] < datamin) data[i] = datamin;
278 } /*endfor*/
279 }
281 scale_pixels(scale, npixels, data, &image_buffer);
283 /* Before we write jpeg, check if there is any requirement to negate
284 * the image (usrnegt = 1) */
285 if (usrnegt == 1)
286 {
287 printinfo("Negating Image");
288 for (i = 0; i < npixels; ++i) image_buffer[i] ^= 0xff;
289 }
291 if (usrzoom == 1)
292 {
293 printf("INFO : Image zoom factor = %3.2f\n", zoomfact);
294 resize_image(&xdim, &ydim, zoomfact, &image_buffer);
295 }
297 /*Write out data into JPEG file*/
298 jpeg_file = fopen(jpeg_file_name, "wb");/* Open JPEG file for writing*/
299 if (!jpeg_file) printerro("Unable to create output file");
300 cinfo.err = jpeg_std_error(&jerr); /* JPEG error handler */
301 jpeg_create_compress(&cinfo); /* JPEG initialization */
302 jpeg_stdio_dest(&cinfo, jpeg_file); /* Send compressed data to stdio */
303 cinfo.image_width = xdim; /* Image width */
304 cinfo.image_height = ydim; /* Image height */
305 cinfo.input_components = 1; /* Number of colors per pixel */
306 cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
307 jpeg_set_defaults(&cinfo); /* Set JPEG defaults */
308 jpeg_set_quality(&cinfo, jpgqual, TRUE); /* Set jpeg quality factor */
309 jpeg_start_compress(&cinfo, TRUE); /* default data compression */
310 row_stride = xdim; /* JSAMPLEs per row inimage buffer */
312 /* Now we have to turn the data upside down */
313 while (cinfo.next_scanline < cinfo.image_height)
314 {
315 row_pointer[0] = &image_buffer[(cinfo.image_height -
316 cinfo.next_scanline) *
317 row_stride];
319 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
320 }/*Loop through file writing one line at a time*/
322 jpeg_finish_compress(&cinfo); /* Finish compression */
323 fclose(jpeg_file); /* Close file */
324 jpeg_destroy_compress(&cinfo); /* Release memory */
326 free(data);
327 free(image_buffer);
328 printf("INFO : wrote output to %s\n", jpeg_file_name);
329 }
330 exit(EXIT_SUCCESS);
331 } /*End of program*/