1 #ifndef lint
RCSid()2 static char *RCSid() { return RCSid("$Id: breaders.c,v 1.12 2012/06/08 17:33:41 sfeam Exp $"); }
3 #endif
4 
5 /* GNUPLOT - breaders.c */
6 
7 /*[
8  * Copyright 2004  Petr Mikulik
9  *
10  * As part of the program Gnuplot, which is
11  *
12  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
13  *
14  * Permission to use, copy, and distribute this software and its
15  * documentation for any purpose with or without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and
17  * that both that copyright notice and this permission notice appear
18  * in supporting documentation.
19  *
20  * Permission to modify the software is granted, but not the right to
21  * distribute the complete modified source code.  Modifications are to
22  * be distributed as patches to the released version.  Permission to
23  * distribute binaries produced by compiling modified sources is granted,
24  * provided you
25  *   1. distribute the corresponding source modifications from the
26  *    released version in the form of a patch file along with the binaries,
27  *   2. add special version identification to distinguish your version
28  *    in addition to the base release version number,
29  *   3. provide your name and address as the primary contact for the
30  *    support of your modified version, and
31  *   4. retain our contact information in regard to use of the base
32  *    software.
33  * Permission to distribute the released version of the source code along
34  * with corresponding source modifications in the form of a patch file is
35  * granted with same provisions 2 through 4 for binary distributions.
36  *
37  * This software is provided "as is" without express or implied warranty
38  * to the extent permitted by applicable law.
39 ]*/
40 
41 /* AUTHOR : Petr Mikulik */
42 
43 /*
44  * Readers to set up binary data file information for particular formats.
45  */
46 
47 #include "breaders.h"
48 #include "datafile.h"
49 #include "alloc.h"
50 #include "misc.h"
51 
52 /*
53  * Reader for the ESRF Header File format files (EDF / EHF).
54  */
55 
56 /* Inside datafile.c, but kept hidden. */
57 extern int df_no_bin_cols;	/* cols to read */
58 extern df_endianess_type df_bin_file_endianess;
59 extern TBOOLEAN df_matrix_file, df_binary_file;
60 extern void *df_pixeldata;
61 
62 /* Reader for the ESRF Header File format files (EDF / EHF).
63  */
64 
65 /* gen_table4 */
66 struct gen_table4 {
67     const char *key;
68     int value;
69     short signum; /* 0..unsigned, 1..signed, 2..float or double */
70     short sajzof; /* sizeof on 32bit architecture */
71 };
72 
73 /* Exactly like lookup_table_nth from tables.c, but for gen_table4 instead
74  * of gen_table.
75  */
76 static int
lookup_table4_nth(const struct gen_table4 * tbl,const char * search_str)77 lookup_table4_nth(const struct gen_table4 *tbl, const char *search_str)
78 {
79     int k = -1;
80     while (tbl[++k].key)
81 	if (tbl[k].key && !strncmp(search_str, tbl[k].key, strlen(tbl[k].key)))
82 	    return k;
83     return -1; /* not found */
84 }
85 
86 static const struct gen_table4 edf_datatype_table[] =
87 {
88     { "UnsignedByte",	DF_UCHAR,   0, 1 },
89     { "SignedByte",	DF_CHAR,    1, 1 },
90     { "UnsignedShort",	DF_USHORT,  0, 2 },
91     { "SignedShort",	DF_SHORT,   1, 2 },
92     { "UnsignedInteger",DF_UINT,    0, 4 },
93     { "SignedInteger",	DF_INT,	    1, 4 },
94     { "UnsignedLong",	DF_ULONG,   0, 8 },
95     { "SignedLong",	DF_LONG,    1, 8 },
96     { "FloatValue",	DF_FLOAT,   2, 4 },
97     { "DoubleValue",	DF_DOUBLE,  2, 8 },
98     { "Float",		DF_FLOAT,   2, 4 }, /* Float and FloatValue are synonyms */
99     { "Double",		DF_DOUBLE,  2, 8 }, /* Double and DoubleValue are synonyms */
100     { NULL, -1, -1, -1 }
101 };
102 
103 static const struct gen_table edf_byteorder_table[] =
104 {
105     { "LowByteFirst",	DF_LITTLE_ENDIAN }, /* little endian */
106     { "HighByteFirst",	DF_BIG_ENDIAN },    /* big endian */
107     { NULL, -1 }
108 };
109 
110 /* Orientation of axes of the raster, as the binary matrix is saved in
111  * the file.
112  */
113 enum EdfRasterAxes {
114     EDF_RASTER_AXES_XrightYdown,	/* matricial format: rows, columns */
115     EDF_RASTER_AXES_XrightYup		/* cartesian coordinate system */
116     /* other 6 combinations not available (not needed until now) */
117 };
118 
119 static const struct gen_table edf_rasteraxes_table[] =
120 {
121     { "XrightYdown",	EDF_RASTER_AXES_XrightYdown },
122     { "XrightYup",	EDF_RASTER_AXES_XrightYup },
123     { NULL, -1 }
124 };
125 
126 
127 /* Find value_ptr as pointer to the parameter of the given key in the header.
128  * Returns NULL on success.
129  */
130 static char*
edf_findInHeader(const char * header,const char * key)131 edf_findInHeader ( const char* header, const char* key )
132 {
133     char *value_ptr = strstr( header, key );
134 
135     if (!value_ptr)
136 	return NULL;
137     /* an edf line is "key     = value ;" */
138     value_ptr = 1 + strchr(value_ptr + strlen(key), '=');
139     while (isspace((unsigned char)*value_ptr))
140 	value_ptr++;
141     return value_ptr;
142 }
143 
144 void
edf_filetype_function(void)145 edf_filetype_function(void)
146 {
147     FILE *fp;
148     char *header = NULL;
149     int header_size = 0;
150     char *p;
151     int k;
152     /* open (header) file */
153     fp = loadpath_fopen(df_filename, "rb");
154     if (!fp)
155 	os_error(NO_CARET, "Can't open data file \"%s\"", df_filename);
156     /* read header: it is a multiple of 512 B ending by "}\n" */
157     while (header_size == 0 || strncmp(&header[header_size-2],"}\n",2)) {
158 	int header_size_prev = header_size;
159 	header_size += 512;
160 	if (!header)
161 	    header = gp_alloc(header_size+1, "EDF header");
162 	else
163 	    header = gp_realloc(header, header_size+1, "EDF header");
164 	header[header_size_prev] = 0; /* protection against empty file */
165 	k = fread(header+header_size_prev, 512, 1, fp);
166 	if (k == 0) { /* protection against indefinite loop */
167 	    free(header);
168 	    os_error(NO_CARET, "Damaged EDF header of %s: not multiple of 512 B.\n", df_filename);
169 	}
170 	header[header_size] = 0; /* end of string: protection against strstr later on */
171     }
172     fclose(fp);
173     /* make sure there is a binary record structure for each image */
174     if (df_num_bin_records < 1)
175 	df_add_binary_records(1-df_num_bin_records, DF_CURRENT_RECORDS); /* otherwise put here: number of images (records) from this file */
176     if ((p = edf_findInHeader(header, "EDF_BinaryFileName"))) {
177 	int plen = strcspn(p, " ;\n");
178 	df_filename = gp_realloc(df_filename, plen+1, "datafile name");
179 	strncpy(df_filename, p, plen);
180 	df_filename[plen] = '\0';
181 	if ((p = edf_findInHeader(header, "EDF_BinaryFilePosition")))
182 	    df_bin_record[0].scan_skip[0] = atoi(p);
183 	else
184 	    df_bin_record[0].scan_skip[0] = 0;
185     } else
186 	df_bin_record[0].scan_skip[0] = header_size; /* skip header */
187     /* set default values */
188     df_bin_record[0].scan_dir[0] = 1;
189     df_bin_record[0].scan_dir[1] = -1;
190     df_bin_record[0].scan_generate_coord = TRUE;
191     df_bin_record[0].cart_scan[0] = DF_SCAN_POINT;
192     df_bin_record[0].cart_scan[1] = DF_SCAN_LINE;
193     df_extend_binary_columns(1);
194     df_set_skip_before(1,0);
195     df_set_skip_after(1,0);
196     df_no_use_specs = 1;
197     use_spec[0].column = 1;
198     /* now parse the header */
199     if ((p = edf_findInHeader(header, "Dim_1")))
200 	df_bin_record[0].scan_dim[0] = atoi(p);
201     if ((p = edf_findInHeader(header, "Dim_2")))
202 	df_bin_record[0].scan_dim[1] = atoi(p);
203     if ((p = edf_findInHeader(header, "DataType"))) {
204 	k = lookup_table4_nth(edf_datatype_table, p);
205 	if (k >= 0) { /* known EDF DataType */
206 	    int s = edf_datatype_table[k].sajzof;
207 	    switch (edf_datatype_table[k].signum) {
208 		case 0: df_set_read_type(1,SIGNED_TEST(s)); break;
209 		case 1: df_set_read_type(1,UNSIGNED_TEST(s)); break;
210 		case 2: df_set_read_type(1,FLOAT_TEST(s)); break;
211 	    }
212 	}
213     }
214     if ((p = edf_findInHeader(header, "ByteOrder"))) {
215 	k = lookup_table_nth(edf_byteorder_table, p);
216 	if (k >= 0)
217 	    df_bin_file_endianess = edf_byteorder_table[k].value;
218     }
219     /* Origin vs center: EDF specs allows only Center, but it does not hurt if
220        Origin is supported as well; however, Center rules if both specified.
221     */
222     if ((p = edf_findInHeader(header, "Origin_1"))) {
223 	df_bin_record[0].scan_cen_or_ori[0] = atof(p);
224 	df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_ORIGIN;
225     }
226     if ((p = edf_findInHeader(header, "Origin_2"))) {
227 	df_bin_record[0].scan_cen_or_ori[1] = atof(p);
228 	df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_ORIGIN;
229     }
230     if ((p = edf_findInHeader(header, "Center_1"))) {
231 	df_bin_record[0].scan_cen_or_ori[0] = atof(p);
232 	df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_CENTER;
233     }
234     if ((p = edf_findInHeader(header, "Center_2"))) {
235 	df_bin_record[0].scan_cen_or_ori[1] = atof(p);
236 	df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_CENTER;
237     }
238     /* now pixel sizes and raster orientation */
239     if ((p = edf_findInHeader(header, "PSize_1")))
240 	df_bin_record[0].scan_delta[0] = atof(p);
241     if ((p = edf_findInHeader(header, "PSize_2")))
242 	df_bin_record[0].scan_delta[1] = atof(p);
243     if ((p = edf_findInHeader(header, "RasterAxes"))) {
244 	k = lookup_table_nth(edf_rasteraxes_table, p);
245 	switch (k) {
246 	    case EDF_RASTER_AXES_XrightYup:
247 		df_bin_record[0].scan_dir[0] = 1;
248 		df_bin_record[0].scan_dir[1] = 1;
249 		df_bin_record[0].cart_scan[0] = DF_SCAN_POINT;
250 		df_bin_record[0].cart_scan[1] = DF_SCAN_LINE;
251 		break;
252 	    default: /* also EDF_RASTER_AXES_XrightYdown */
253 		df_bin_record[0].scan_dir[0] = 1;
254 		df_bin_record[0].scan_dir[1] = -1;
255 		df_bin_record[0].cart_scan[0] = DF_SCAN_POINT;
256 		df_bin_record[0].cart_scan[1] = DF_SCAN_LINE;
257 	}
258     }
259 
260     free(header);
261 
262 }
263 
264 /*
265  *	Use libgd for input of binary images in PNG GIF JPEG formats
266  *	Ethan A Merritt - August 2009
267  */
268 
269 #define GD_PNG 1
270 #define GD_GIF 2
271 #define GD_JPEG 3
272 void gd_filetype_function __PROTO((int filetype));
273 
274 void
png_filetype_function(void)275 png_filetype_function(void)
276 {
277     gd_filetype_function(GD_PNG);
278 }
279 
280 void
gif_filetype_function(void)281 gif_filetype_function(void)
282 {
283     gd_filetype_function(GD_GIF);
284 }
285 
286 void
jpeg_filetype_function(void)287 jpeg_filetype_function(void)
288 {
289     gd_filetype_function(GD_JPEG);
290 }
291 
292 #ifndef HAVE_GD_PNG
293 
294 void
gd_filetype_function(int type)295 gd_filetype_function(int type)
296 {
297     int_error(NO_CARET, "This copy of gnuplot cannot read png/gif/jpeg images");
298 }
299 
300 int
df_libgd_get_pixel(int i,int j,int component)301 df_libgd_get_pixel(int i, int j, int component) { return 0; }
302 
303 #else
304 
305 #include <gd.h>
306 static gdImagePtr im = NULL;
307 
308 void
gd_filetype_function(int filetype)309 gd_filetype_function(int filetype)
310 {
311     FILE *fp;
312     unsigned int M, N;
313 
314     /* free previous image, if any */
315     if (im) {
316 	gdImageDestroy(im);
317 	im = NULL;
318     }
319 
320     /* read image into memory */
321     fp = loadpath_fopen(df_filename, "rb");
322     if (!fp)
323 	int_error(NO_CARET, "Can't open data file \"%s\"", df_filename);
324 
325     switch(filetype) {
326 	case GD_PNG:	im = gdImageCreateFromPng(fp); break;
327 	case GD_GIF:
328 #ifdef HAVE_GD_GIF
329 			im = gdImageCreateFromGif(fp);
330 #endif
331 			break;
332 	case GD_JPEG:
333 #ifdef HAVE_GD_JPEG
334 			im = gdImageCreateFromJpeg(fp);
335 #endif
336 	default:	break;
337     }
338     fclose(fp);
339 
340     if (!im)
341 	int_error(NO_CARET, "libgd doesn't recognize the format of \"%s\"", df_filename);
342 
343     /* check on image properties and complain if we can't handle them */
344     M = im->sx;
345     N = im->sy;
346     FPRINTF((stderr,"This is a %u X %u %s image\n",M,N,
347 		im->trueColor ? "TrueColor" : "palette"));
348 
349     df_pixeldata = im->trueColor ? (void *)im->tpixels : (void *)im->pixels;
350     df_matrix_file = FALSE;
351     df_binary_file = TRUE;
352 
353     df_bin_record[0].scan_skip[0] = 0;
354     df_bin_record[0].scan_dim[0] = M;
355     df_bin_record[0].scan_dim[1] = N;
356 
357     df_bin_record[0].scan_dir[0] = 1;
358     df_bin_record[0].scan_dir[1] = -1;
359     df_bin_record[0].scan_generate_coord = TRUE;
360     df_bin_record[0].cart_scan[0] = DF_SCAN_POINT;
361     df_bin_record[0].cart_scan[1] = DF_SCAN_LINE;
362 
363     df_extend_binary_columns(4);
364     df_set_read_type(1, DF_UCHAR);
365     df_set_read_type(2, DF_UCHAR);
366     df_set_read_type(3, DF_UCHAR);
367     df_set_read_type(4, DF_UCHAR);
368     df_set_skip_before(1,0);
369 
370     df_no_use_specs = 4;
371     use_spec[0].column = 1;
372     use_spec[1].column = 2;
373     use_spec[2].column = 3;
374     use_spec[3].column = 4;
375 }
376 
377 int
df_libgd_get_pixel(int i,int j,int component)378 df_libgd_get_pixel(int i, int j, int component)
379 {
380     static int pixel;
381     int alpha;
382 
383     switch(component) {
384     case 0:	pixel = gdImageGetTrueColorPixel(im, i,j);
385     		return gdTrueColorGetRed(pixel);
386     case 1:	return gdTrueColorGetGreen(pixel);
387     case 2:	return gdTrueColorGetBlue(pixel);
388     case 3:	/* FIXME? Supposedly runs from 0-127 rather than 0-255 */
389 		alpha = 2 * gdTrueColorGetAlpha(pixel);
390 		return (255-alpha);
391     default:	return 0; /* shouldn't happen */
392     }
393 }
394 
395 #endif
396