// This program is free software: you can use, modify and/or redistribute it // under the terms of the simplified BSD License. You should have received a // copy of this license along this program. If not, see // . // // Copyright 2012 Enric Meinhardt-Llopis // All rights reserved. // IIO: a library for reading small images {{{1 // // Goal: load an image (of unknown format) from a given FILE* // // Technique: read the first few bytes of the file to identify the format, and // call the appropriate image library (lipng, lipjpeg, libtiff, etc). For // simple, uncompressed formats, write the loading code by hand. For formats // having a library with a nice API, call the library functions. For other or // unrecognized formats use an external program (convert, anytopnm, // gm convert...) to convert them into a readable format. If anything else // fails, assume that the image is in headings+raw format, and try to extract // its dimensions and headings using some heuristics (file name containing // "%dx%d", headings containing ascii numbers, etc.) // // Difficulties: most image libraries expect to be fed a whole file, not a // beheaded file. Thus, some hackery is necessary. // // // Copyright 2012 Enric Meinhardt-Llopis // #include #include #include #include #include #include #include #include "iio.h" // only for IIO_MAX_DIMENSION #ifdef I_CAN_HAS_LIBPNG // ugly "feature" in png.h forces this header to be included first #include #endif // #defines {{{1 // // configuration // #if _POSIX_C_SOURCE >= 200809L #define I_CAN_HAS_FMEMOPEN 1 #endif #if _POSIX_C_SOURCE >= 200112L #define I_CAN_HAS_MKSTEMP 1 #endif // // enum-like, only used internally // #define IIO_TYPE_INT8 1 #define IIO_TYPE_UINT8 2 #define IIO_TYPE_INT16 3 #define IIO_TYPE_UINT16 4 #define IIO_TYPE_INT32 5 #define IIO_TYPE_UINT32 6 #define IIO_TYPE_FLOAT 7 #define IIO_TYPE_DOUBLE 8 #define IIO_TYPE_LONGDOUBLE 9 #define IIO_TYPE_INT64 10 #define IIO_TYPE_UINT64 11 #define IIO_TYPE_HALF 12 #define IIO_TYPE_UINT1 13 #define IIO_TYPE_UINT2 14 #define IIO_TYPE_UINT4 15 #define IIO_TYPE_CHAR 16 #define IIO_TYPE_SHORT 17 #define IIO_TYPE_INT 18 #define IIO_TYPE_LONG 19 #define IIO_TYPE_LONGLONG 20 #define IIO_FORMAT_WHATEVER 0 #define IIO_FORMAT_QNM 1 #define IIO_FORMAT_PNG 2 #define IIO_FORMAT_JPEG 3 #define IIO_FORMAT_TIFF 4 #define IIO_FORMAT_RIM 5 #define IIO_FORMAT_BMP 6 #define IIO_FORMAT_EXR 7 #define IIO_FORMAT_JP2 8 #define IIO_FORMAT_VTK 9 #define IIO_FORMAT_CIMG 10 #define IIO_FORMAT_PAU 11 #define IIO_FORMAT_DICOM 12 #define IIO_FORMAT_PFM 13 #define IIO_FORMAT_NIFTI 14 #define IIO_FORMAT_PCX 15 #define IIO_FORMAT_GIF 16 #define IIO_FORMAT_XPM 17 #define IIO_FORMAT_RAFA 18 #define IIO_FORMAT_FLO 19 #define IIO_FORMAT_JUV 20 #define IIO_FORMAT_LUM 21 #define IIO_FORMAT_PCM 22 #define IIO_FORMAT_UNRECOGNIZED (-1) // // sugar // #define FORI(n) for(int i=0;i<(int)(n);i++) #define FORJ(n) for(int j=0;j<(int)(n);j++) #define FORK(n) for(int k=0;k<(int)(n);k++) #define FORL(n) for(int l=0;l<(int)(n);l++) #ifdef IIO_SHOW_DEBUG_MESSAGES #define IIO_DEBUG(...) do {\ fprintf(stderr,"DEBUG(%s:%d:%s): ",__FILE__,__LINE__,__PRETTY_FUNCTION__);\ fprintf(stderr,__VA_ARGS__);} while(0) #else //IIO_SHOW_DEBUG_MESSAGES #define IIO_DEBUG(...) do { ; } while(0) /* no-res */ #endif //IIO_SHOW_DEBUG_MESSAGES // // hacks // #ifndef __attribute__ #ifndef __GNUC__ #define __attribute__(x) /*NOTHING*/ #endif #endif // typedefs {{{1 typedef long long longong; typedef long double longdouble; // utility functions {{{1 static bool checkbounds (int a, int x, int b) { return a <= x && x < b; } #ifndef IIO_ABORT_ON_ERROR // NOTE: libpng has a nasty "feature" whereby you have to include libpng.h // before setjmp.h if you want to use both. This induces the following // hackery: #ifndef I_CAN_HAS_LIBPNG #include #endif //I_CAN_HAS_LIBPNG static jmp_buf global_jump_buffer; #endif //IIO_ABORT_ON_ERROR //#include // only for errno #include // for isspace #include // for floorf #include #ifdef I_CAN_HAS_LINUX #include static const char *emptystring = ""; static const char * myname (void) { #define n 0x29a static char buf[n]; pid_t p = getpid (); snprintf (buf, n, "/proc/%d/cmdline", p); FILE *f = fopen (buf, "r"); if (!f) return emptystring; int c, i = 0; while ((c = fgetc (f)) != EOF && i < n) { #undef n buf[i] = c ? c : ' '; i += 1; } if (i) buf[i - 1] = '\0'; fclose (f); return buf; } #else static const char * myname (void) { return ""; } #endif //I_CAN_HAS_LINUX //static int iio_single_jmpstuff(bool setup, bool do_return) //{ // if (setup) { //} static void error (const char *fmt, ...) __attribute__ ((noreturn, format (printf, 1, 2))); static void error (const char *fmt, ...) { va_list argp; fprintf (stderr, "\nERROR(\"%s\"): ", myname ()); va_start (argp, fmt); vfprintf (stderr, fmt, argp); va_end (argp); fprintf (stderr, "\n\n"); fflush (NULL); // if (global_hack_to_never_fail) // { // IIO_DEBUG("now wave a dead chicken and press enter\n"); // getchar(); // return; // } // exit(43); #ifndef IIO_ABORT_ON_ERROR longjmp (global_jump_buffer, 1); //iio_single_jmpstuff(true, false); #else //IIO_ABORT_ON_ERROR #ifdef NDEBUG exit (-1); #else //NDEBUG //print_trace(stderr); exit (*(int *) 0x43); #endif //NDEBUG #endif //IIO_ABORT_ON_ERROR } static void * xmalloc (size_t size) { if (size == 0) error ("xmalloc: zero size"); void *new = malloc (size); if (!new) { double sm = size / (0x100000 * 1.0); error ("xmalloc: out of memory when requesting " "%zu bytes (%gMB)", //:\"%s\"", size, sm); //, strerror(errno)); } return new; } static void * xrealloc (void *p, size_t s) { void *r = realloc (p, s); if (!r) error ("realloc failed"); return r; } static void xfree (void *p) { if (!p) error ("thou shalt not free a null pointer!"); free (p); } static const char *global_variable_containing_the_name_of_the_last_opened_file = NULL; static FILE * xfopen (const char *s, const char *p) { global_variable_containing_the_name_of_the_last_opened_file = NULL; FILE *f; if (!s) error ("trying to open a file with NULL name"); if (0 == strcmp ("-", s)) { if (0 == strcmp ("w", p)) return stdout; else if (0 == strcmp ("r", p)) return stdin; else error ("unknown fopen mode \"%s\"", p); } if (0 == strcmp ("--", s) && 0 == strcmp ("w", p)) return stderr; f = fopen (s, p); if (f == NULL) error ("can not open file \"%s\" in mode \"%s\"", // (%s)", s, p); //, strerror(errno)); //global_variable_containing_the_name_of_the_last_opened_file = (char*)s; global_variable_containing_the_name_of_the_last_opened_file = s; return f; } static void xfclose (FILE * f) { global_variable_containing_the_name_of_the_last_opened_file = NULL; if (f != stdout && f != stdin && f != stderr) { int r = fclose (f); if (r) error ("fclose error"); // \"%s\"", strerror(errno)); } } static int pilla_caracter_segur (FILE * f) { int c = getc (f); if (EOF == c) error ("input file ended before expected"); //IIO_DEBUG("pcs = '%c'\n", c); return c; } static void menja_espais (FILE * f) { //IIO_DEBUG("inside menja espais\n"); int c; do c = pilla_caracter_segur (f); while (isspace (c)); ungetc (c, f); } static void menja_linia (FILE * f) { //IIO_DEBUG("inside menja linia\n"); while (pilla_caracter_segur (f) != '\n') ; } static void menja_espais_i_comentaris (FILE * f) { //IIO_DEBUG("inside menja espais i comentaris\n"); int c, comment_char = '#'; menja_espais (f); while (1) { c = pilla_caracter_segur (f); if (c == comment_char) { menja_linia (f); menja_espais (f); } else ungetc (c, f); if (c == comment_char) break; } } // struct iio_image { ... }; {{{1 // This struct is used for exchanging image information between internal // functions. It could be safely eliminated, and this information be passed as // five or six variables. struct iio_image { int dimension; // 1, 2, 3 or 4 int sizes[IIO_MAX_DIMENSION]; int pixel_dimension; int type; // IIO_TYPE_* int meta; // IIO_META_* int format; // IIO_FORMAT_* bool contiguous_data; bool caca[3]; void *data; }; // struct iio_image management {{{1 // TODO: reduce the silly number of constructors to 1 static void iio_image_assert_struct_consistency (struct iio_image *x) { assert (x->dimension > 0); assert (x->dimension <= IIO_MAX_DIMENSION); FORI (x->dimension) assert (x->sizes[i] > 0); assert (x->pixel_dimension > 0); switch (x->type) { case IIO_TYPE_INT8: case IIO_TYPE_UINT8: case IIO_TYPE_INT16: case IIO_TYPE_UINT16: case IIO_TYPE_INT32: case IIO_TYPE_UINT32: case IIO_TYPE_FLOAT: case IIO_TYPE_DOUBLE: case IIO_TYPE_LONGDOUBLE: case IIO_TYPE_INT64: case IIO_TYPE_UINT64: case IIO_TYPE_HALF: case IIO_TYPE_CHAR: case IIO_TYPE_SHORT: case IIO_TYPE_INT: case IIO_TYPE_LONG: case IIO_TYPE_LONGLONG: break; default: assert (false); } //if (x->contiguous_data) // assert(x->data == (void*)(x+1)); } // API static size_t iio_type_size (int type) { switch (type) { case IIO_TYPE_INT8: return 1; case IIO_TYPE_UINT8: return 1; case IIO_TYPE_INT16: return 2; case IIO_TYPE_UINT16: return 2; case IIO_TYPE_INT32: return 4; case IIO_TYPE_UINT32: return 4; case IIO_TYPE_INT64: return 8; case IIO_TYPE_UINT64: return 8; case IIO_TYPE_CHAR: return sizeof (char); // 1 case IIO_TYPE_SHORT: return sizeof (short); case IIO_TYPE_INT: return sizeof (int); case IIO_TYPE_LONG: return sizeof (long); case IIO_TYPE_LONGLONG: return sizeof (long long); case IIO_TYPE_FLOAT: return sizeof (float); case IIO_TYPE_DOUBLE: return sizeof (double); case IIO_TYPE_LONGDOUBLE: return sizeof (long double); case IIO_TYPE_HALF: return sizeof (float) / 2; default: error ("unrecognized type %d", type); } } // XXX TODO FIXME: this is architecture dependent! // this function actually requires A LOT of magic to be portable static int normalize_type (int type_in) { int type_out; switch (type_in) { case IIO_TYPE_CHAR: type_out = IIO_TYPE_UINT8; break; case IIO_TYPE_SHORT: type_out = IIO_TYPE_INT16; break; case IIO_TYPE_INT: type_out = IIO_TYPE_UINT32; break; default: type_out = type_in; break; } if (type_out != type_in) { // the following assertion fails on many architectures assert (iio_type_size (type_in) == iio_type_size (type_out)); } return type_out; } // internal API static int iio_type_id (size_t sample_size, bool ieeefp_sample, bool signed_sample) { if (ieeefp_sample) { if (signed_sample) error ("signed floats are a no-no!"); switch (sample_size) { case sizeof (float): return IIO_TYPE_FLOAT; case sizeof (double): return IIO_TYPE_DOUBLE; case sizeof (long double): return IIO_TYPE_LONGDOUBLE; case sizeof (float) / 2: return IIO_TYPE_HALF; default: error ("bad float size %zu", sample_size); } } else { switch (sample_size) { case 1: return signed_sample ? IIO_TYPE_INT8 : IIO_TYPE_UINT8; case 2: return signed_sample ? IIO_TYPE_INT16 : IIO_TYPE_UINT16; case 4: return signed_sample ? IIO_TYPE_INT32 : IIO_TYPE_UINT32; case 8: return signed_sample ? IIO_TYPE_INT64 : IIO_TYPE_UINT64; default: error ("bad integral size %zu", sample_size); } } } // internal API static void iio_type_unid (int *size, bool * ieefp, bool * signedness, int type) { int t = normalize_type (type); *size = iio_type_size (t); *ieefp = (t == IIO_TYPE_HALF || t == IIO_TYPE_FLOAT || t == IIO_TYPE_DOUBLE || t == IIO_TYPE_LONGDOUBLE); *signedness = (t == IIO_TYPE_INT8 || t == IIO_TYPE_INT16 || t == IIO_TYPE_INT32 || t == IIO_TYPE_INT64); } // internal API static int iio_image_number_of_elements (struct iio_image *x) { iio_image_assert_struct_consistency (x); int r = 1; FORI (x->dimension) r *= x->sizes[i]; return r; } // internal API static int iio_image_number_of_samples (struct iio_image *x) { return iio_image_number_of_elements (x) * x->pixel_dimension; } // internal API static int iio_image_data_size (struct iio_image *x) { return iio_type_size (x->type) * iio_image_number_of_samples (x); } // internal API static bool iio_image_sample_integerP (struct iio_image *x) { if (false || x->type == IIO_TYPE_HALF || x->type == IIO_TYPE_FLOAT || x->type == IIO_TYPE_DOUBLE || x->type == IIO_TYPE_LONGDOUBLE) return false; else return true; } // internal API static size_t iio_image_sample_size (struct iio_image *x) { return iio_type_size (x->type); } static const char * iio_strtyp (int type) { #define M(t) case IIO_TYPE_ ## t: return #t switch (type) { M (INT8); M (UINT8); M (INT16); M (UINT16); M (INT32); M (UINT32); M (INT64); M (UINT64); M (FLOAT); M (DOUBLE); M (LONGDOUBLE); M (HALF); M (UINT1); M (UINT2); M (UINT4); M (CHAR); M (SHORT); M (INT); M (LONG); M (LONGLONG); default: return "unrecognized"; } #undef M } static const char * iio_strfmt (int format) { #define M(f) case IIO_FORMAT_ ## f: return #f switch (format) { M (WHATEVER); M (QNM); M (PNG); M (JPEG); M (TIFF); M (RIM); M (BMP); M (EXR); M (JP2); M (VTK); M (CIMG); M (PAU); M (DICOM); M (PFM); M (NIFTI); M (PCX); M (GIF); M (XPM); M (RAFA); M (UNRECOGNIZED); default: error ("caca de la grossa"); } #undef M } static void iio_print_image_info (FILE * f, struct iio_image *x) { fprintf (f, "iio_print_image_info %p\n", (void *) x); fprintf (f, "dimension = %d\n", x->dimension); int *s = x->sizes; switch (x->dimension) { case 1: fprintf (f, "size = %d\n", s[0]); break; case 2: fprintf (f, "sizes = %dx%d\n", s[0], s[1]); break; case 3: fprintf (f, "sizes = %dx%dx%d\n", s[0], s[1], s[2]); break; case 4: fprintf (f, "sizes = %dx%dx%dx%d\n", s[0], s[1], s[2], s[3]); break; default: error ("unsupported dimension %d", x->dimension); } fprintf (f, "pixel_dimension = %d\n", x->pixel_dimension); fprintf (f, "type = %s\n", iio_strtyp (x->type)); //fprintf(f, "format = %d\n", x->format); //fprintf(f, "meta = %d\n", x->meta); //fprintf(f, "contiguous_data = %d\n", x->contiguous_data); fprintf (f, "data = %p\n", (void *) x->data); } //static void fill_canonic_type_descriptors(struct iio_image *x, int type) //{ // bool s; int i; int f; // switch(type) { // case IIO_TYPE_INT8: s=true; i=1; f=0; break; // case IIO_TYPE_INT16: s=true; i=2; f=0; break; // case IIO_TYPE_INT32: s=true; i=4; f=0; break; // case IIO_TYPE_INT64: s=true; i=4; f=0; break; // case IIO_TYPE_UINT8: s=false; i=1; f=0; break; // case IIO_TYPE_UINT16: s=false; i=2; f=0; break; // case IIO_TYPE_UINT32: s=false; i=4; f=0; break; // case IIO_TYPE_UINT64: s=false; i=8; f=0; break; // case IIO_TYPE_FLOAT: s=false; i=0; f=4; break; // case IIO_TYPE_DOUBLE: s=false; i=0; f=8; break; // case IIO_TYPE_HALF: s=false; i=0; f=2; break; // default: error("unrecognized type %d", type); // } // x->signedness = s; // x->integer_size = i; // x->float_size = f; //} //static size_t typesize(int type) //{ // switch(type) { // case IIO_TYPE_CHAR: return sizeof(char); // case IIO_TYPE_SHORT: return sizeof(short); // case IIO_TYPE_INT: return sizeof(int); // case IIO_TYPE_LONG: return sizeof(long); // case IIO_TYPE_FLOAT: return sizeof(float); // case IIO_TYPE_DOUBLE: return sizeof(double); // default: return -1; // } //} static void fill_struct_2d (struct iio_image *x, int w, int h, int pd, int type, void *data) { x->dimension = 2; x->type = type; x->pixel_dimension = pd; x->data = data; x->sizes[0] = w; x->sizes[1] = h; } static void iio_image_fill (struct iio_image *x, int dimension, int *sizes, int type, int pixel_dimension) { x->dimension = dimension; FORI (dimension) x->sizes[i] = sizes[i]; x->type = type; x->pixel_dimension = pixel_dimension; x->data = NULL; x->format = -1; x->meta = -1; x->contiguous_data = false; } static void iio_wrap_image_struct_around_data (struct iio_image *x, int dimension, int *sizes, int pixel_dimension, int type, void *data) { assert (dimension < IIO_MAX_DIMENSION); x->dimension = dimension; FORI (x->dimension) x->sizes[i] = sizes[i]; x->pixel_dimension = pixel_dimension; x->type = type; x->data = data; x->contiguous_data = false; x->meta = -42; x->format = -42; } static void iio_image_build_independent (struct iio_image *x, int dimension, int *sizes, int type, int pixel_dimension) { assert (dimension > 0); assert (dimension <= 4); assert (pixel_dimension > 0); iio_image_fill (x, dimension, sizes, type, pixel_dimension); size_t datalength = 1; FORI (dimension) datalength *= sizes[i]; size_t datasize = datalength * iio_type_size (type) * pixel_dimension; x->data = xmalloc (datasize); } // low-level API: constructor static struct iio_image * iio_image_build_contiguous (int dimension, int *sizes, int type, int pixel_dimension, void *data) { assert (!data); assert (dimension > 0); assert (dimension <= 4); assert (pixel_dimension > 0); size_t datalength = 1; FORI (dimension) datalength *= sizes[i]; size_t datasize = datalength * iio_type_size (type) * pixel_dimension; struct iio_image *r = xmalloc (datasize + sizeof *r); iio_image_fill (r, dimension, sizes, type, pixel_dimension); r->data = sizeof *r + (char *) r; r->contiguous_data = true; return r; } // low-level API: queries static int iio_image_get_dimension (struct iio_image *x) { return x->dimension; } static int * iio_image_get_sizes (struct iio_image *x) { return x->sizes; } static int iio_image_get_type (struct iio_image *x) { return x->type; } static int iio_image_get_pixel_dimension (struct iio_image *x) { return x->pixel_dimension; } static int iio_image_get_meta (struct iio_image *x) { return x->meta; } //int iio_image_get_layout(struct iio_image *x) { return x->layout; } static int iio_image_get_format (struct iio_image *x) { return x->format; } static void * iio_image_get_data (struct iio_image *x) { return x->data; } // data conversion {{{1 #define T0(x) ((x)>0?(x):0) #define T8(x) ((x)>0?((x)<0xff?(x):0xff):0) #define T6(x) ((x)>0?((x)<0xffff?(x):0xffff):0) #define CC(a,b) (77*(a)+(b)) // hash number of a conversion pair #define I8 IIO_TYPE_INT8 #define U8 IIO_TYPE_UINT8 #define I6 IIO_TYPE_INT16 #define U6 IIO_TYPE_UINT16 #define I2 IIO_TYPE_INT32 #define U2 IIO_TYPE_UINT32 #define I4 IIO_TYPE_INT64 #define U4 IIO_TYPE_UINT64 #define F4 IIO_TYPE_FLOAT #define F8 IIO_TYPE_DOUBLE #define F6 IIO_TYPE_LONGDOUBLE static void convert_datum (void *dest, void *src, int dest_fmt, int src_fmt) { // NOTE: verify that this switch is optimized outside of the loop in // which it is contained. Otherwise, produce some self-modifying code // here. switch (CC (dest_fmt, src_fmt)) { // change of sign (lossless, but changes interpretation) case CC (I8, U8): *(int8_t *) dest = *(uint8_t *) src; break; case CC (I6, U6): *(int16_t *) dest = *(uint16_t *) src; break; case CC (I2, U2): *(int32_t *) dest = *(uint32_t *) src; break; case CC (U8, I8): *(uint8_t *) dest = *(int8_t *) src; break; case CC (U6, I6): *(uint16_t *) dest = *(int16_t *) src; break; case CC (U2, I2): *(uint32_t *) dest = *(int32_t *) src; break; // different size signed integers (3 lossy, 3 lossless) case CC (I8, I6): *(int8_t *) dest = *(int16_t *) src; break; //iw810 case CC (I8, I2): *(int8_t *) dest = *(int32_t *) src; break; //iw810 case CC (I6, I2): *(int16_t *) dest = *(int32_t *) src; break; //iw810 case CC (I6, I8): *(int16_t *) dest = *(int8_t *) src; break; case CC (I2, I8): *(int32_t *) dest = *(int8_t *) src; break; case CC (I2, I6): *(int32_t *) dest = *(int16_t *) src; break; // different size unsigned integers (3 lossy, 3 lossless) case CC (U8, U6): *(uint8_t *) dest = *(uint16_t *) src; break; //iw810 case CC (U8, U2): *(uint8_t *) dest = *(uint32_t *) src; break; //iw810 case CC (U6, U2): *(uint16_t *) dest = *(uint32_t *) src; break; //iw810 case CC (U6, U8): *(uint16_t *) dest = *(uint8_t *) src; break; case CC (U2, U8): *(uint32_t *) dest = *(uint8_t *) src; break; case CC (U2, U6): *(uint32_t *) dest = *(uint16_t *) src; break; // diferent size mixed integers, make signed (3 lossy, 3 lossless) case CC (I8, U6): *(int8_t *) dest = *(uint16_t *) src; break; //iw810 case CC (I8, U2): *(int8_t *) dest = *(uint32_t *) src; break; //iw810 case CC (I6, U2): *(int16_t *) dest = *(uint32_t *) src; break; //iw810 case CC (I6, U8): *(int16_t *) dest = *(uint8_t *) src; break; case CC (I2, U8): *(int32_t *) dest = *(uint8_t *) src; break; case CC (I2, U6): *(int32_t *) dest = *(uint16_t *) src; break; // diferent size mixed integers, make unsigned (3 lossy, 3 lossless) case CC (U8, I6): *(uint8_t *) dest = *(int16_t *) src; break; //iw810 case CC (U8, I2): *(uint8_t *) dest = *(int32_t *) src; break; //iw810 case CC (U6, I2): *(uint16_t *) dest = *(int32_t *) src; break; //iw810 case CC (U6, I8): *(uint16_t *) dest = *(int8_t *) src; break; case CC (U2, I8): *(uint32_t *) dest = *(int8_t *) src; break; case CC (U2, I6): *(uint32_t *) dest = *(int16_t *) src; break; // from float (typically lossy, except for small integers) case CC (I8, F4): *(int8_t *) dest = *(float *) src; break; //iw810 case CC (I6, F4): *(int16_t *) dest = *(float *) src; break; //iw810 case CC (I2, F4): *(int32_t *) dest = *(float *) src; break; case CC (I8, F8): *(int8_t *) dest = *(double *) src; break; //iw810 case CC (I6, F8): *(int16_t *) dest = *(double *) src; break; //iw810 case CC (I2, F8): *(int32_t *) dest = *(double *) src; break; //iw810 case CC (U8, F4): *(uint8_t *) dest = T8 (0.5 + *(float *) src); break; //iw810 case CC (U6, F4): *(uint16_t *) dest = T6 (0.5 + *(float *) src); break; //iw810 case CC (U2, F4): *(uint32_t *) dest = *(float *) src; break; case CC (U8, F8): *(uint8_t *) dest = T8 (0.5 + *(double *) src); break; //iw810 case CC (U6, F8): *(uint16_t *) dest = T6 (0.5 + *(double *) src); break; //iw810 case CC (U2, F8): *(uint32_t *) dest = *(double *) src; break; //iw810 // to float (typically lossless, except for large integers) case CC (F4, I8): *(float *) dest = *(int8_t *) src; break; case CC (F4, I6): *(float *) dest = *(int16_t *) src; break; case CC (F4, I2): *(float *) dest = *(int32_t *) src; break; //iw810 case CC (F8, I8): *(double *) dest = *(int8_t *) src; break; case CC (F8, I6): *(double *) dest = *(int16_t *) src; break; case CC (F8, I2): *(double *) dest = *(int32_t *) src; break; case CC (F4, U8): *(float *) dest = *(uint8_t *) src; break; case CC (F4, U6): *(float *) dest = *(uint16_t *) src; break; case CC (F4, U2): *(float *) dest = *(uint32_t *) src; break; //iw810 case CC (F8, U8): *(double *) dest = *(uint8_t *) src; break; case CC (F8, U6): *(double *) dest = *(uint16_t *) src; break; case CC (F8, U2): *(double *) dest = *(uint32_t *) src; break; #ifdef I_CAN_HAS_INT64 // to int64_t and uint64_t case CC (I4, I8): *(int64_t *) dest = *(int8_t *) src; break; case CC (I4, I6): *(int64_t *) dest = *(int16_t *) src; break; case CC (I4, I2): *(int64_t *) dest = *(int32_t *) src; break; case CC (I4, U8): *(int64_t *) dest = *(uint8_t *) src; break; case CC (I4, U6): *(int64_t *) dest = *(uint16_t *) src; break; case CC (I4, U2): *(int64_t *) dest = *(uint32_t *) src; break; case CC (I4, F4): *(int64_t *) dest = *(float *) src; break; case CC (I4, F8): *(int64_t *) dest = *(double *) src; break; case CC (U4, I8): *(uint64_t *) dest = *(int8_t *) src; break; case CC (U4, I6): *(uint64_t *) dest = *(int16_t *) src; break; case CC (U4, I2): *(uint64_t *) dest = *(int32_t *) src; break; case CC (U4, U8): *(uint64_t *) dest = *(uint8_t *) src; break; case CC (U4, U6): *(uint64_t *) dest = *(uint16_t *) src; break; case CC (U4, U2): *(uint64_t *) dest = *(uint32_t *) src; break; case CC (U4, F4): *(uint64_t *) dest = *(float *) src; break; case CC (U4, F8): *(uint64_t *) dest = *(double *) src; break; // from int64_t and uint64_t case CC (I8, I4): *(int8_t *) dest = *(int64_t *) src; break; case CC (I6, I4): *(int16_t *) dest = *(int64_t *) src; break; case CC (I2, I4): *(int32_t *) dest = *(int64_t *) src; break; case CC (U8, I4): *(uint8_t *) dest = *(int64_t *) src; break; case CC (U6, I4): *(uint16_t *) dest = *(int64_t *) src; break; case CC (U2, I4): *(uint32_t *) dest = *(int64_t *) src; break; case CC (F4, I4): *(float *) dest = *(int64_t *) src; break; case CC (F8, I4): *(double *) dest = *(int64_t *) src; break; case CC (I8, U4): *(int8_t *) dest = *(uint64_t *) src; break; case CC (I6, U4): *(int16_t *) dest = *(uint64_t *) src; break; case CC (I2, U4): *(int32_t *) dest = *(uint64_t *) src; break; case CC (U8, U4): *(uint8_t *) dest = *(uint64_t *) src; break; case CC (U6, U4): *(uint16_t *) dest = *(uint64_t *) src; break; case CC (U2, U4): *(uint32_t *) dest = *(uint64_t *) src; break; case CC (F4, U4): *(float *) dest = *(uint64_t *) src; break; case CC (F8, U4): *(double *) dest = *(uint64_t *) src; break; #endif //I_CAN_HAS_INT64 #ifdef I_CAN_HAS_LONGDOUBLE // to longdouble case CC (F6, I8): *(longdouble *) dest = *(int8_t *) src; break; case CC (F6, I6): *(longdouble *) dest = *(int16_t *) src; break; case CC (F6, I2): *(longdouble *) dest = *(int32_t *) src; break; case CC (F6, U8): *(longdouble *) dest = *(uint8_t *) src; break; case CC (F6, U6): *(longdouble *) dest = *(uint16_t *) src; break; case CC (F6, U2): *(longdouble *) dest = *(uint32_t *) src; break; case CC (F6, F4): *(longdouble *) dest = *(float *) src; break; case CC (F6, F8): *(longdouble *) dest = *(double *) src; break; // from longdouble case CC (I8, F6): *(int8_t *) dest = *(longdouble *) src; break; case CC (I6, F6): *(int16_t *) dest = *(longdouble *) src; break; case CC (I2, F6): *(int32_t *) dest = *(longdouble *) src; break; case CC (U8, F6): *(uint8_t *) dest = T8 (0.5 + *(longdouble *) src); break; case CC (U6, F6): *(uint16_t *) dest = T6 (0.5 + *(longdouble *) src); break; case CC (U2, F6): *(uint32_t *) dest = *(longdouble *) src; break; case CC (F4, F6): *(float *) dest = *(longdouble *) src; break; case CC (F8, F6): *(double *) dest = *(longdouble *) src; break; #ifdef I_CAN_HAS_INT64 //(nested) case CC (F6, I4): *(longdouble *) dest = *(int64_t *) src; break; case CC (F6, U4): *(longdouble *) dest = *(uint64_t *) src; break; case CC (I4, F6): *(int64_t *) dest = *(longdouble *) src; break; case CC (U4, F6): *(uint64_t *) dest = *(longdouble *) src; break; #endif //I_CAN_HAS_INT64 (nested) #endif //I_CAN_HAS_LONGDOUBLE default: error ("bad conversion from %d to %d", src_fmt, dest_fmt); } } #undef CC #undef I8 #undef U8 #undef I6 #undef U6 #undef I2 #undef U2 #undef F4 #undef F8 #undef F6 static void * convert_data (void *src, int n, int dest_fmt, int src_fmt) { if (src_fmt == IIO_TYPE_FLOAT) IIO_DEBUG ("first float sample = %g\n", *(float *) src); size_t src_width = iio_type_size (src_fmt); size_t dest_width = iio_type_size (dest_fmt); IIO_DEBUG ("converting %d samples from %s to %s\n", n, iio_strtyp (src_fmt), iio_strtyp (dest_fmt)); IIO_DEBUG ("src width = %zu\n", src_width); IIO_DEBUG ("dest width = %zu\n", dest_width); char *r = xmalloc (n * dest_width); // NOTE: the switch inside "convert_datum" should be optimized // outside of this loop FORI (n) { void *to = i * dest_width + r; void *from = i * src_width + (char *) src; convert_datum (to, from, dest_fmt, src_fmt); } xfree (src); if (dest_fmt == IIO_TYPE_INT16) IIO_DEBUG ("first short sample = %d\n", *(int16_t *) r); return r; } static void unpack_nibbles_to_bytes (uint8_t out[2], uint8_t in) { out[1] = (in & 0x0f); //0b00001111 out[0] = (in & 0xf0) >> 4; //0b11110000 } static void unpack_couples_to_bytes (uint8_t out[4], uint8_t in) { out[3] = (in & 0x03); //0b00000011 out[2] = (in & 0x0c) >> 2; //0b00001100 out[1] = (in & 0x30) >> 4; //0b00110000 out[0] = (in & 0xc0) >> 6; //0b11000000 } static void unpack_bits_to_bytes (uint8_t out[8], uint8_t in) { out[7] = (in & 1) ? 1 : 0; out[6] = (in & 2) ? 1 : 0; out[5] = (in & 4) ? 1 : 0; out[4] = (in & 8) ? 1 : 0; out[3] = (in & 16) ? 1 : 0; out[2] = (in & 32) ? 1 : 0; out[1] = (in & 64) ? 1 : 0; out[0] = (in & 128) ? 1 : 0; } static void unpack_to_bytes_here (uint8_t * dest, uint8_t * src, int n, int bits) { fprintf (stderr, "unpacking %d bytes %d-fold\n", n, bits); assert (bits == 1 || bits == 2 || bits == 4); size_t unpack_factor = 8 / bits; switch (bits) { case 1: FORI (n) unpack_bits_to_bytes (dest + 8 * i, src[i]); break; case 2: FORI (n) unpack_couples_to_bytes (dest + 4 * i, src[i]); break; case 4: FORI (n) unpack_nibbles_to_bytes (dest + 2 * i, src[i]); break; default: error ("very strange error"); } } //static uint8_t *unpack_to_bytes(uint8_t *s, int n, int src_bits) //{ // assert(src_bits==1 || src_bits==2 || src_bits==4); // size_t unpack_factor = 8 / src_bits; // uint8_t *r = xmalloc(n * unpack_factor); // switch(src_bits) { // case 1: FORI(n) unpack_bits_to_bytes(r + 8*i, s[i]); break; // case 2: FORI(n) unpack_couples_to_bytes(r + 4*i, s[i]); break; // case 4: FORI(n) unpack_nibbles_to_bytes(r + 2*i, s[i]); break; // default: error("very strange error"); // } // xfree(s); // return r; //} static void iio_convert_samples (struct iio_image *x, int desired_type) { assert (!x->contiguous_data); int source_type = normalize_type (x->type); if (source_type == desired_type) return; IIO_DEBUG ("converting from %s to %s\n", iio_strtyp (x->type), iio_strtyp (desired_type)); int n = iio_image_number_of_samples (x); x->data = convert_data (x->data, n, desired_type, source_type); x->type = desired_type; } static void iio_hacky_colorize (struct iio_image *x, int pd) { assert (!x->contiguous_data); if (x->pixel_dimension != 1) error ("please, do not colorize color stuff"); int source_type = normalize_type (x->type); int n = iio_image_number_of_elements (x); int ss = iio_image_sample_size (x); void *rdata = xmalloc (n * ss * pd); char *data_dest = rdata; char *data_src = x->data; FORI (n) FORJ (pd) memcpy (data_dest + (pd * i + j) * ss, data_src + i * ss, ss); xfree (x->data); x->data = rdata; x->pixel_dimension = pd; } // uncolorize static void iio_hacky_uncolorize (struct iio_image *x) { assert (!x->contiguous_data); if (x->pixel_dimension != 3) error ("please, do not uncolorize non-color stuff"); assert (x->pixel_dimension == 3); int source_type = normalize_type (x->type); int n = iio_image_number_of_elements (x); switch (source_type) { case IIO_TYPE_UINT8: { uint8_t (*xd)[3] = x->data; uint8_t *r = xmalloc (n * sizeof *r); FORI (n) r[i] = .299 * xd[i][0] + .587 * xd[i][1] + .114 * xd[i][2]; xfree (x->data); x->data = r; } break; case IIO_TYPE_FLOAT: { float (*xd)[3] = x->data; float *r = xmalloc (n * sizeof *r); FORI (n) r[i] = .299 * xd[i][0] + .587 * xd[i][1] + .114 * xd[i][2]; xfree (x->data); x->data = r; } break; default: error ("uncolorize type not supported"); } x->pixel_dimension = 1; } // uncolorize static void iio_hacky_uncolorizea (struct iio_image *x) { assert (!x->contiguous_data); if (x->pixel_dimension != 4) error ("please, do not uncolorizea non-colora stuff"); assert (x->pixel_dimension == 4); int source_type = normalize_type (x->type); int n = iio_image_number_of_elements (x); switch (source_type) { case IIO_TYPE_UINT8: { uint8_t (*xd)[4] = x->data; uint8_t *r = xmalloc (n * sizeof *r); FORI (n) r[i] = .299 * xd[i][0] + .587 * xd[i][1] + .114 * xd[i][2]; xfree (x->data); x->data = r; } break; case IIO_TYPE_FLOAT: { float (*xd)[4] = x->data; float *r = xmalloc (n * sizeof *r); FORI (n) r[i] = .299 * xd[i][0] + .587 * xd[i][1] + .114 * xd[i][2]; xfree (x->data); x->data = r; } break; default: error ("uncolorizea type not supported"); } x->pixel_dimension = 1; } // (minimal) image processing using the iio_image {{{1 //TODO: remove this section // whatever // get/set pixel {{{2 // the "getpixel" function can be used also as a setpixel static void * iio_getpixel (struct iio_image *x, int *p) { FORI (x->dimension) if (!checkbounds (0, p[i], x->sizes[i])) return NULL; int n = iio_image_sample_size (x); char *r = x->data; switch (x->dimension) { case 1: return n * p[0] + r; case 2: return n * p[0] + x->sizes[0] * p[1] + r; case 3: return n * p[0] + x->sizes[0] * (p[1] + x->sizes[1] * p[2]) + r; default: error ("getpixel not yet for dimension %d", x->dimension); } } static void * iio_getsample (struct iio_image *x, int *p, int c) { if (!checkbounds (0, c, x->pixel_dimension)) return NULL; void *pixel = iio_getpixel (x, p); int n = iio_image_sample_size (x); return c * n + (char *) pixel; } // crop/slice/select {{{2 // To CROP an image means building an image with a "rectangular" subset of its // numbers As particular cases it contains taking a slice from a video, or a // color channel. It does not change the signature. // signs equals 1. static void iio_general_crop (struct iio_image *x, int *corner, int *sizes, int firstchan, int lastchan) { // silently ignores out of range bounds int newsizes[x->dimension]; } // rotate/deinterlace {{{2 // To TRANSPOSE an image means building an image with the same numbers in // different order. As particular it contains rotation, (de)interlacing, etc. static void iio_general_transposition (struct iio_image *x, int c[2]) { } // ntiply/colorize {{{2 // to NTIPLY an image means building an image where some numbers are repeated // As particular cases it contains zooming in an image (with nearest neighbor // interpolation), or colorizing a gray image. static void iio_general_ntiply (struct iio_image *x, int *factors, int pfac) { // too complicated for now... } // normalize signature {{{2 static void iio_general_normalize_signature (struct iio_image *x) { } // general memory and file utilities {{{1 // Input: a partially read stream "f" // (of which "bufn" bytes are already read into "buf") // // Output: a malloc'd block with the whole file content // // Implementation: re-invent the wheel static void * load_rest_of_file (long *on, FILE * f, void *buf, size_t bufn) { size_t n = bufn, ntop = n + 0x3000; char *t = xmalloc (ntop); if (!t) error ("out of mem (%zu) while loading file", ntop); memcpy (t, buf, bufn); while (1) { if (n >= ntop) { ntop = 1000 + 2 * (ntop + 1); t = xrealloc (t, ntop); if (!t) error ("out of mem (%zu) loading file", ntop); } int r = fgetc (f); if (r == EOF) break; t[n] = r; //iw810 n += 1; } *on = n; return t; } // Input: a pointer to raw data // // Output: the name of a temporary file containing the data // // Implementation: re-invent the wheel static char * put_data_into_temporary_file (void *filedata, size_t filesize) { #ifdef I_CAN_HAS_MKSTEMP static char filename[] = "/tmp/iio_temporal_file_XXXXXX\0"; int r = mkstemp (filename); if (r == -1) error ("caca [pditf]"); #else // WARNING XXX XXX XXX ERROR FIXME TODO WARNING: // this function is not reentrant static char buf[L_tmpnam + 1]; // // from TMPNAM(3): // //The tmpnam() function returns a pointer to a string that is a //valid filename, and such that a file with this name did not exist //at some point in time, so that naive programmers may think it a //suitable name for a temporary file. // char *filename = tmpnam (buf); // MULTIPLE RACE CONDITIONS HERE #endif FILE *f = xfopen (filename, "w"); int cx = fwrite (filedata, filesize, 1, f); if (cx != 1) error ("fwrite to temporary file failed"); xfclose (f); return filename; } static void delete_temporary_file (char *filename) { #ifdef NDEBUG remove (filename); #else //IIO_DEBUG("WARNING: kept temporary file %s around\n", filename); fprintf (stderr, "WARNING: kept temporary file %s around\n", filename); #endif } // Allows read access to memory via a FILE* // Always returns a valid FILE* static FILE * iio_fmemopen (void *data, size_t size) { #ifdef I_CAN_HAS_FMEMOPEN // GNU case FILE *r = fmemopen (data, size, "r"); if (!r) error ("fmemopen failed"); return r; #elif I_CAN_HAS_FUNOPEN // BSD case error ("implement fmemopen using funopen here"); #else // portable case FILE *f = tmpfile (); if (!f) error ("tmpfile failed"); int cx = fwrite (data, size, 1, f); if (cx != 1) error ("fwrite failed"); rewind (f); return f; #endif // I_CAN_HAS_... } // beautiful hack follows static void * matrix_build (int w, int h, size_t n) { size_t p = sizeof (void *); char *r = xmalloc (h * p + w * h * n); for (int i = 0; i < h; i++) *(void **) (r + i * p) = r + h * p + i * w * n; return r; } static void * wrap_2dmatrix_around_data (void *x, int w, int h, size_t s) { void *r = matrix_build (w, h, s); char *y = h * sizeof (void *) + (char *) r; memcpy (y, x, w * h * s); xfree (x); return r; } static int atoin (char *s) { int r = 0; while (isdigit (*s)) { r *= 10; r += *s - '0'; s += 1; } return r; } // heurística per trobar les dimensions a partir del nom static bool find_dimensions_in_string_2d (int out[2], char *s) { // preprocessem el text per trobar-ne els dígits int n = strlen (s), nnums = 0, numbegs[n]; for (int i = 1; i < n; i++) if (isdigit (s[i]) && !isdigit (s[i - 1])) numbegs[nnums++] = i; if (nnums < 2) return false; // si el text conté algun parell "%dx%d", retornem el primer parell for (int i = 1; i < nnums; i++) if (tolower (s[numbegs[i] - 1]) == 'x') { out[0] = atoin (s + numbegs[i - 1]); out[1] = atoin (s + numbegs[i]); return true; } // altrament, cerquem els dos primers números out[0] = atoin (s + numbegs[0]); out[1] = atoin (s + numbegs[1]); return true; } static bool find_dimensions_in_string_3d (int out[3], char *s) { // preprocessem el text per trobar-ne els dígits int n = strlen (s), nnums = 0, numbegs[n]; for (int i = 1; i < n; i++) if (isdigit (s[i]) && !isdigit (s[i - 1])) numbegs[nnums++] = i; if (nnums < 3) return false; // si el text conté algun trio "%dx%dx%d", retornem el primer trio for (int i = 2; i < nnums; i++) if (tolower (s[numbegs[i] - 1]) == 'x' && tolower (s[numbegs[i - 1] - 1]) == 'x') { out[0] = atoin (s + numbegs[i - 2]); out[1] = atoin (s + numbegs[i - 1]); out[2] = atoin (s + numbegs[i]); return true; } // altrament, cerquem els dos primers números out[0] = atoin (s + numbegs[0]); out[1] = atoin (s + numbegs[1]); out[2] = atoin (s + numbegs[2]); return true; } static void break_pixels (void *broken, void *clear, int ss, int n, int pd) { char *to = broken; char *from = clear; FORI (n) FORL (pd) FORK (ss) to[(n * l + i) * ss + k] = from[(pd * i + l) * ss + k]; } static void recover_broken_pixels (void *c, void *b, int ss, int n, int pd) { char *to = c; char *from = b; FORL (pd) FORI (n) FORK (ss) to[(pd * i + l) * ss + k] = from[(n * l + i) * ss + k]; } // todo make this function more general, or a front-end to a general // "data trasposition" routine static void break_pixels_float (float *broken, float *clear, int n, int pd) { //fprintf(stderr, "breaking %d %d-dimensional vectors\n", n, pd); FORI (n) FORL (pd) broken[n * l + i] = clear[pd * i + l]; } static void recover_broken_pixels_float (float *clear, float *broken, int n, int pd) { //fprintf(stderr, "unbreaking %d %d-dimensional vectors\n", n, pd); FORL (pd) FORI (n) clear[pd * i + l] = broken[n * l + i]; } // individual format readers {{{1 // PNG reader {{{2 static void swap_two_bytes (char *here) { char tmp = here[0]; here[0] = here[1]; here[1] = tmp; } #ifdef I_CAN_HAS_LIBPNG //#include #include // for CHAR_BIT only static int read_beheaded_png (struct iio_image *x, FILE * f, char *header, int nheader) { // TODO: reorder this mess png_structp pp = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!pp) error ("png_create_read_struct fail"); png_infop pi = png_create_info_struct (pp); if (!pi) error ("png_create_info_struct fail"); if (setjmp (png_jmpbuf (pp))) error ("png error"); png_init_io (pp, f); png_set_sig_bytes (pp, nheader); int transforms = PNG_TRANSFORM_IDENTITY | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND; png_read_png (pp, pi, transforms, NULL); png_uint_32 w, h; int channels, rowbytes; int depth, color, interl, compr, filt; w = png_get_image_width (pp, pi); h = png_get_image_height (pp, pi); //png_get_IHDR(pp, pi, &w, &h, &depth, &color, &interl, &compr, &filt); channels = png_get_channels (pp, pi); rowbytes = png_get_rowbytes (pp, pi); depth = png_get_bit_depth (pp, pi); color = png_get_color_type (pp, pi); IIO_DEBUG ("png get width = %d\n", (int) w); IIO_DEBUG ("png get height = %d\n", (int) h); IIO_DEBUG ("png get channels = %d\n", channels); IIO_DEBUG ("png get rowbytes = %d\n", rowbytes); IIO_DEBUG ("png get depth = %d\n", depth); IIO_DEBUG ("png get color = %d\n", color); //IIO_DEBUG("png ihdr width = %d\n", (int)w); //IIO_DEBUG("png ihdr height = %d\n", (int)h); //IIO_DEBUG("png ihdr depth = %d\n", depth); //IIO_DEBUG("png ihdr color = %d\n", color); //IIO_DEBUG("png ihdr interl = %d\n", interl); //IIO_DEBUG("png ihdr compr = %d\n", compr); //IIO_DEBUG("png ihdr filt = %d\n", filt); //IIO_DEBUG("png channels = %d\n", channels); //IIO_DEBUG("png rowbytes = %d\n", rowbytes); //assert(rowbytes == ceil((channels * (int)w * depth)/CHAR_BIT)); //if (depth == 16) png_set_swap(pp); (does not seem to work) int sizes[2] = { w, h }; png_bytepp rows = png_get_rows (pp, pi); x->format = IIO_FORMAT_PNG; x->meta = -42; switch (depth) { case 1: case 8: IIO_DEBUG ("first byte = %d\n", (int) rows[0][0]); iio_image_build_independent (x, 2, sizes, IIO_TYPE_CHAR, channels); FORJ (h) FORI (w) FORL (channels) { char *data = x->data; png_byte *b = rows[j] + i * channels + l; data[(i + j * w) * channels + l] = *b; } x->type = IIO_TYPE_CHAR; break; case 16: iio_image_build_independent (x, 2, sizes, IIO_TYPE_UINT16, channels); FORJ (h) FORI (w) FORL (channels) { uint16_t *data = x->data; png_byte *b = rows[j] + 2 * (i * channels + l); swap_two_bytes ((char *) b); uint16_t *tb = (uint16_t *) b; data[(i + j * w) * channels + l] = *tb; } x->type = IIO_TYPE_UINT16; break; default: error ("unsuported bit depth %d", depth); } //FORJ(h) FORIk //png_destroy_read_struct(&pp, &pi, &pe); png_destroy_read_struct (&pp, &pi, NULL); return 0; } #endif //I_CAN_HAS_LIBPNG // JPEG reader {{{2 #ifdef I_CAN_HAS_LIBJPEG #include static int read_whole_jpeg (struct iio_image *x, FILE * f) { // allocate and initialize a JPEG decompression object struct jpeg_decompress_struct cinfo[1]; struct jpeg_error_mgr jerr[1]; cinfo->err = jpeg_std_error (jerr); jpeg_create_decompress (cinfo); // specify the source of the compressed data jpeg_stdio_src (cinfo, f); // obtain image info jpeg_read_header (cinfo, 1); int size[2], depth; size[0] = cinfo->image_width; size[1] = cinfo->image_height; depth = cinfo->num_components; IIO_DEBUG ("jpeg header widht = %d\n", size[0]); IIO_DEBUG ("jpeg header height = %d\n", size[1]); IIO_DEBUG ("jpeg header colordepth = %d\n", depth); iio_image_build_independent (x, 2, size, IIO_TYPE_CHAR, depth); // set parameters for decompression // cinfo->do_fancy_upsampling = 0; // colorspace selection, etc // start decompress jpeg_start_decompress (cinfo); assert (size[0] == (int) cinfo->output_width); assert (size[1] == (int) cinfo->output_height); assert (depth == cinfo->out_color_components); assert (cinfo->output_components == cinfo->out_color_components); // read scanlines FORI (size[1]) { void *wheretoputit = i * depth * size[0] + (char *) x->data; //FORJ(size[0]*depth) ((char*)wheretoputit)[j] = 6; JSAMPROW scanline[1] = { wheretoputit }; int r = jpeg_read_scanlines (cinfo, scanline, 1); //IIO_DEBUG("read %dth scanline (r=%d) {%d}\n", i, r, (int)sizeof(JSAMPLE)); if (1 != r) error ("failed to rean jpeg scanline %d", i); } // finish decompress jpeg_finish_decompress (cinfo); // release the JPEG decompression object jpeg_destroy_decompress (cinfo); return 0; } static int read_beheaded_jpeg (struct iio_image *x, FILE * fin, char *header, int nheader) { long filesize; // TODO: if "f" is rewindable, rewind it! void *filedata = load_rest_of_file (&filesize, fin, header, nheader); FILE *f = iio_fmemopen (filedata, filesize); int r = read_whole_jpeg (x, f); if (r) error ("read whole jpeg returned %d", r); fclose (f); xfree (filedata); return 0; } #endif //I_CAN_HAS_LIBJPEG // TIFF reader {{{2 #ifdef I_CAN_HAS_LIBTIFF #include static int read_whole_tiff (struct iio_image *x, const char *filename) { // tries to read data in the correct format (via scanlines) // if it fails, it tries to read ABGR data TIFF *tif = TIFFOpen (filename, "r"); if (!tif) error ("could not open TIFF file \"%s\"", filename); uint32_t w, h; uint16_t spp, bps, fmt; int r = 0, fmt_iio = -1; r += TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &w); IIO_DEBUG ("tiff get field width %d (r=%d)\n", (int) w, r); r += TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &h); IIO_DEBUG ("tiff get field length %d (r=%d)\n", (int) h, r); if (r != 2) error ("can not read tiff of unknown size"); r = TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp); if (!r) spp = 1; if (r) IIO_DEBUG ("tiff get field spp %d (r=%d)\n", spp, r); r = TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bps); if (!r) bps = 1; if (r) IIO_DEBUG ("tiff get field bps %d (r=%d)\n", bps, r); r = TIFFGetField (tif, TIFFTAG_SAMPLEFORMAT, &fmt); if (!r) fmt = SAMPLEFORMAT_UINT; if (r) IIO_DEBUG ("tiff get field fmt %d (r=%d)\n", fmt, r); //if (r != 5) error("some tiff getfield failed (r=%d)", r); // TODO: consider the missing cases (run through PerlMagick's format database) IIO_DEBUG ("fmt = %d\n", fmt); // set appropriate size and type flags if (fmt == SAMPLEFORMAT_UINT) { if (1 == bps) fmt_iio = IIO_TYPE_UINT1; else if (2 == bps) fmt_iio = IIO_TYPE_UINT2; else if (4 == bps) fmt_iio = IIO_TYPE_UINT4; else if (8 == bps) fmt_iio = IIO_TYPE_UINT8; else if (16 == bps) fmt_iio = IIO_TYPE_UINT16; else if (32 == bps) fmt_iio = IIO_TYPE_UINT32; else error ("unrecognized UINT type of size %d bits", bps); } else if (fmt == SAMPLEFORMAT_INT) { if (8 == bps) fmt_iio = IIO_TYPE_INT8; else if (16 == bps) fmt_iio = IIO_TYPE_INT16; else if (32 == bps) fmt_iio = IIO_TYPE_INT32; else error ("unrecognized INT type of size %d bits", bps); } else if (fmt == SAMPLEFORMAT_IEEEFP) { IIO_DEBUG ("floating tiff!\n"); if (32 == bps) fmt_iio = IIO_TYPE_FLOAT; else if (64 == bps) fmt_iio = IIO_TYPE_DOUBLE; else error ("unrecognized FLOAT type of size %d bits", bps); } else error ("unrecognized tiff sample format %d (see tiff.h)", fmt); if (bps >= 8 && bps != 8 * iio_type_size (fmt_iio)) { IIO_DEBUG ("bps = %d\n", bps); IIO_DEBUG ("fmt_iio = %d\n", fmt_iio); IIO_DEBUG ("ts = %zu\n", iio_type_size (fmt_iio)); IIO_DEBUG ("8*ts = %zu\n", 8 * iio_type_size (fmt_iio)); } if (bps >= 8) assert (bps == 8 * iio_type_size (fmt_iio)); // acquire memory block uint32_t scanline_size = (w * spp * bps) / 8; int rbps = bps / 8 ? bps / 8 : 1; uint32_t uscanline_size = w * spp * rbps; IIO_DEBUG ("bps = %d\n", (int) bps); IIO_DEBUG ("spp = %d\n", (int) spp); IIO_DEBUG ("sls = %d\n", (int) scanline_size); int sls = TIFFScanlineSize (tif); IIO_DEBUG ("sls(r) = %d\n", (int) sls); assert ((int) scanline_size == sls); scanline_size = sls; uint8_t *data = xmalloc (w * h * spp * rbps); //FORI(h*scanline_size) data[i] = 42; uint8_t *buf = xmalloc (scanline_size); // dump scanline data FORI (h) { //r = TIFFReadScanline(tif, data + i * scanline_size, i, 0); r = TIFFReadScanline (tif, buf, i, 0); if (r < 0) error ("error reading tiff row %d/%d", i, (int) h); if (bps < 8) { fprintf (stderr, "unpacking %dth scanline\n", i); unpack_to_bytes_here (data + i * uscanline_size, buf, scanline_size, bps); fmt_iio = IIO_TYPE_UINT8; } else { //assert(uscanline_size == scanline_size); memcpy (data + i * scanline_size, buf, scanline_size); } } TIFFClose (tif); xfree (buf); // fill struct fields x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = spp; x->type = fmt_iio; x->format = x->meta = -42; x->data = data; x->contiguous_data = false; return 0; } // Note: TIFF library only reads from a named file. The only way to use the // library if you have your image in a stream, is to write the data to a // temporary file, and read it from there. This can be optimized in the future // by recovering the original filename through hacks, in case it was not a pipe. static int read_beheaded_tiff (struct iio_image *x, FILE * fin, char *header, int nheader) { if (global_variable_containing_the_name_of_the_last_opened_file) { int r = read_whole_tiff (x, global_variable_containing_the_name_of_the_last_opened_file); if (r) error ("read whole tiff returned %d", r); return 0; } long filesize; void *filedata = load_rest_of_file (&filesize, fin, header, nheader); char *filename = put_data_into_temporary_file (filedata, filesize); xfree (filedata); //IIO_DEBUG("tmpfile = \"%s\"\n", filename); int r = read_whole_tiff (x, filename); if (r) error ("read whole tiff returned %d", r); delete_temporary_file (filename); return 0; } #endif //I_CAN_HAS_LIBTIFF // QNM readers {{{2 #include static void llegeix_floats_en_bytes (FILE * don, float *on, int quants) { for (int i = 0; i < quants; i++) { float c; c = pilla_caracter_segur (don); //iw810 on[i] = c; } } static void llegeix_floats_en_shorts (FILE * don, float *on, int quants) { for (int i = 0; i < quants; i++) { float c; c = pilla_caracter_segur (don); c *= 256; c += pilla_caracter_segur (don); on[i] = c; } } static void llegeix_floats_en_ascii (FILE * don, float *on, int quants) { for (int i = 0; i < quants; i++) { int r; float c; r = fscanf (don, "%f ", &c); if (r != 1) error ("no s'han pogut llegir %d numerets del fitxer &%p\n", quants, (void *) don); on[i] = c; } } static int read_qnm_numbers (float *data, FILE * f, int n, int m, bool use_ascii) { if (use_ascii) llegeix_floats_en_ascii (f, data, n); else { if (m < 0x100) llegeix_floats_en_bytes (f, data, n); else if (m < 0x10000) llegeix_floats_en_shorts (f, data, n); else error ("too large maxval %d", m); } // TODO: error checking return n; } // qnm_types: // 2 P2 (ascii 2d grayscale pgm) // 5 P5 (binary 2d grayscale pgm) // 3 P3 (ascii 2d color ppm) // 6 P6 (binary 2d color ppm) // 12 Q2 (ascii 3d grayscale pgm) // 15 Q5 (binary 3d grayscale pgm) // 13 Q3 (ascii 3d color ppm) // 16 Q6 (binary 3d color ppm) // 17 Q7 (ascii 3d nd ) // 19 Q9 (binary 3d nd ) static int read_beheaded_qnm (struct iio_image *x, FILE * f, char *header, int nheader) { assert (nheader == 2); int w, h, d = 1, m, pd = 1; int c1 = header[0]; int c2 = header[1] - '0'; IIO_DEBUG ("QNM reader (%c %d)...\n", c1, c2); menja_espais_i_comentaris (f); if (1 != fscanf (f, "%d", &w)) return -1; menja_espais_i_comentaris (f); if (1 != fscanf (f, "%d", &h)) return -2; if (c1 == 'Q') { if (1 != fscanf (f, "%d", &d)) return -3; menja_espais_i_comentaris (f); } if (c2 == 7 || c2 == 9) { if (1 != fscanf (f, "%d", &pd)) return -4; menja_espais_i_comentaris (f); } if (1 != fscanf (f, "%d", &m)) return -5; // maxval is ignored and the image is always read into floats if (!isspace (pilla_caracter_segur (f))) return -6; bool use_ascii = (c2 == 2 || c2 == 3 || c2 == 7); bool use_2d = (d == 1); if (!use_2d) assert (c1 == 'Q'); if (c2 == 3 || c2 == 6) pd = 3; size_t nn = w * h * d * pd; // number of numbers float *data = xmalloc (nn * sizeof *data); IIO_DEBUG ("QNM reader w = %d\n", w); IIO_DEBUG ("QNM reader h = %d\n", h); IIO_DEBUG ("QNM reader d = %d\n", d); IIO_DEBUG ("QNM reader pd = %d\n", pd); IIO_DEBUG ("QNM reader m = %d\n", m); IIO_DEBUG ("QNM reader use_2d = %d\n", use_2d); IIO_DEBUG ("QNM reader use_ascii = %d\n", use_ascii); int r = read_qnm_numbers (data, f, nn, m, use_ascii); if (nn - r) return -7; x->dimension = use_2d ? 2 : 3; x->sizes[0] = w; x->sizes[1] = h; if (d > 1) x->sizes[2] = d; x->pixel_dimension = pd; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = data; return 0; } // PCM reader {{{2 // PCM is a file format to store complex float images // it is used by some people also for optical flow fields static int read_beheaded_pcm (struct iio_image *x, FILE * f, char *header, int nheader) { assert (nheader == 2); int w, h; float scale; //menja_espais_i_comentaris(f); if (1 != fscanf (f, " %d", &w)) return -1; //menja_espais_i_comentaris(f); if (1 != fscanf (f, " %d", &h)) return -2; //menja_espais_i_comentaris(f); if (1 != fscanf (f, " %g", &scale)) return -3; if (!isspace (pilla_caracter_segur (f))) return -6; fprintf (stderr, "%d PCM w h scale = %d %d %g\n", nheader, w, h, scale); assert (sizeof (float) == 4); float *data = xmalloc (w * h * 2 * sizeof (float)); int r = fread (data, sizeof (float), w * h * 2, f); if (r != w * h * 2) return -7; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 2; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = data; return 0; } // RIM reader {{{2 // CIMAGE header bytes: ("IMG" format) // short 0: 'MI' // short 1: comment length // short 2: image width // short 3: image height // // FIMAGE header bytes: ("RIM" format) // short 0: 'IR' // short 1: comment length // short 2: image width // short 3: image height // // CCIMAGE header bytes: ("MTI" format) // // // static uint16_t rim_getshort (FILE * f, bool swp) { int a = pilla_caracter_segur (f); int b = pilla_caracter_segur (f); IIO_DEBUG ("rgs %.2x%.2x\n", a, b); assert (a >= 0); assert (b >= 0); assert (a < 256); assert (b < 256); uint16_t r = swp ? b * 0x100 + a : a * 0x100 + b; return r; } // Note: different order than for shorts. // Fascinating braindeadness. static uint32_t rim_getint (FILE * f, bool swp) { int a = pilla_caracter_segur (f); int b = pilla_caracter_segur (f); int c = pilla_caracter_segur (f); int d = pilla_caracter_segur (f); IIO_DEBUG ("rgi %.2x%.2x %.2x%.2x\n", a, b, c, d); assert (a >= 0); assert (b >= 0); assert (c >= 0); assert (d >= 0); assert (a < 256); assert (b < 256); assert (c < 256); assert (d < 256); uint32_t r = swp ? a * 0x1000000 + b * 0x10000 + c * 0x100 + d : d * 0x1000000 + c * 0x10000 + b * 0x100 + a; return r; } static int read_beheaded_rim_cimage (struct iio_image *x, FILE * f, bool swp) { uint16_t lencomm = rim_getshort (f, swp); uint16_t dx = rim_getshort (f, swp); uint16_t dy = rim_getshort (f, swp); IIO_DEBUG ("RIM READER lencomm = %d\n", (int) lencomm); IIO_DEBUG ("RIM READER dx = %d\n", (int) dx); IIO_DEBUG ("RIM READER dy = %d\n", (int) dy); FORI (28) rim_getshort (f, swp); // skip shit (ascii numbers and zeros) FORI (lencomm) { int c = pilla_caracter_segur (f); // skip further shit (comments) IIO_DEBUG ("RIM READER comment[%d] = '%c'\n", i, c); } float *data = xmalloc (dx * dy); size_t r = fread (data, 1, dx * dy, f); if (r != (size_t) (dx * dy)) error ("could not read entire RIM file:\n" "expected %zu chars, but got only %zu", (size_t) dx * dy, r); int s[2] = { dx, dy }; iio_wrap_image_struct_around_data (x, 2, s, 1, IIO_TYPE_UINT8, data); return 0; } static void byteswap4 (void *data, int n) { char *t = data; FORI (n) { char *t4 = t + 4 * i; char tt[4] = { t4[3], t4[2], t4[1], t4[0] }; FORL (4) t4[l] = tt[l]; } } static int read_beheaded_rim_fimage (struct iio_image *x, FILE * f, bool swp) { IIO_DEBUG ("rim reader fimage swp = %d", swp); uint16_t lencomm = rim_getshort (f, swp); uint16_t dx = rim_getshort (f, swp); uint16_t dy = rim_getshort (f, swp); //IIO_DEBUG("RIM READER lencomm = %d\n", (int)lencomm); //IIO_DEBUG("RIM READER dx = %d\n", (int)dx); //IIO_DEBUG("RIM READER dy = %d\n", (int)dy); FORI (28) rim_getshort (f, swp); // skip shit (ascii numbers and zeros) FORI (lencomm) { int c = pilla_caracter_segur (f); // skip further shit (comments) //IIO_DEBUG("RIM READER comment[%d] = '%c'\n", i, c); } // now, read dx*dy floats float *data = xmalloc (dx * dy * sizeof *data); size_t r = fread (data, sizeof *data, dx * dy, f); if (r != (size_t) (dx * dy)) error ("could not read entire RIM file:\n" "expected %zu floats, but got only %zu", (size_t) dx * dy, r); assert (sizeof (float) == 4); if (swp) byteswap4 (data, r); int s[2] = { dx, dy }; iio_wrap_image_struct_around_data (x, 2, s, 1, IIO_TYPE_FLOAT, data); return 0; } static int read_beheaded_rim_ccimage (struct iio_image *x, FILE * f, bool swp) { uint16_t iv = rim_getshort (f, swp); if (iv != 0x4956 && iv != 0x5649 && iv != 0x4557 && iv != 0x5745) error ("bad ccimage header %x", (int) iv); uint32_t pm_np = rim_getint (f, swp); uint32_t pm_nrow = rim_getint (f, swp); uint32_t pm_ncol = rim_getint (f, swp); uint32_t pm_band = rim_getint (f, swp); uint32_t pm_form = rim_getint (f, swp); uint32_t pm_cmtsize = rim_getint (f, swp); IIO_DEBUG ("RIM READER pm_np = %d\n", (int) pm_np); IIO_DEBUG ("RIM READER pm_nrow = %d\n", (int) pm_nrow); IIO_DEBUG ("RIM READER pm_ncol = %d\n", (int) pm_ncol); IIO_DEBUG ("RIM READER pm_band = %d\n", (int) pm_band); IIO_DEBUG ("RIM READER pm_form = %x\n", (int) pm_form); IIO_DEBUG ("RIM READER pm_cmtsize = %d\n", (int) pm_cmtsize); uint32_t nsamples = pm_np * pm_nrow * pm_ncol; if (pm_form == 0x8001) { // ccimage uint8_t *data = xmalloc (nsamples); size_t r = fread (data, 1, nsamples, f); if (r != nsamples) error ("rim reader failed at reading %zu " "samples (got only %zu)\n", (size_t) nsamples, r); uint8_t *good_data = xmalloc (nsamples); FORJ (pm_nrow) FORI (pm_ncol) FORL (pm_np) good_data[l + (i + j * pm_ncol) * pm_np] = data[i + j * pm_ncol + l * pm_ncol * pm_nrow]; xfree (data); data = good_data; int s[2] = { pm_ncol, pm_nrow }; iio_wrap_image_struct_around_data (x, 2, s, pm_np, IIO_TYPE_UINT8, data); } else if (pm_form == 0xc004) { // cfimage float *data = xmalloc (4 * nsamples); size_t r = fread (data, 4, nsamples, f); if (r != nsamples) error ("rim reader failed at reading %zu " "samples (got only %zu)\n", (size_t) nsamples, r); float *good_data = xmalloc (4 * nsamples); FORJ (pm_nrow) FORI (pm_ncol) FORL (pm_np) good_data[l + (i + j * pm_ncol) * pm_np] = data[i + j * pm_ncol + l * pm_ncol * pm_nrow]; xfree (data); data = good_data; int s[2] = { pm_ncol, pm_nrow }; iio_wrap_image_struct_around_data (x, 2, s, pm_np, IIO_TYPE_FLOAT, data); } else error ("unsupported PM_form %x", pm_form); return 0; } static int read_beheaded_rim (struct iio_image *x, FILE * f, char *h, int nh) { assert (nh == 2); if (h[0] == 'I' && h[1] == 'R') return read_beheaded_rim_fimage (x, f, false); if (h[0] == 'R' && h[1] == 'I') return read_beheaded_rim_fimage (x, f, true); if (h[0] == 'M' && h[1] == 'I') return read_beheaded_rim_cimage (x, f, false); if (h[0] == 'I' && h[1] == 'M') return read_beheaded_rim_cimage (x, f, true); if (h[0] == 'W' && h[1] == 'E') return read_beheaded_rim_ccimage (x, f, false); if (h[0] == 'V' && h[1] == 'I') return read_beheaded_rim_ccimage (x, f, true); return 1; } static void switch_4endianness (void *tt, int n) { char *t = tt; FORI (n) { char tmp[4] = { t[0], t[1], t[2], t[3] }; t[0] = tmp[3]; t[1] = tmp[2]; t[2] = tmp[1]; t[3] = tmp[0]; t += 4; } } // PFM reader {{{2 static int read_beheaded_pfm (struct iio_image *x, FILE * f, char *header, int nheader) { assert (4 == sizeof (float)); assert (nheader == 2); assert ('f' == tolower (header[1])); int w, h, pd = isupper (header[1]) ? 3 : 1; float scale; if (!isspace (pilla_caracter_segur (f))) return -1; if (3 != fscanf (f, "%d %d\n%g", &w, &h, &scale)) return -2; if (!isspace (pilla_caracter_segur (f))) return -3; float *data = xmalloc (w * h * 4 * pd); if (1 != fread (data, w * h * 4 * pd, 1, f)) return -4; //if (scale < 0) switch_4endianness(data, w*h*pd); x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = pd; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = data; return 0; } // FLO reader {{{2 static int read_beheaded_flo (struct iio_image *x, FILE * f, char *header, int nheader) { int w = rim_getint (f, false); int h = rim_getint (f, false); float *data = xmalloc (w * h * 2 * sizeof *data); if (1 != fread (data, w * h * 4 * 2, 1, f)) return -1; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 2; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = data; return 0; } // JUV reader {{{2 static int read_beheaded_juv (struct iio_image *x, FILE * f, char *header, int nheader) { char buf[255]; FORI (nheader) buf[i] = header[i]; FORI (255 - nheader) buf[i + nheader] = pilla_caracter_segur (f); int w, h, r = sscanf (buf, "#UV {\n dimx %d dimy %d\n}\n", &w, &h); if (r != 2) return -1; size_t sf = sizeof (float); float *u = xmalloc (w * h * sf); r = fread (u, sf, w * h, f); if (r != w * h) return -2; float *v = xmalloc (w * h * sf); r = fread (v, sf, w * h, f); if (r != w * h) return -2; float *uv = xmalloc (2 * w * h * sf); FORI (w * h) uv[2 * i] = u[i]; FORI (w * h) uv[2 * i + 1] = v[i]; xfree (u); xfree (v); x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 2; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = uv; return 0; } // LUM reader {{{2 static int lum_pickshort (char *ss) { uint8_t *s = (uint8_t *) ss; int a = s[0]; int b = s[1]; return 0x100 * a + b; } static int read_beheaded_lum (struct iio_image *x, FILE * f, char *header, int nheader) { int w = lum_pickshort (header + 2); int h = lum_pickshort (header + 6); while (nheader++ < 0xf94) pilla_caracter_segur (f); float *data = xmalloc (w * h * sizeof *data); if (1 != fread (data, w * h * 4, 1, f)) return -1; switch_4endianness (data, w * h); x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 1; x->type = IIO_TYPE_FLOAT; x->contiguous_data = false; x->data = data; return 0; } // BMP reader {{{2 static int read_beheaded_bmp (struct iio_image *x, FILE * f, char *header, int nheader) { long len; char *bmp = load_rest_of_file (&len, f, header, nheader); uint32_t pix_offset = *(uint32_t *) (bmp + 0xa); error ("BMP reader not yet finished"); xfree (bmp); //x->dimension = 2; //x->sizes[0] = dib_width; //x->sizes[1] = dib_height; //x->pixel_dimension = 1; //x->type = IIO_TYPE_FLOAT; //x->contiguous_data = false; //x->data = data; return 0; //fprintf(stderr, "bmp reader\n"); //uint32_t aoffset = *(uint32_t*)(header+0xa); //fprintf(stderr, "aoffset = %d\n", aoffset); //assert(nheader == 14); // ignore the file header //uint32_t dib_size = rim_getint(f, false); //fprintf(stderr, "dib_size = %d\n", dib_size); //if (dib_size != 40) error("only windows-like bitmaps ara supported"); //int32_t dib_width = rim_getint(f, false); //int32_t dib_height = rim_getint(f, false); //uint16_t dib_planes = rim_getshort(f, true); //uint16_t dib_bpp = rim_getshort(f, true); //uint32_t dib_compression = rim_getint(f, false); //fprintf(stderr, "w,h = %dx%d, bpp=%d (p=%d), compression=%d\n", // dib_width, dib_height, // dib_bpp, dib_planes, dib_compression); ////if (dib_planes != 1) error("BMP READER: only one plane is supported (not %d)", dib_planes); //if (dib_compression) error("compressed BMP are not supported"); //uint32_t dib_imsize = rim_getint(f, false); //int32_t dib_hres = rim_getint(f, false); //int32_t dib_vres = rim_getint(f, false); //uint32_t dib_ncolors = rim_getint(f, false); //uint32_t dib_nicolors = rim_getint(f, false); //fprintf(stderr, "ncolors = %d\n", dib_ncolors); //error("fins aquí hem arribat!"); } // EXR reader {{{2 #ifdef I_CAN_HAS_LIBEXR #include // EXTERNALIZED TO : read_exr_float.cpp //extern int read_whole_exr(struct iio_image *x, char *filename); static int read_whole_exr (struct iio_image *x, char *filename) { struct ImfInputFile *f = ImfOpenInputFile (filename); if (!f) error ("could not read exr from %s", filename); int r; const char *nom = ImfInputFileName (f); IIO_DEBUG ("ImfInputFileName returned %s\n", nom); r = ImfInputChannels (f); IIO_DEBUG ("ImfInputChannels returned %d\n", r); // this data is only for information. The file is always // converted to RGB //if (r != IMF_WRITE_RGBA) // error("only RGBA EXR supported so far (got %d)", r); const struct ImfHeader *header = ImfInputHeader (f); int xmin, ymin, xmax, ymax; ImfHeaderDataWindow (header, &xmin, &ymin, &xmax, &ymax); IIO_DEBUG ("xmin ymin xmax ymax = %d %d %d %d\n", xmin, ymin, xmax, ymax); int width = xmax - xmin + 1; int height = ymax - ymin + 1; struct ImfRgba *data = xmalloc (width * height * sizeof *data); r = ImfInputSetFrameBuffer (f, data, 1, width); IIO_DEBUG ("ImfInputSetFrameBuffer returned %d\n", r); r = ImfInputReadPixels (f, ymin, ymax); IIO_DEBUG ("ImfInputReadPixels returned %d\n", r); r = ImfCloseInputFile (f); IIO_DEBUG ("ImfCloseInputFile returned %d\n", r); float *finaldata = xmalloc (4 * width * height * sizeof *data); FORI (width * height) { finaldata[4 * i + 0] = ImfHalfToFloat (data[i].r); finaldata[4 * i + 1] = ImfHalfToFloat (data[i].g); finaldata[4 * i + 2] = ImfHalfToFloat (data[i].b); finaldata[4 * i + 3] = ImfHalfToFloat (data[i].a); //IIO_DEBUG("read %d rgb %g %g %g\n", i, finaldata[3*i+0], finaldata[3*i+1], finaldata[3*i+2]); } xfree (data); // fill struct fields x->dimension = 2; x->sizes[0] = width; x->sizes[1] = height; x->pixel_dimension = 4; x->type = IIO_TYPE_FLOAT; x->format = x->meta = -42; x->data = finaldata; x->contiguous_data = false; return 0; } // Note: OpenEXR library only reads from a named file. The only way to use the // library if you have your image in a stream, is to write the data to a // temporary file, and read it from there. This can be optimized in the future // by recovering the original filename through hacks, in case it was not a pipe. static int read_beheaded_exr (struct iio_image *x, FILE * fin, char *header, int nheader) { if (global_variable_containing_the_name_of_the_last_opened_file) { int r = read_whole_exr (x, global_variable_containing_the_name_of_the_last_opened_file); if (r) error ("read whole tiff returned %d", r); return 0; } long filesize; void *filedata = load_rest_of_file (&filesize, fin, header, nheader); char *filename = put_data_into_temporary_file (filedata, filesize); xfree (filedata); //IIO_DEBUG("tmpfile = \"%s\"\n", filename); int r = read_whole_exr (x, filename); if (r) error ("read whole exr returned %d", r); delete_temporary_file (filename); return 0; } #endif //I_CAN_HAS_LIBEXR // WHATEVER reader {{{2 //static int read_image(struct iio_image*, const char *); static int read_image_f (struct iio_image *, FILE *); static int read_beheaded_whatever (struct iio_image *x, FILE * fin, char *header, int nheader) { // dump data to file long filesize; void *filedata = load_rest_of_file (&filesize, fin, header, nheader); char *filename = put_data_into_temporary_file (filedata, filesize); xfree (filedata); //IIO_DEBUG("tmpfile = \"%s\"\n", filename); //char command_format[] = "convert - %s < %s\0"; char command_format[] = "/usr/bin/convert - %s < %s\0"; char ppmname[strlen (filename) + 5]; sprintf (ppmname, "%s.ppm", filename); char command[strlen (command_format) + 1 + 2 * strlen (filename)]; sprintf (command, command_format, ppmname, filename); IIO_DEBUG ("COMMAND: %s\n", command); int r = system (command); IIO_DEBUG ("command returned %d\n", r); if (r) error ("could not run command \"%s\" successfully", command); FILE *f = xfopen (ppmname, "r"); r = read_image_f (x, f); xfclose (f); delete_temporary_file (filename); delete_temporary_file (ppmname); return r; } // individual format writers {{{1 // PNG writer {{{2 #ifdef I_CAN_HAS_LIBPNG static void iio_save_image_as_png (const char *filename, struct iio_image *x) { png_structp pp = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!pp) error ("png_create_write_struct fail"); png_infop pi = png_create_info_struct (pp); if (!pi) error ("png_create_info_struct fail"); if (setjmp (png_jmpbuf (pp))) error ("png write error"); if (x->dimension != 2) error ("can only save 2d images"); int width = x->sizes[0]; int height = x->sizes[1]; int bit_depth = 0; switch (normalize_type (x->type)) { case IIO_TYPE_UINT16: case IIO_TYPE_INT16: bit_depth = 16; break; case IIO_TYPE_INT8: case IIO_TYPE_UINT8: bit_depth = 8; break; default: error ("can not yet save samples of type %s as PNG", iio_strtyp (x->type)); } assert (bit_depth > 0); int color_type = PNG_COLOR_TYPE_PALETTE; switch (x->pixel_dimension) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: error ("can not save %d-dimensional samples as PNG", x->pixel_dimension); } assert (color_type != PNG_COLOR_TYPE_PALETTE); FILE *f = xfopen (filename, "w"); png_init_io (pp, f); int ss = bit_depth / 8; int pd = x->pixel_dimension; png_bytepp row = xmalloc (height * sizeof (png_bytep)); FORI (height) row[i] = i * pd * width * ss + (uint8_t *) x->data; png_set_IHDR (pp, pi, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_rows (pp, pi, row); int transforms = PNG_TRANSFORM_IDENTITY; png_write_png (pp, pi, transforms, NULL); xfclose (f); png_destroy_write_struct (&pp, &pi); xfree (row); } #endif //I_CAN_HAS_LIBPNG // TIFF writer {{{2 #ifdef I_CAN_HAS_LIBTIFF static void iio_save_image_as_tiff (const char *filename, struct iio_image *x) { //fprintf(stderr, "saving image as tiff file \"%s\"\n", filename); if (x->dimension != 2) error ("only 2d images can be saved as TIFFs"); TIFF *tif = TIFFOpen (filename, "w"); if (!tif) error ("could not open TIFF file \"%s\"", filename); int ss = iio_image_sample_size (x); int sls = x->sizes[0] * x->pixel_dimension * ss; int tsf; TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, x->sizes[0]); TIFFSetField (tif, TIFFTAG_IMAGELENGTH, x->sizes[1]); TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, x->pixel_dimension); TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, ss * 8); uint16 caca[1] = { EXTRASAMPLE_UNASSALPHA }; switch (x->pixel_dimension) { case 1: TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); break; case 3: TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); break; case 2: TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); //TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, caca); break; case 4: TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, caca); break; default: TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); //error("bad pixel dimension %d for TIFF", x->pixel_dimension); } /////TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField (tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); //TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); switch (x->type) { case IIO_TYPE_FLOAT: tsf = SAMPLEFORMAT_IEEEFP; break; case IIO_TYPE_INT8: case IIO_TYPE_INT16: case IIO_TYPE_INT32: tsf = SAMPLEFORMAT_INT; break; case IIO_TYPE_UINT8: case IIO_TYPE_UINT16: case IIO_TYPE_UINT32: tsf = SAMPLEFORMAT_UINT; break; default: error ("can not save samples of type %s on tiff file", iio_strtyp (x->type)); } TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, tsf); FORI (x->sizes[1]) { void *line = i * sls + (char *) x->data; int r = TIFFWriteScanline (tif, line, i, 0); if (r < 0) error ("error writing %dth TIFF scanline", i); } TIFFClose (tif); } static void iio_save_image_as_tiff_smarter (const char *filename, struct iio_image *x) { char *tiffname = strstr (filename, "TIFF:"); if (tiffname == filename) { iio_save_image_as_tiff_smarter (filename + 5, x); return; } if (0 == strcmp (filename, "-")) { #ifdef I_CAN_HAS_MKSTEMP static char tfn[] = "/tmp/iio_temporal_tiff_XXXXXX\0"; int r = mkstemp (tfn); if (r == -1) error ("caca [tiff smarter]"); #else static char buf[L_tmpnam + 1]; char *tfn = tmpnam (buf); #endif //I_CAN_HAS_MKSTEMP iio_save_image_as_tiff (tfn, x); FILE *f = xfopen (tfn, "r"); int c; while ((c = fgetc (f)) != EOF) fputc (c, stdout); fclose (f); delete_temporary_file (tfn); } else iio_save_image_as_tiff (filename, x); } #endif //I_CAN_HAS_LIBTIFF // JUV writer {{{2 static void iio_save_image_as_juv (const char *filename, struct iio_image *x) { assert (x->type == IIO_TYPE_FLOAT); assert (x->dimension == 2); char buf[255]; FORI (255) buf[i] = ' '; snprintf (buf, 255, "#UV {\n dimx %d dimy %d\n}\n", x->sizes[0], x->sizes[1]); size_t sf = sizeof (float); int w = x->sizes[0]; int h = x->sizes[1]; float *uv = x->data; float *u = xmalloc (w * h * sf); FORI (w * h) u[i] = uv[2 * i]; float *v = xmalloc (w * h * sf); FORI (w * h) v[i] = uv[2 * i + 1]; FILE *f = xfopen (filename, "w"); fwrite (buf, 1, 255, f); fwrite (u, sf, w * h, f); fwrite (v, sf, w * h, f); xfclose (f); xfree (u); xfree (v); } // FLO writer {{{2 static void iio_save_image_as_flo (const char *filename, struct iio_image *x) { assert (x->type == IIO_TYPE_FLOAT); assert (x->dimension == 2); union { char s[4]; float f; } pieh = { "PIEH"}; assert (sizeof (float) == 4); assert (pieh.f == 202021.25); uint32_t w = x->sizes[0]; uint32_t h = x->sizes[1]; FILE *f = xfopen (filename, "w"); fwrite (&pieh.f, 4, 1, f); fwrite (&w, 4, 1, f); fwrite (&h, 4, 1, f); fwrite (x->data, 4, w * h * 2, f); xfclose (f); } // RIM writer {{{2 static void rim_putshort (FILE * f, uint16_t n) { int a = n % 0x100; int b = n / 0x100; assert (a >= 0); assert (b >= 0); assert (a < 256); assert (b < 256); fputc (b, f); fputc (a, f); } static void iio_save_image_as_rim_fimage (const char *fname, struct iio_image *x) { if (x->type != IIO_TYPE_FLOAT) error ("fimage expects float data"); if (x->dimension != 2) error ("fimage expects 2d image"); if (x->pixel_dimension != 1) error ("fimage expects gray image"); FILE *f = xfopen (fname, "w"); fputc ('I', f); fputc ('R', f); rim_putshort (f, 2); rim_putshort (f, x->sizes[0]); rim_putshort (f, x->sizes[1]); FORI (29) rim_putshort (f, 0); int r = fwrite (x->data, sizeof (float), x->sizes[0] * x->sizes[1], f); if (r != x->sizes[0] * x->sizes[1]) error ("could not write an entire fimage for some reason"); xfclose (f); } static void iio_save_image_as_rim_cimage (const char *fname, struct iio_image *x) { if (x->type != IIO_TYPE_UINT8) error ("cimage expects byte data"); if (x->dimension != 2) error ("cimage expects 2d image"); if (x->pixel_dimension != 1) error ("cimage expects gray image"); FILE *f = xfopen (fname, "w"); fputc ('M', f); fputc ('I', f); rim_putshort (f, 2); rim_putshort (f, x->sizes[0]); rim_putshort (f, x->sizes[1]); FORI (29) rim_putshort (f, 0); int r = fwrite (x->data, 1, x->sizes[0] * x->sizes[1], f); if (r != x->sizes[0] * x->sizes[1]) error ("could not write an entire cimage for some reason"); xfclose (f); } // guess format using magic {{{1 static char add_to_header_buffer (FILE * f, uint8_t * buf, int *nbuf, int bufmax) { int c = pilla_caracter_segur (f); if (*nbuf >= bufmax) error ("buffer header too small (%d)", bufmax); buf[*nbuf] = c; //iw810 IIO_DEBUG ("ATHB[%d] = %x \"%c\"\n", *nbuf, c, c); *nbuf += 1; return c; } static int guess_format (FILE * f, char *buf, int *nbuf, int bufmax) { assert (sizeof (uint8_t) == sizeof (char)); uint8_t *b = (uint8_t *) buf; *nbuf = 0; // // program a state machine here // b[0] = add_to_header_buffer (f, b, nbuf, bufmax); b[1] = add_to_header_buffer (f, b, nbuf, bufmax); if (b[0] == 'P' || b[0] == 'Q') if (b[1] >= '1' && b[1] <= '9') return IIO_FORMAT_QNM; if (b[0] == 'P' && (b[1] == 'F' || b[1] == 'f')) return IIO_FORMAT_PFM; #ifdef I_CAN_HAS_LIBTIFF if ((b[0] == 'M' && buf[1] == 'M') || (b[0] == 'I' && buf[1] == 'I')) return IIO_FORMAT_TIFF; #endif //I_CAN_HAS_LIBTIFF if (b[0] == 'I' && b[1] == 'R') return IIO_FORMAT_RIM; if (b[0] == 'R' && b[1] == 'I') return IIO_FORMAT_RIM; if (b[0] == 'M' && b[1] == 'I') return IIO_FORMAT_RIM; if (b[0] == 'I' && b[1] == 'M') return IIO_FORMAT_RIM; if (b[0] == 'W' && b[1] == 'E') return IIO_FORMAT_RIM; if (b[0] == 'V' && b[1] == 'I') return IIO_FORMAT_RIM; if (b[0] == 'P' && b[1] == 'C') return IIO_FORMAT_PCM; if (b[0] == 'B' && b[1] == 'M') { FORI (12) add_to_header_buffer (f, b, nbuf, bufmax); return IIO_FORMAT_BMP; } b[2] = add_to_header_buffer (f, b, nbuf, bufmax); b[3] = add_to_header_buffer (f, b, nbuf, bufmax); #ifdef I_CAN_HAS_LIBPNG if (b[1] == 'P' && b[2] == 'N' && b[3] == 'G') return IIO_FORMAT_PNG; #endif //I_CAN_HAS_LIBPNG #ifdef I_CAN_HAS_LIBEXR if (b[0] == 0x76 && b[1] == 0x2f && b[2] == 0x31 && b[3] == 0x01) return IIO_FORMAT_EXR; #endif //I_CAN_HAS_LIBEXR if (b[0] == '#' && b[1] == 'U' && b[2] == 'V') return IIO_FORMAT_JUV; if (b[0] == 'P' && b[1] == 'I' && b[2] == 'E' && b[3] == 'H') return IIO_FORMAT_FLO; b[4] = add_to_header_buffer (f, b, nbuf, bufmax); b[5] = add_to_header_buffer (f, b, nbuf, bufmax); b[6] = add_to_header_buffer (f, b, nbuf, bufmax); b[7] = add_to_header_buffer (f, b, nbuf, bufmax); #ifdef I_CAN_HAS_LIBJPEG if (b[0] == 0xff && b[1] == 0xd8 && b[2] == 0xff) { if (b[3] == 0xe0 && b[6] == 'J' && b[7] == 'F') return IIO_FORMAT_JPEG; if (b[3] == 0xe1 && b[6] == 'E' && b[7] == 'x') return IIO_FORMAT_JPEG; } #endif //I_CAN_HAS_LIBPNG b[8] = add_to_header_buffer (f, b, nbuf, bufmax); b[9] = add_to_header_buffer (f, b, nbuf, bufmax); b[10] = add_to_header_buffer (f, b, nbuf, bufmax); b[11] = add_to_header_buffer (f, b, nbuf, bufmax); if (b[8] == 'F' && b[9] == 'L' && b[10] == 'O' && b[11] == 'A') return IIO_FORMAT_LUM; return IIO_FORMAT_UNRECOGNIZED; } // dispatcher {{{1 // "centralized dispatcher" static int read_beheaded_image (struct iio_image *x, FILE * f, char *h, int hn, int fmt) { IIO_DEBUG ("rbi fmt = %d\n", fmt); // these functions can be defined in separate, independent files switch (fmt) { case IIO_FORMAT_QNM: return read_beheaded_qnm (x, f, h, hn); case IIO_FORMAT_RIM: return read_beheaded_rim (x, f, h, hn); case IIO_FORMAT_PFM: return read_beheaded_pfm (x, f, h, hn); case IIO_FORMAT_FLO: return read_beheaded_flo (x, f, h, hn); case IIO_FORMAT_JUV: return read_beheaded_juv (x, f, h, hn); case IIO_FORMAT_LUM: return read_beheaded_lum (x, f, h, hn); case IIO_FORMAT_PCM: return read_beheaded_pcm (x, f, h, hn); case IIO_FORMAT_BMP: return read_beheaded_bmp (x, f, h, hn); #ifdef I_CAN_HAS_LIBPNG case IIO_FORMAT_PNG: return read_beheaded_png (x, f, h, hn); #endif #ifdef I_CAN_HAS_LIBJPEG case IIO_FORMAT_JPEG: return read_beheaded_jpeg (x, f, h, hn); #endif #ifdef I_CAN_HAS_LIBTIFF case IIO_FORMAT_TIFF: return read_beheaded_tiff (x, f, h, hn); #endif #ifdef I_CAN_HAS_LIBEXR case IIO_FORMAT_EXR: return read_beheaded_exr (x, f, h, hn); #endif /* case IIO_FORMAT_JP2: return read_beheaded_jp2 (x, f, h, hn); case IIO_FORMAT_VTK: return read_beheaded_vtk (x, f, h, hn); case IIO_FORMAT_CIMG: return read_beheaded_cimg(x, f, h, hn); case IIO_FORMAT_PAU: return read_beheaded_pau (x, f, h, hn); case IIO_FORMAT_DICOM: return read_beheaded_dicom(x, f, h, hn); case IIO_FORMAT_NIFTI: return read_beheaded_nifti(x, f, h, hn); case IIO_FORMAT_PCX: return read_beheaded_pcx (x, f, h, hn); case IIO_FORMAT_GIF: return read_beheaded_gif (x, f, h, hn); case IIO_FORMAT_XPM: return read_beheaded_xpm (x, f, h, hn); case IIO_FORMAT_RAFA: return read_beheaded_rafa (x, f, h, hn); */ //#ifdef I_CAN_HAS_WHATEVER case IIO_FORMAT_UNRECOGNIZED: return read_beheaded_whatever (x, f, h, hn); //#else // case IIO_FORMAT_UNRECOGNIZED: return -2; //#endif default: return -17; } } // general image reader {{{1 // // This function is the core of the library. // Everything passes through here. // static int read_image_f (struct iio_image *x, FILE * f) { int bufmax = 0x100, nbuf, format; char buf[bufmax]; format = guess_format (f, buf, &nbuf, bufmax); IIO_DEBUG ("iio file format guess: %s {%d}\n", iio_strfmt (format), nbuf); assert (nbuf > 0); return read_beheaded_image (x, f, buf, nbuf, format); } static int read_image (struct iio_image *x, const char *fname) { #ifndef IIO_ABORT_ON_ERROR if (setjmp (global_jump_buffer)) { IIO_DEBUG ("SOME ERROR HAPPENED AND WAS HANDLED\n"); return 1; } //if (iio_single_jmpstuff(false, true)) { // IIO_DEBUG("SOME ERROR HAPPENED AND WAS HANDLED\n"); // exit(42); //} #endif //IIO_ABORT_ON_ERROR FILE *f = xfopen (fname, "r"); int r = read_image_f (x, f); fclose (f); IIO_DEBUG ("READ IMAGE return value = %d\n", r); IIO_DEBUG ("READ IMAGE dimension = %d\n", x->dimension); switch (x->dimension) { case 1: IIO_DEBUG ("READ IMAGE sizes = %d\n", x->sizes[0]); break; case 2: IIO_DEBUG ("READ IMAGE sizes = %d x %d\n", x->sizes[0], x->sizes[1]); break; case 3: IIO_DEBUG ("READ IMAGE sizes = %d x %d x %d\n", x->sizes[0], x->sizes[1], x->sizes[2]); break; case 4: IIO_DEBUG ("READ IMAGE sizes = %d x %d x %d x %d\n", x->sizes[0], x->sizes[1], x->sizes[2], x->sizes[3]); break; default: error ("caca [dimension = %d]", x->dimension); } //FORI(x->dimension) IIO_DEBUG(" %d", x->sizes[i]); //IIO_DEBUG("\n"); IIO_DEBUG ("READ IMAGE pixel_dimension = %d\n", x->pixel_dimension); IIO_DEBUG ("READ IMAGE type = %s\n", iio_strtyp (x->type)); //IIO_DEBUG("READ IMAGE meta = %d\n", x->meta); //IIO_DEBUG("READ IMAGE format = %d\n", x->format); IIO_DEBUG ("READ IMAGE contiguous_data = %d\n", x->contiguous_data); return r; } static void iio_save_image_default (const char *filename, struct iio_image *x); // API (input) {{{1 static void * rerror (const char *fmt, ...) { #ifdef IIO_ABORT_ON_ERROR va_list argp; va_start (argp, fmt); error (fmt, argp); va_end (argp); #endif return NULL; } // 2D only static void * iio_read_image (const char *fname, int *w, int *h, int desired_sample_type) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; //error("non 2d image"); } *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, desired_sample_type); return x->data; } // API 2D float * iio_read_image_float_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; //error("non 2d image"); } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; iio_convert_samples (x, IIO_TYPE_FLOAT); return x->data; } // API 2D float * iio_read_image_float_split (const char *fname, int *w, int *h, int *pd) { float *r = iio_read_image_float_vec (fname, w, h, pd); float *rbroken = xmalloc (*w ** h ** pd * sizeof *rbroken); break_pixels_float (rbroken, r, *w ** h, *pd); xfree (r); return rbroken; } // API 2D float * iio_read_image_float_rgb (const char *fname, int *w, int *h) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension != 3) { iio_hacky_colorize (x, 3); } *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_FLOAT); return x->data; } // API 2D double * iio_read_image_double_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; //error("non 2d image"); } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; iio_convert_samples (x, IIO_TYPE_DOUBLE); return x->data; } // API 2D uint8_t * iio_read_image_uint8_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; iio_convert_samples (x, IIO_TYPE_UINT8); return x->data; } // API 2D uint16_t * iio_read_image_uint16_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; iio_convert_samples (x, IIO_TYPE_UINT16); return x->data; } // API 2D uint8_t (*iio_read_image_uint8_rgb (const char *fname, int *w, int *h))[3] { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; error ("non 2d image"); } if (x->pixel_dimension != 3) error ("non-color image"); *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_UINT8); return x->data; } // API 2D uint8_t (**iio_read_image_uint8_matrix_rgb (const char *fnam, int *w, int *h)) [3] { struct iio_image x[1]; int r = read_image (x, fnam); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension != 3) { iio_hacky_colorize (x, 3); } *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_UINT8); return wrap_2dmatrix_around_data (x->data, *w, *h, 3); } // API 2D float (**iio_read_image_float_matrix_rgb (const char *fnam, int *w, int *h)) [3] { struct iio_image x[1]; int r = read_image (x, fnam); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension != 3) { iio_hacky_colorize (x, 3); } *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_FLOAT); return wrap_2dmatrix_around_data (x->data, *w, *h, 3 * sizeof (float)); } // API 2D uint8_t *** iio_read_image_uint8_matrix_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; fprintf (stderr, "matrix_vec pd = %d\n", *pd); iio_convert_samples (x, IIO_TYPE_UINT8); return wrap_2dmatrix_around_data (x->data, *w, *h, *pd); } // API 2D void * iio_read_image_float_matrix_vec (const char *fname, int *w, int *h, int *pd) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } *w = x->sizes[0]; *h = x->sizes[1]; *pd = x->pixel_dimension; iio_convert_samples (x, IIO_TYPE_FLOAT); return wrap_2dmatrix_around_data (x->data, *w, *h, *pd * sizeof (float)); } // API 2D uint8_t ** iio_read_image_uint8_matrix (const char *fname, int *w, int *h) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension == 3) iio_hacky_uncolorize (x); if (x->pixel_dimension != 1) error ("non-scalar image"); *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_UINT8); return wrap_2dmatrix_around_data (x->data, *w, *h, 1); //return x->data; // WRONG!: //uint8_t *f = iio_read_image_uint8(fname, w, h); //uint8_t **a = wrap_2dmatrix_around_data(f, *w, *h, sizeof*f); //return a; } float ** iio_read_image_float_matrix (const char *fname, int *w, int *h) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension == 3) iio_hacky_uncolorize (x); if (x->pixel_dimension != 1) return rerror ("non-scalar image"); *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_FLOAT); return wrap_2dmatrix_around_data (x->data, *w, *h, sizeof (float)); } // API nd general void * iio_read_nd_image_as_stored (char *fname, int *dimension, int *sizes, int *samples_per_pixel, int *sample_size, bool * ieefp_samples, bool * signed_samples) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("so much fail"); *dimension = x->dimension; FORI (x->dimension) sizes[i] = x->sizes[i]; *samples_per_pixel = x->pixel_dimension; iio_type_unid (sample_size, ieefp_samples, signed_samples, x->type); return x->data; } // API nd general void * iio_read_nd_image_as_desired (char *fname, int *dimension, int *sizes, int *samples_per_pixel, int desired_sample_size, bool desired_ieeefp_samples, bool desired_signed_samples) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("so much fail"); int desired_type = iio_type_id (desired_sample_size, desired_ieeefp_samples, desired_signed_samples); iio_convert_samples (x, desired_type); *dimension = x->dimension; FORI (x->dimension) sizes[i] = x->sizes[i]; *samples_per_pixel = x->pixel_dimension; return x->data; } //// API 2D general //void *iio_read_image_numbers_as_they_are_stored(char *fname, int *w, int *h, // int *samples_per_pixel, int *sample_size, // bool *ieeefp_samples, bool *signed_samples) //{ //} // API 2D float * iio_read_image_float (const char *fname, int *w, int *h) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension == 3) iio_hacky_uncolorize (x); if (x->pixel_dimension == 4) iio_hacky_uncolorizea (x); if (x->pixel_dimension != 1) return rerror ("non-scalarizable image"); *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_FLOAT); return x->data; } // API 2D double * iio_read_image_double (const char *fname, int *w, int *h) { struct iio_image x[1]; int r = read_image (x, fname); if (r) return rerror ("could not read image"); if (x->dimension != 2) { x->dimension = 2; return rerror ("non 2d image"); } if (x->pixel_dimension == 3) iio_hacky_uncolorize (x); if (x->pixel_dimension != 1) return rerror ("non-scalar image"); *w = x->sizes[0]; *h = x->sizes[1]; iio_convert_samples (x, IIO_TYPE_DOUBLE); return x->data; } //// API 2D //char *iio_read_image_char(const char *fname, int *w, int *h) //{ // return iio_read_image(fname, w, h, IIO_TYPE_CHAR); //} // API 2D uint8_t * iio_read_image_uint8 (const char *fname, int *w, int *h) { return iio_read_image (fname, w, h, IIO_TYPE_UINT8); } // API 2D //float **iio_read_image_float_matrix(const char *fname, int *w, int *h) //{ // float *f = iio_read_image_float(fname, w, h); // float **a = wrap_2dmatrix_around_data(f, *w, *h, sizeof*f); // return a; //} // API (output) {{{1 static bool this_float_is_actually_a_byte (float x) { return (x == floorf (x)) && (x >= 0) && (x < 256); } static bool these_floats_are_actually_bytes (float *t, int n) { IIO_DEBUG ("checking %d floats for byteness (%p)\n", n, (void *) t); FORI (n) if (!this_float_is_actually_a_byte (t[i])) return false; return true; } //// returns the un-prefixed string, or NULL //static const char *hasprefix(const char *haystack, const char *needle) //{ // const char *r = strstr(haystack, needle); // if (r == haystack) // return r + strlen(needle); // else // return NULL; //} // //// returns the first argument, or NULL //static const char *hassufix(const char *haystack, const char *needle) //{ // const char *r = //} static bool string_suffix (const char *s, const char *suf) { int len_s = strlen (s); int len_suf = strlen (suf); if (len_s < len_suf) return false; return 0 == strcmp (suf, s + (len_s - len_suf)); } // Note: // This function was written without being designed. See file "saving.txt" for // an attempt at designing it. static void iio_save_image_default (const char *filename, struct iio_image *x) { int typ = normalize_type (x->type); if (x->dimension != 2) error ("de moment només escrivim 2D"); //static bool silly = true; if (string_suffix (filename, ".uv") && typ == IIO_TYPE_FLOAT && x->pixel_dimension == 2) { iio_save_image_as_juv (filename, x); return; } if (string_suffix (filename, ".flo") && typ == IIO_TYPE_FLOAT && x->pixel_dimension == 2) { iio_save_image_as_flo (filename, x); return; } if (string_suffix (filename, ".mw") && typ == IIO_TYPE_FLOAT && x->pixel_dimension == 1) { iio_save_image_as_rim_fimage (filename, x); return; } if (string_suffix (filename, ".mw") && typ == IIO_TYPE_UINT8 && x->pixel_dimension == 1) { iio_save_image_as_rim_cimage (filename, x); return; } if (x->pixel_dimension != 1 && x->pixel_dimension != 3 && x->pixel_dimension != 4 && x->pixel_dimension != 2) { iio_save_image_as_tiff_smarter (filename, x); return; //error("de moment només escrivim gris ó RGB"); } if (typ != IIO_TYPE_FLOAT && typ != IIO_TYPE_UINT8 && typ != IIO_TYPE_INT16 && typ != IIO_TYPE_INT8) error ("de moment només fem floats o bytes (got %d)", typ); int nsamp = iio_image_number_of_samples (x); if (typ == IIO_TYPE_FLOAT && these_floats_are_actually_bytes (x->data, nsamp)) { void *old_data = x->data; x->data = xmalloc (nsamp * sizeof (float)); memcpy (x->data, old_data, nsamp * sizeof (float)); iio_convert_samples (x, IIO_TYPE_UINT8); //silly=false; iio_save_image_default (filename, x); // recursive call //silly=true; xfree (x->data); x->data = old_data; return; } if (true) { if (false || string_suffix (filename, ".tiff") || string_suffix (filename, ".tif") || string_suffix (filename, ".TIFF") || string_suffix (filename, ".TIF")) { iio_save_image_as_tiff_smarter (filename, x); return; } } if (true) { char *tiffname = strstr (filename, "TIFF:"); if (tiffname == filename) { iio_save_image_as_tiff_smarter (filename + 5, x); return; } } if (true) { char *pngname = strstr (filename, "PNG:"); if (pngname == filename) { if (typ == IIO_TYPE_FLOAT) { void *old_data = x->data; x->data = xmalloc (nsamp * sizeof (float)); memcpy (x->data, old_data, nsamp * sizeof (float)); iio_convert_samples (x, IIO_TYPE_UINT8); iio_save_image_default (filename, x); //recursive xfree (x->data); x->data = old_data; return; } iio_save_image_as_png (filename + 4, x); return; } } if (true) { if (false || string_suffix (filename, ".png") || string_suffix (filename, ".PNG") || (typ == IIO_TYPE_UINT8 && x->pixel_dimension == 4) // || (typ==IIO_TYPE_FLOAT&&x->pixel_dimension==4) || (typ == IIO_TYPE_UINT8 && x->pixel_dimension == 2) // || (typ==IIO_TYPE_FLOAT&&x->pixel_dimension==2) ) { if (typ == IIO_TYPE_FLOAT) { void *old_data = x->data; x->data = xmalloc (nsamp * sizeof (float)); memcpy (x->data, old_data, nsamp * sizeof (float)); iio_convert_samples (x, IIO_TYPE_UINT8); iio_save_image_default (filename, x); //recursive xfree (x->data); x->data = old_data; return; } iio_save_image_as_png (filename, x); return; } } IIO_DEBUG ("SIDEF:\n"); #ifdef IIO_SHOW_DEBUG_MESSAGES iio_print_image_info (stderr, x); #endif FILE *f = xfopen (filename, "w"); if (x->pixel_dimension == 1 && typ == IIO_TYPE_FLOAT) { int m = these_floats_are_actually_bytes (x->data, x->sizes[0] * x->sizes[1]) ? 255 : 65535; fprintf (f, "P2\n%d %d\n%d\n", x->sizes[0], x->sizes[1], m); float *data = x->data; FORI (x->sizes[0] * x->sizes[1]) fprintf (f, "%a\n", data[i]); } else if (x->pixel_dimension == 3 && typ == IIO_TYPE_FLOAT) { int m = these_floats_are_actually_bytes (x->data, 3 * x->sizes[0] * x->sizes[1]) ? 255 : 65535; float *data = x->data; fprintf (f, "P3\n%d %d\n%d\n", x->sizes[0], x->sizes[1], m); FORI (3 * x->sizes[0] * x->sizes[1]) { fprintf (f, "%g\n", data[i]); } } else if (x->pixel_dimension == 3 && typ == IIO_TYPE_UINT8) { uint8_t *data = x->data; int w = x->sizes[0]; int h = x->sizes[1]; if (w * h <= 10000) { fprintf (f, "P3\n%d %d\n255\n", w, h); FORI (3 * w * h) { int datum = data[i]; fprintf (f, "%d\n", datum); } } else { fprintf (f, "P6\n%d %d\n255\n", w, h); fwrite (data, 3 * w * h, 1, f); } } else if (x->pixel_dimension == 4 && typ == IIO_TYPE_UINT8) { fprintf (stderr, "IIO WARNING: assuming 4 chanels mean RGBA\n"); uint8_t *data = x->data; fprintf (f, "P3\n%d %d\n255\n", x->sizes[0], x->sizes[1]); //error("write correctly here"); FORI (4 * x->sizes[0] * x->sizes[1]) { if (i % 4 == 3) continue; int datum = data[i]; fprintf (f, "%d\n", datum); } } else if (x->pixel_dimension == 1 && typ == IIO_TYPE_UINT8) { uint8_t *data = x->data; int w = x->sizes[0]; int h = x->sizes[1]; if (w * h <= 10000) { fprintf (f, "P2\n%d %d\n255\n", w, h); FORI (w * h) { int datum = data[i]; fprintf (f, "%d\n", datum); } } else { fprintf (f, "P5\n%d %d\n255\n", w, h); fwrite (data, w * h, 1, f); } } else iio_save_image_as_tiff_smarter (filename, x); // error("\n\n\nThis particular data format can not yet be saved." // "\nPlease, ask enric.\n"); xfclose (f); } void iio_save_image_uint8_matrix_rgb (char *filename, uint8_t (**data)[3], int w, int h) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 3; x->type = IIO_TYPE_UINT8; x->data = data[0][0]; iio_save_image_default (filename, x); } void iio_save_image_uint8_matrix (char *filename, uint8_t ** data, int w, int h) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 1; x->type = IIO_TYPE_UINT8; x->data = data[0]; iio_save_image_default (filename, x); } void iio_save_image_float_vec (char *filename, float *data, int w, int h, int pd) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = pd; x->type = IIO_TYPE_FLOAT; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } void iio_save_image_float_split (char *filename, float *data, int w, int h, int pd) { float *rdata = xmalloc (w * h * pd * sizeof *rdata); recover_broken_pixels_float (rdata, data, w * h, pd); iio_save_image_float_vec (filename, rdata, w, h, pd); xfree (rdata); } void iio_save_image_double_vec (char *filename, double *data, int w, int h, int pd) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = pd; x->type = IIO_TYPE_DOUBLE; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } void iio_save_image_float (char *filename, float *data, int w, int h) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 1; x->type = IIO_TYPE_FLOAT; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } void iio_save_image_double (char *filename, double *data, int w, int h) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = 1; x->type = IIO_TYPE_DOUBLE; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } void iio_save_image_uint8_vec (char *filename, uint8_t * data, int w, int h, int pd) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = pd; x->type = IIO_TYPE_UINT8; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } void iio_save_image_uint16_vec (char *filename, uint16_t * data, int w, int h, int pd) { struct iio_image x[1]; x->dimension = 2; x->sizes[0] = w; x->sizes[1] = h; x->pixel_dimension = pd; x->type = IIO_TYPE_UINT16; x->data = data; x->contiguous_data = false; iio_save_image_default (filename, x); } // misc debugging stuff {{{1 //void try_iio(void); //void try_iio(void) //{ //#ifdef _XOPEN_SOURCE // IIO_DEBUG("IIO compiled with _XOPEN_SOURCE = %d\n",_XOPEN_SOURCE); //#endif // int w, h; // float **t = iio_read_image_float_matrix("-", &w, &h); // printf("we read a %dx%d image!\n", w, h); // xfree(t); // // /* // FILE *f = stdin; // struct iio_image x[1]; read_image_f(x, f); // printf("we read a %dx%d image!\n", x->sizes[0], x->sizes[1]); // iio_print_image_info(stdout, x); // xfree(x->data); // */ // /* // FILE *f = stdin; // struct iio_image *x = read_whole_jpeg(f); // printf("we read a %dx%d jpg!\n", x->sizes[0], x->sizes[1]); // unsigned char *data = x->data; // FORJ(x->sizes[1]) FORI(x->sizes[0]) // FORL(x->pixel_dimension) // printf("%g%c", (float)data[(x->sizes[0]*j+i)*x->pixel_dimension+l], // l==x->pixel_dimension-1?'\n':' '); // xfree(x); // */ // /* // FILE *f = stdin; // //struct iio_image x[1]; // char buf[4]; // FORI(4) buf[i] = fgetc(f); // struct iio_image *x = read_beheaded_image_png(f, buf, 4); // printf("we read a %dx%d png!\n", x->sizes[0], x->sizes[1]); // float *data = x->data; // //FORJ(x->sizes[1]) FORI(x->sizes[0]) // // FORL(x->pixel_dimension) // // printf("%g%c", data[(x->sizes[0]*j+i)*x->pixel_dimension+l], // // l==x->pixel_dimension-1?'\n':' '); // xfree(x); // */ //} // }}}1 // vim:set foldmethod=marker: