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