// 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
// <http://www.opensource.org/licenses/bsd-license.html>.
//
// Copyright 2012 Enric Meinhardt-Llopis <enric.meinhardt@cmla.ens-cachan.fr>
// 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 <enric.meinhardt@cmla.ens-cachan.fr>
//
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#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 <png.h>
#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 <setjmp.h>
#endif //I_CAN_HAS_LIBPNG
static jmp_buf global_jump_buffer;
#endif //IIO_ABORT_ON_ERROR
//#include <errno.h> // only for errno
#include <ctype.h> // for isspace
#include <math.h> // for floorf
#include <stdlib.h>
#ifdef I_CAN_HAS_LINUX
#include <unistd.h>
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 <png.h>
#include <limits.h> // 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 <jpeglib.h>
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 <tiffio.h>
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 <ctype.h>
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 <ImfCRgbaFile.h>
// 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: