diff --git a/ChangeLog b/ChangeLog index b08790f1..67e4c795 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,7 +14,8 @@ im_pow*(), im_exp*(), im_ifthenelse(), im_blend(), im_c2amph(), im_c2rect(), im_bandmean(), im_c2real(), im_c2imag(), im_ri2c(), im_jpeg*2vips(), im_vips2jpeg*(), im_tiff2vips(), im_vips2tiff(), im_exr2vips(), - im_fits2vips(), im_vips2fits(), im_analyze2vips(), im_raw2vips() + im_fits2vips(), im_vips2fits(), im_analyze2vips(), im_raw2vips(), + im_vips2raw() redone as classes - added argument priorites to help control arg ordering - generate has a 'stop' param to signal successful early termination diff --git a/libvips/foreign/Makefile.am b/libvips/foreign/Makefile.am index 896854ea..01d61ee2 100644 --- a/libvips/foreign/Makefile.am +++ b/libvips/foreign/Makefile.am @@ -2,8 +2,9 @@ noinst_LTLIBRARIES = libforeign.la libforeign_la_SOURCES = \ rawload.c \ - vipssave.c \ + rawsave.c \ vipsload.c \ + vipssave.c \ analyzeload.c \ analyze2vips.c \ analyze2vips.h \ @@ -27,14 +28,14 @@ if HAVE_CFITSIO libforeign_la_SOURCES += \ fits.h \ fits.c \ - fitssave.c \ - fitsload.c + fitsload.c \ + fitssave.c else EXTRA_DIST += \ fits.h \ fits.c \ - fitssave.c \ - fitsload.c + fitsload.c \ + fitssave.c endif if HAVE_TIFF diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index ff2b9c6a..e17fd5ce 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1179,6 +1179,15 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_vips_get_type( void ); extern GType vips_foreign_save_vips_get_type( void ); extern GType vips_foreign_load_raw_get_type( void ); + extern GType vips_foreign_save_raw_get_type( void ); + extern GType vips_foreign_save_rawfd_get_type( void ); + + vips_foreign_load_analyze_get_type(); + vips_foreign_load_raw_get_type(); + vips_foreign_save_raw_get_type(); + vips_foreign_save_rawfd_get_type(); + vips_foreign_load_vips_get_type(); + vips_foreign_save_vips_get_type(); #ifdef HAVE_JPEG vips_foreign_load_jpeg_file_get_type(); @@ -1205,11 +1214,6 @@ vips_foreign_operation_init( void ) #ifdef HAVE_OPENEXR vips_foreign_load_openexr_get_type(); #endif /*HAVE_OPENEXR*/ - - vips_foreign_load_analyze_get_type(); - vips_foreign_load_raw_get_type(); - vips_foreign_load_vips_get_type(); - vips_foreign_save_vips_get_type(); } /** diff --git a/libvips/foreign/rawsave.c b/libvips/foreign/rawsave.c new file mode 100644 index 00000000..6379227b --- /dev/null +++ b/libvips/foreign/rawsave.c @@ -0,0 +1,307 @@ +/* save to raw + * + * Write raw image data to file. Usefull when defining new formats... + * + * Jesper Friis + * + * 10/06/08 JF + * - initial code based on im_vips2ppm() + * + * 04/07/08 JF + * - replaced FILE with plain file handlers for reducing + * confusion about binary vs. non-binary file modes. + * 4/2/10 + * - gtkdoc + * 15/12/11 + * - rework as a class + * - added save raw to filename + */ + +/* + + 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 + + */ + +/* +#define DEBUG_VERBOSE +#define DEBUG +#define VIPS_DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include +#include + +#include +#include + +typedef struct _VipsForeignSaveRaw { + VipsForeignSave parent_object; + + char *filename; + + int fd; +} VipsForeignSaveRaw; + +typedef VipsForeignSaveClass VipsForeignSaveRawClass; + +G_DEFINE_TYPE( VipsForeignSaveRaw, vips_foreign_save_raw, + VIPS_TYPE_FOREIGN_SAVE ); + +static void +vips_foreign_save_raw_dispose( GObject *gobject ) +{ + VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) gobject; + + VIPS_FREEF( vips_tracked_close, raw->fd ); + + G_OBJECT_CLASS( vips_foreign_save_raw_parent_class )-> + dispose( gobject ); +} + +static int +vips_foreign_save_raw_write( VipsRegion *region, Rect *area, void *a ) +{ + VipsForeignSave *save = (VipsForeignSave *) a; + VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) a; + int i; + + for( i = 0; i < area->height; i++ ) { + PEL *p = VIPS_REGION_ADDR( region, area->left, area->top + i ); + + if( vips__write( raw->fd, p, + VIPS_IMAGE_SIZEOF_PEL( save->in ) * area->width ) ) + return( -1 ); + } + + return( 0 ); +} + +static int +vips_foreign_save_raw_build( VipsObject *object ) +{ + VipsForeignSave *save = (VipsForeignSave *) object; + VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) object; + + if( VIPS_OBJECT_CLASS( vips_foreign_save_raw_parent_class )-> + build( object ) ) + return( -1 ); + + if( (raw->fd = vips__open_image_write( raw->filename, FALSE )) < 0 || + vips_image_pio_input( save->in ) || + vips_sink_disc( save->in, vips_foreign_save_raw_write, raw ) ) + return( -1 ); + + return( 0 ); +} + +/* Save a bit of typing. + */ +#define UC VIPS_FORMAT_UCHAR +#define C VIPS_FORMAT_CHAR +#define US VIPS_FORMAT_USHORT +#define S VIPS_FORMAT_SHORT +#define UI VIPS_FORMAT_UINT +#define I VIPS_FORMAT_INT +#define F VIPS_FORMAT_FLOAT +#define X VIPS_FORMAT_COMPLEX +#define D VIPS_FORMAT_DOUBLE +#define DX VIPS_FORMAT_DPCOMPLEX + +/* Type promotion for division. Sign and value preserving. Make sure + * these match the case statement in complexform_buffer() above. + */ +static int vips_bandfmt_raw[10] = { +/* UC C US S UI I F X D DX */ + UC, C, US, S, UI, I, F, X, D, DX +}; + +static void +vips_foreign_save_raw_class_init( VipsForeignSaveRawClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; + + gobject_class->dispose = vips_foreign_save_raw_dispose; + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "rawsave"; + object_class->description = _( "save image to raw file" ); + object_class->build = vips_foreign_save_raw_build; + + save_class->saveable = VIPS_SAVEABLE_ANY; + save_class->format_table = vips_bandfmt_raw; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to save to" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveRaw, filename ), + NULL ); +} + +static void +vips_foreign_save_raw_init( VipsForeignSaveRaw *raw ) +{ +} + +/** + * vips_rawsave: + * @in: image to save + * @filename: file to write to + * @...: %NULL-terminated list of optional named arguments + * + * Writes the pixels in @in to the file @filename with no header or other + * metadata. + * + * See also: vips_image_write_file(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_rawsave( VipsImage *in, const char *filename, ... ) +{ + va_list ap; + int result; + + va_start( ap, filename ); + result = vips_call_split( "rawsave", ap, filename ); + va_end( ap ); + + return( result ); +} + +/* And with an fd rather than a filename. + */ + +typedef struct _VipsForeignSaveRawfd { + VipsForeignSave parent_object; + + int fd; +} VipsForeignSaveRawfd; + +typedef VipsForeignSaveClass VipsForeignSaveRawfdClass; + +G_DEFINE_TYPE( VipsForeignSaveRawfd, vips_foreign_save_rawfd, + VIPS_TYPE_FOREIGN_SAVE ); + +static int +vips_foreign_save_rawfd_write( VipsRegion *region, Rect *area, void *a ) +{ + VipsForeignSave *save = (VipsForeignSave *) a; + VipsForeignSaveRawfd *rawfd = (VipsForeignSaveRawfd *) a; + int i; + + for( i = 0; i < area->height; i++ ) { + PEL *p = VIPS_REGION_ADDR( region, area->left, area->top + i ); + + if( vips__write( rawfd->fd, p, + VIPS_IMAGE_SIZEOF_PEL( save->in ) * area->width ) ) + return( -1 ); + } + + return( 0 ); +} + +static int +vips_foreign_save_rawfd_build( VipsObject *object ) +{ + VipsForeignSave *save = (VipsForeignSave *) object; + VipsForeignSaveRawfd *rawfd = (VipsForeignSaveRawfd *) object; + + if( VIPS_OBJECT_CLASS( vips_foreign_save_rawfd_parent_class )-> + build( object ) ) + return( -1 ); + + if( vips_image_pio_input( save->in ) || + vips_sink_disc( save->in, + vips_foreign_save_rawfd_write, rawfd ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_save_rawfd_class_init( VipsForeignSaveRawfdClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "rawsavefd"; + object_class->description = _( "write raw image to file descriptor" ); + object_class->build = vips_foreign_save_rawfd_build; + + save_class->saveable = VIPS_SAVEABLE_ANY; + save_class->format_table = vips_bandfmt_raw; + + VIPS_ARG_INT( class, "fd", 1, + _( "File descriptor" ), + _( "File descriptor to write to" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveRawfd, fd ), + 0, 10000, 0 ); +} + +static void +vips_foreign_save_rawfd_init( VipsForeignSaveRawfd *rawfd ) +{ +} + +/** + * vips_rawsavefd: + * @in: image to save + * @fd: file to write to + * @...: %NULL-terminated list of optional named arguments + * + * Writes the pixels in @in to the @fd with no header or other + * metadata. Handy for implementing other savers. + * + * See also: vips_rawsave(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_rawsavefd( VipsImage *in, int fd, ... ) +{ + va_list ap; + int result; + + va_start( ap, fd ); + result = vips_call_split( "rawsavefd", ap, fd ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/format/Makefile.am b/libvips/format/Makefile.am index ad5f0d81..e0d0be47 100644 --- a/libvips/format/Makefile.am +++ b/libvips/format/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libformat.la libformat_la_SOURCES = \ format.c \ + raw.c \ format_dispatch.c \ im_analyze2vips.c \ im_csv2vips.c \ @@ -10,7 +11,6 @@ libformat_la_SOURCES = \ im_magick2vips.c \ im_png2vips.c \ im_ppm2vips.c \ - im_raw2vips.c \ im_tiff2vips.c \ im_tile_cache.c \ im_vips2csv.c \ @@ -18,7 +18,6 @@ libformat_la_SOURCES = \ im_vips2png.c \ im_vips2ppm.c \ im_vips2tiff.c \ - im_vips2raw.c \ matlab.c \ fits.c \ radiance.c diff --git a/libvips/format/im_vips2jpeg.c b/libvips/format/im_vips2jpeg.c index d938e049..e34141ff 100644 --- a/libvips/format/im_vips2jpeg.c +++ b/libvips/format/im_vips2jpeg.c @@ -1,51 +1,5 @@ /* Convert 8-bit VIPS images to/from JPEG. * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 12/11/04 - * - better demand size choice for eval - * 30/6/05 JC - * - update im_error()/im_warn() - * - now loads and saves exif data - * 30/7/05 - * - now loads ICC profiles - * - now saves ICC profiles from the VIPS header - * 24/8/05 - * - jpeg load sets vips xres/yres from exif, if possible - * - jpeg save sets exif xres/yres from vips, if possible - * 29/8/05 - * - cut from old vips_jpeg.c - * 20/4/06 - * - auto convert to sRGB/mono for save - * 13/10/06 - * - add -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - - - -/* What we track during a write - */ -typedef struct { - IMAGE *in; - int fd; -} Write; - - - -static void -write_destroy( Write *write ) -{ - im_free( write ); -} - - -static Write * -write_new( IMAGE *in, int fd ) -{ - Write *write; - - if( !(write = IM_NEW( NULL, Write )) ) - return( NULL ); - - write->in = in; - write->fd = fd; - - if( !write->fd ) { - write_destroy( write ); - return( NULL ); - } - - return( write ); -} - - -static int -write_block( REGION *region, Rect *area, void *a ) -{ - Write *write = (Write *) a; - int i; - - for( i = 0; i < area->height; i++ ) { - PEL *p = (PEL *) IM_REGION_ADDR( region, area->left, area->top + i ); - if( im__write( write->fd, p, IM_IMAGE_SIZEOF_PEL(write->in)*area->width ) ) - return( -1 ); - } - - return( 0 ); -} - - -/** - * im_vips2raw: - * @in: image to save - * @fd: file descriptor to write to - * - * Writes the pixels in @in to the file descriptor. It's handy for writing - * writers for other formats. - * - * See also: #VipsFormat, im_raw2vips(). - * - * Returns: 0 on success, -1 on error. - */ -int -im_vips2raw( IMAGE *in, int fd ) -{ - Write *write; - - if( im_pincheck( in ) || !(write = write_new( in, fd )) ) - return( -1 ); - - if( vips_sink_disc( in, write_block, write ) ) { - write_destroy( write ); - return( -1 ); - } - - write_destroy( write ); - return( 0 ); -} - diff --git a/libvips/format/im_raw2vips.c b/libvips/format/raw.c similarity index 61% rename from libvips/format/im_raw2vips.c rename to libvips/format/raw.c index a5e876cd..bb3bc5bb 100644 --- a/libvips/format/im_raw2vips.c +++ b/libvips/format/raw.c @@ -1,8 +1,7 @@ /* Read raw image. Just a wrapper over im_binfile(). * - * 3/8/05 - * 4/2/10 - * - gtkdoc + * 15/12/11 + * - just a compat stub now */ /* @@ -42,40 +41,27 @@ #include -/** - * im_raw2vips: - * @filename: file to read - * @out: image to write to - * @width: image width in pixels - * @height: image height in pixels - * @bpp: bytes per pixel - * @offset: skip this many bytes at the start of the file - * - * This operation mmaps the file, setting @out so that access to that - * image will read from the file. - * - * Use functions like im_copy_morph() to set the pixel type, byte ordering - * and so on. - * - * See also: #VipsFormat, im_vips2raw(). - * - * Returns: 0 on success, -1 on error. - */ int im_raw2vips( const char *filename, IMAGE *out, int width, int height, int bpp, int offset ) { - IMAGE *t; + VipsImage *t; - if( !(t = im_binfile( filename, width, height, bpp, offset )) ) + if( vips_rawload( filename, &t, width, height, bpp, + "offset", offset, + NULL ) ) return( -1 ); - if( im_add_close_callback( out, - (im_callback_fn) im_close, t, NULL ) ) { - im_close( t ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); return( -1 ); } - if( im_copy( t, out ) ) - return( -1 ); + g_object_unref( t ); return( 0 ); } + +int +im_vips2raw( IMAGE *in, int fd ) +{ + return( vips_rawsavefd( in, fd, NULL ) ); +} diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index a8727b10..ae8e3eac 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -334,6 +334,10 @@ int vips_analyzeload( const char *filename, VipsImage **out, ... ) int vips_rawload( const char *filename, VipsImage **out, int width, int height, int bands, ... ) __attribute__((sentinel)); +int vips_rawsave( VipsImage *in, const char *filename, ... ) + __attribute__((sentinel)); +int vips_rawsavefd( VipsImage *in, int fd, ... ) + __attribute__((sentinel)); #ifdef __cplusplus } diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 31071d5a..066d1e8d 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -87,6 +87,7 @@ typedef int (*im__fftproc_fn)( VipsImage *, VipsImage *, VipsImage * ); /* iofuncs */ int vips__open_image_read( const char *filename ); +int vips__open_image_write( const char *filename, gboolean temp ); int vips_image_open_input( VipsImage *image ); int vips_image_open_output( VipsImage *image ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 8afc4702..6f275846 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -870,6 +870,12 @@ vips_object_set_property( GObject *gobject, *member = g_value_get_int( value ); } + else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) { + guint64 *member = &G_STRUCT_MEMBER( guint64, object, + argument_class->offset ); + + *member = g_value_get_uint64( value ); + } else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { gboolean *member = &G_STRUCT_MEMBER( gboolean, object, argument_class->offset ); @@ -968,6 +974,12 @@ vips_object_get_property( GObject *gobject, g_value_set_int( value, *member ); } + else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) { + guint64 *member = &G_STRUCT_MEMBER( guint64, object, + argument_class->offset ); + + g_value_set_uint64( value, *member ); + } else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { gboolean *member = &G_STRUCT_MEMBER( gboolean, object, argument_class->offset ); @@ -1344,6 +1356,10 @@ vips_object_set_argument_from_string( VipsObject *object, g_value_init( &gvalue, G_TYPE_INT ); g_value_set_int( &gvalue, atoi( value ) ); } + else if( G_IS_PARAM_SPEC_UINT64( pspec ) ) { + g_value_init( &gvalue, G_TYPE_UINT64 ); + g_value_set_uint64( &gvalue, atoll( value ) ); + } else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) { g_value_init( &gvalue, G_TYPE_DOUBLE ); g_value_set_double( &gvalue, atof( value ) ); diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index fccf098f..cee70b8a 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -147,6 +147,35 @@ vips__open_image_read( const char *filename ) return( fd ); } +/* Open for write for image files. + */ +int +vips__open_image_write( const char *filename, gboolean temp ) +{ + int flags; + int fd; + + flags = MODE_WRITE; + +#ifdef _O_TEMPORARY + /* On Windows, setting O_TEMP gets the file automatically + * deleted on process exit, even if the processes crashes. See + * vips_image_rewind() for what we do to help on *nix. + */ + if( temp ) + flags |= _O_TEMPORARY; +#endif /*_O_TEMPORARY*/ + + if( (fd = vips_tracked_open( filename, flags, 0666 )) < 0 ) { + vips_error_system( errno, "VipsImage", + _( "unable to write to \"%s\"" ), + filename ); + return( -1 ); + } + + return( fd ); +} + /* Predict the size of the header plus pixel data. Don't use off_t, * it's sometimes only 32 bits (eg. on many windows build environments) and we * want to always be 64 bit. @@ -956,26 +985,10 @@ vips_image_open_output( VipsImage *image ) * writing a VIPS image anyway. */ unsigned char header[VIPS_SIZEOF_HEADER]; - int flags; - flags = MODE_WRITE; - -#ifdef _O_TEMPORARY - /* On Windows, setting O_TEMP gets the file automatically - * deleted on process exit, even if the processes crashes. See - * vips_image_rewind() for what we do to help on *nix. - */ - if( image->delete_on_close ) - flags |= _O_TEMPORARY; -#endif /*_O_TEMPORARY*/ - - if( (image->fd = vips_tracked_open( image->filename, - flags, 0666 )) < 0 ) { - vips_error_system( errno, "VipsImage", - _( "unable to write to \"%s\"" ), - image->filename ); + if( (image->fd = vips__open_image_write( image->filename, + image->delete_on_close )) < 0 ) return( -1 ); - } /* We always write in native mode, so we must overwrite the * magic we read from the file originally.