/* Read matlab save files with libmatio */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Remaining issues: + it transposes images, I think, since Matlab seems to use column-major order + will colour images work? no idea, needs testing + it will not do complex images + it will not handle sparse matricies + it loads the first variable in the file with between 1 and 3 dimensions, is this sensible behaviour? + load only, no save + could use much less memory --- we use Mat_VarReadDataAll() to read the whole variable into mem, then copy to a vips buffer, yuk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_MATIO #include #include #include #include #include #include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ /* What we track during a Mat-file read. */ typedef struct { char *filename; IMAGE *out; mat_t *mat; matvar_t *var; } Read; static void read_destroy( Read *read ) { IM_FREE( read->filename ); IM_FREEF( Mat_VarFree, read->var ); IM_FREEF( Mat_Close, read->mat ); im_free( read ); } static Read * read_new( const char *filename, IMAGE *out ) { Read *read; if( !(read = IM_NEW( NULL, Read )) ) return( NULL ); read->filename = im_strdup( NULL, filename ); read->out = out; read->mat = NULL; read->var = NULL; if( !(read->mat = Mat_Open( filename, MAT_ACC_RDONLY )) ) { im_error( "mat2vips", _( "unable to open \"%s\"" ), filename ); read_destroy( read ); return( NULL ); } for(;;) { if( !(read->var = Mat_VarReadNextInfo( read->mat )) ) { im_error( "mat2vips", _( "no matrix variables in \"%s\"" ), filename ); read_destroy( read ); return( NULL ); } #ifdef DEBUG printf( "mat2vips: seen:\n" ); printf( "var->name == %s\n", read->var->name ); printf( "var->class_type == %d\n", read->var->class_type ); printf( "var->rank == %d\n", read->var->rank ); #endif /*DEBUG*/ /* Vector to colour image is OK for us. */ if( read->var->rank >= 1 && read->var->rank <= 3 ) break; IM_FREEF( Mat_VarFree, read->var ); } return( read ); } /* Matlab classes -> VIPS band formats. */ static int mat2vips_formats[][2] = { { MAT_C_UINT8, IM_BANDFMT_UCHAR }, { MAT_C_INT8, IM_BANDFMT_CHAR }, { MAT_C_UINT16, IM_BANDFMT_USHORT }, { MAT_C_INT16, IM_BANDFMT_SHORT }, { MAT_C_UINT32, IM_BANDFMT_UINT }, { MAT_C_INT32, IM_BANDFMT_INT }, { MAT_C_SINGLE, IM_BANDFMT_FLOAT }, { MAT_C_DOUBLE, IM_BANDFMT_DOUBLE } }; static int mat2vips_get_header( matvar_t *var, IMAGE *im ) { int width, height, bands, format, type; int i; width = 1; height = 1; bands = 1; switch( var->rank ) { case 3: bands = var->dims[2]; case 2: height = var->dims[1]; case 1: width = var->dims[0]; break; default: im_error( "mat2vips", _( "unsupported bands %d\n" ), var->rank ); return( -1 ); } if( bands > 1 ) type = IM_TYPE_MULTIBAND; else type = IM_TYPE_B_W; for( i = 0; i < IM_NUMBER( mat2vips_formats ); i++ ) if( mat2vips_formats[i][0] == var->class_type ) break; if( i == IM_NUMBER( mat2vips_formats ) ) { im_error( "mat2vips", _( "unsupported class type %d\n" ), var->class_type ); return( -1 ); } format = mat2vips_formats[i][1]; im_initdesc( im, width, height, bands, im_bits_of_fmt( format ), format, IM_CODING_NONE, type, 1.0, 1.0, 0, 0 ); return( 0 ); } static int mat2vips_header( const char *filename, IMAGE *out ) { Read *read; #ifdef DEBUG printf( "mat2vips_header: reading \"%s\"\n", filename ); #endif /*DEBUG*/ if( !(read = read_new( filename, out )) ) return( -1 ); if( mat2vips_get_header( read->var, read->out ) ) { read_destroy( read ); return( -1 ); } read_destroy( read ); return( 0 ); } static int mat2vips_get_data( mat_t *mat, matvar_t *var, IMAGE *im ) { int y; if( Mat_VarReadDataAll( mat, var ) ) { im_error( "mat2vips", "%s", _( "Mat_VarReadDataAll failed" ) ); return( -1 ); } if( im_outcheck( im ) || im_setupout( im ) ) return( -1 ); for( y = 0; y < im->Ysize; y++ ) if( im_writeline( y, im, var->data + y * IM_IMAGE_SIZEOF_LINE( im ) ) ) return( -1 ); return( 0 ); } static int mat2vips( const char *filename, IMAGE *out ) { Read *read; #ifdef DEBUG printf( "mat2vips: reading \"%s\"\n", filename ); #endif /*DEBUG*/ if( !(read = read_new( filename, out )) ) return( -1 ); if( mat2vips_get_header( read->var, read->out ) || mat2vips_get_data( read->mat, read->var, read->out ) ) { read_destroy( read ); return( -1 ); } read_destroy( read ); return( 0 ); } static int ismat( const char *filename ) { mat_t *mat; if( !(mat = Mat_Open( filename, MAT_ACC_RDONLY )) ) return( 0 ); Mat_Close( mat ); return( 1 ); } static const char *mat_suffs[] = { ".mat", NULL }; /* mat format adds no new members. */ typedef VipsFormat VipsFormatMat; typedef VipsFormatClass VipsFormatMatClass; static void vips_format_mat_class_init( VipsFormatMatClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "mat"; object_class->description = _( "Matlab" ); format_class->is_a = ismat; format_class->header = mat2vips_header; format_class->load = mat2vips; format_class->save = NULL; format_class->suffs = mat_suffs; } static void vips_format_mat_init( VipsFormatMat *object ) { } G_DEFINE_TYPE( VipsFormatMat, vips_format_mat, VIPS_TYPE_FORMAT ); #endif /*HAVE_MATIO*/