Merge remote-tracking branch 'origin/format-hacking' into format-hacking

This commit is contained in:
John Cupitt 2011-11-28 11:18:10 +00:00
commit c4c1dad8a6
13 changed files with 371 additions and 401 deletions

21
TODO
View File

@ -1,25 +1,24 @@
- need vips load/save class, so we can detect vips files for native read /
write
- do jpegbuffer load and save
jpeg load needs to set suffs
need a jpegsave base class, with subclasses for save to file and save to
buffer
get image.c using the new system for vips_image_new_from_file()
CLI stuff image->new_from_string() needs to use new system too, chcek this
savers need it too ... delayed save system and also
image->output_to_arg()
same for jpegload
make compat wrappers for old im_jpeg2vips() and im_vips2jpeg()
move format/* to deprecated
make sure we are using the operation cache for jpegload
have something to print the cache before we flush it?
try tiff load
move format/* to deprecated
- return missing just after read_xmp() in master?

View File

@ -876,6 +876,10 @@ input_interpolate_init( im_object *obj, char *str )
interpolate_class = vips_class_find( "VipsInterpolate", "interpolate" );
if( !(object = vips_object_new_from_string( interpolate_class, str )) )
return( -1 );
if( vips_object_build( object ) ) {
g_object_unref( object );
return( -1 );
}
*obj = object;
return( 0 );

View File

@ -234,7 +234,7 @@ vips_file_print_class( VipsObjectClass *object_class, VipsBuf *buf )
VIPS_OBJECT_CLASS( vips_file_parent_class )->
print_class( object_class, buf );
vips_buf_appends( buf, ", " );
vips_buf_appends( buf, " " );
if( class->suffs ) {
vips_buf_appends( buf, "(" );
@ -243,7 +243,7 @@ vips_file_print_class( VipsObjectClass *object_class, VipsBuf *buf )
if( p[1] )
vips_buf_appends( buf, ", " );
}
vips_buf_appends( buf, ") " );
vips_buf_appends( buf, "), " );
}
vips_buf_appendf( buf, "priority=%d", class->priority );
@ -364,6 +364,77 @@ vips_file_load_print_class( VipsObjectClass *object_class, VipsBuf *buf )
vips_buf_appends( buf, ", load" );
}
/* Can this VipsFile open this file?
*/
static void *
vips_file_load_new_from_file_sub( VipsFileLoadClass *load_class,
const char *filename )
{
VipsFileClass *class = VIPS_FILE_CLASS( load_class );
if( load_class->is_a ) {
if( load_class->is_a( filename ) )
return( load_class );
}
else if( vips_filename_suffix_match( filename, class->suffs ) )
return( load_class );
return( NULL );
}
/**
* vips_file_find_load:
* @filename: file to find a file for
*
* Searches for an operation you could use to load a file.
*
* See also: vips_file_read().
*
* Returns: the nmae of an operation on success, %NULL on error
*/
const char *
vips_file_find_load( const char *filename )
{
VipsFileLoadClass *load_class;
if( !vips_existsf( "%s", filename ) ) {
vips_error( "VipsFileLoad",
_( "file \"%s\" not found" ), filename );
return( NULL );
}
if( !(load_class = (VipsFileLoadClass *) vips_file_map(
"VipsFileLoad",
(VipsSListMap2Fn) vips_file_load_new_from_file_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsFileLoad",
_( "file \"%s\" not a known file" ), filename );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( load_class ) );
}
static VipsObject *
vips_file_load_new_from_string( const char *string )
{
const char *file_op;
GType type;
VipsFileLoad *load;
if( !(file_op = vips_file_find_load( string )) )
return( NULL );
type = g_type_from_name( file_op );
g_assert( type );
load = VIPS_FILE_LOAD( g_object_new( type, NULL ) );
g_object_set( load,
"filename", string,
NULL );
return( VIPS_OBJECT( load ) );
}
static size_t
vips_get_disc_threshold( void )
{
@ -414,7 +485,7 @@ vips_file_load_start_cb( VipsImage *out, void *a, void *dummy )
*/
if( load->disc &&
disc_threshold &&
(load->flags & VIPS_FORMAT_PARTIAL) &&
(load->flags & VIPS_FILE_PARTIAL) &&
image_size > disc_threshold )
if( !(load->real = vips_image_new_disc_temp( "%s.v" )) )
return( NULL );
@ -476,24 +547,34 @@ vips_file_load_build( VipsObject *object )
build( object ) )
return( -1 );
/* Read header fields to init the return image. THINSTRIP since this is
* probably a disc file. We can't tell yet whether we will be opening
* to memory, sadly, so we can't suggest ANY.
/* Read the header into @out.
*/
if( class->header &&
class->header( load ) )
return( -1 );
vips_demand_hint( load->out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Then 'start' creates the real image and 'gen' fetches pixels for
* 'out' from real on demand.
/* If there's no ->load() method then the header read has done
* everything. Otherwise, it's just set fields and we now must
* convert pixels on demand.
*/
if( vips_image_generate( load->out,
vips_file_load_start_cb,
vips_file_load_generate_cb,
vips_stop_one,
load, NULL ) )
return( -1 );
if( class->load ) {
/* THINSTRIP since this is probably a disc file.
* We can't tell yet whether we will be opening
* to memory, sadly, so we can't suggest ANY.
*/
vips_demand_hint( load->out,
VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Then 'start' creates the real image and 'gen' fetches
* pixels for @out from @real on demand.
*/
if( vips_image_generate( load->out,
vips_file_load_start_cb,
vips_file_load_generate_cb,
vips_stop_one,
load, NULL ) )
return( -1 );
}
return( 0 );
}
@ -508,10 +589,11 @@ vips_file_load_class_init( VipsFileLoadClass *class )
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->build = vips_file_load_build;
object_class->print_class = vips_file_load_print_class;
object_class->new_from_string = vips_file_load_new_from_string;
object_class->nickname = "fileload";
object_class->description = _( "file loaders" );
object_class->print_class = vips_file_load_print_class;
object_class->build = vips_file_load_build;
VIPS_ARG_IMAGE( class, "out", 2,
_( "Output" ),
@ -541,57 +623,6 @@ vips_file_load_init( VipsFileLoad *load )
load->disc = TRUE;
}
/* Can this file open this file?
*/
static void *
vips_file_load_new_from_file_sub( VipsFileLoadClass *load_class,
const char *filename )
{
VipsFileClass *class = VIPS_FILE_CLASS( load_class );
if( load_class->is_a ) {
if( load_class->is_a( filename ) )
return( load_class );
}
else if( vips_filename_suffix_match( filename, class->suffs ) )
return( load_class );
return( NULL );
}
/**
* vips_file_find_load:
* @filename: file to find a file for
*
* Searches for an operation you could use to load a file.
*
* See also: vips_file_read().
*
* Returns: the nmae of an operation on success, %NULL on error
*/
const char *
vips_file_find_load( const char *filename )
{
VipsFileLoadClass *load_class;
if( !vips_existsf( "%s", filename ) ) {
vips_error( "VipsFileLoad",
_( "file \"%s\" not found" ), filename );
return( NULL );
}
if( !(load_class = (VipsFileLoadClass *) vips_file_map(
"VipsFileLoad",
(VipsSListMap2Fn) vips_file_load_new_from_file_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsFileLoad",
_( "file \"%s\" not a known file" ), filename );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( load_class ) );
}
/* Abstract base class for image savers.
*/
@ -619,6 +650,69 @@ vips_file_save_print_class( VipsObjectClass *object_class, VipsBuf *buf )
VIPS_ENUM_NICK( VIPS_TYPE_SAVEABLE, class->saveable ) );
}
/* Can we write this filename with this file?
*/
static void *
vips_file_save_new_from_filename_sub( VipsFileSaveClass *save_class,
const char *filename )
{
VipsFileClass *class = VIPS_FILE_CLASS( save_class );
if( vips_filename_suffix_match( filename, class->suffs ) )
return( save_class );
return( NULL );
}
/**
* vips_file_find_save:
* @filename: name to find a file for
*
* Searches for an operation you could use to save a file.
*
* See also: vips_file_write().
*
* Returns: the name of an operation on success, %NULL on error
*/
const char *
vips_file_find_save( const char *filename )
{
VipsFileSaveClass *save_class;
if( !(save_class = (VipsFileSaveClass *) vips_file_map(
"VipsFileSave",
(VipsSListMap2Fn) vips_file_save_new_from_filename_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsFileSave",
_( "\"%s\" is not a supported image file." ),
filename );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( save_class ) );
}
static VipsObject *
vips_file_save_new_from_string( const char *string )
{
const char *file_op;
GType type;
VipsFileSave *save;
if( !(file_op = vips_file_find_save( string )) )
return( NULL );
type = g_type_from_name( file_op );
g_assert( type );
save = VIPS_FILE_SAVE( g_object_new( type, NULL ) );
g_object_set( save,
"filename", string,
NULL );
return( VIPS_OBJECT( save ) );
}
/* Generate the saveable image.
*/
static int
@ -843,10 +937,11 @@ vips_file_save_class_init( VipsFileSaveClass *class )
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->build = vips_file_save_build;
object_class->print_class = vips_file_save_print_class;
object_class->new_from_string = vips_file_save_new_from_string;
object_class->nickname = "filesave";
object_class->description = _( "file savers" );
object_class->print_class = vips_file_save_print_class;
object_class->build = vips_file_save_build;
VIPS_ARG_IMAGE( class, "in", 0,
_( "Input" ),
@ -860,49 +955,6 @@ vips_file_save_init( VipsFileSave *object )
{
}
/* Can we write this filename with this file?
*/
static void *
vips_file_save_new_from_filename_sub( VipsFileSaveClass *save_class,
const char *filename )
{
VipsFileClass *class = VIPS_FILE_CLASS( save_class );
if( vips_filename_suffix_match( filename, class->suffs ) )
return( save_class );
return( NULL );
}
/**
* vips_file_find_save:
* @filename: name to find a file for
*
* Searches for an operation you could use to save a file.
*
* See also: vips_file_write().
*
* Returns: the name of an operation on success, %NULL on error
*/
const char *
vips_file_find_save( const char *filename )
{
VipsFileSaveClass *save_class;
if( !(save_class = (VipsFileSaveClass *) vips_file_map(
"VipsFileSave",
(VipsSListMap2Fn) vips_file_save_new_from_filename_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsFileSave",
_( "\"%s\" is not a supported image file." ),
filename );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( save_class ) );
}
/**
* vips_file_read:
* @filename: file to load

View File

@ -901,11 +901,14 @@ vips_file_load_jpeg_load( VipsFileLoad *load )
return( result );
}
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
static void
vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFileClass *file_class = (VipsFileClass *) class;
VipsFileLoadClass *load_class = (VipsFileLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -915,6 +918,8 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
object_class->description = _( "load jpeg from file" );
object_class->build = vips_file_load_jpeg_build;
file_class->suffs = jpeg_suffs;
load_class->is_a = vips_file_load_jpeg_is_a;
load_class->header = vips_file_load_jpeg_header;
load_class->load = vips_file_load_jpeg_load;
@ -932,7 +937,6 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsFileLoadJpeg, fail ),
FALSE );
}
static void

View File

@ -852,7 +852,6 @@ vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsFileSaveJpeg, profile ),
NULL );
}
static void

View File

@ -42,38 +42,31 @@
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
typedef VipsFileLoad VipsFileLoadVips;
typedef VipsFileLoadClass VipsFileLoadVipsClass;
G_DEFINE_TYPE( VipsFileLoadVips, vips_file_load_vips, VIPS_TYPE_FILE_SAVE );
G_DEFINE_TYPE( VipsFileLoadVips, vips_file_load_vips, VIPS_TYPE_FILE_LOAD );
static int
vips_file_load_vips_build( VipsObject *object )
static gboolean
vips_file_load_vips_is_a( const char *filename )
{
if( VIPS_OBJECT_CLASS( vips_file_load_vips_parent_class )->
build( object ) )
return( -1 );
return( 0 );
return( vips__file_magic( filename ) );
}
static int
vips_file_load_vips_is_a( const char *filename )
vips_file_load_vips_get_flags( VipsFileLoad *load )
{
unsigned char buf[4];
VipsFile *file = VIPS_FILE( load );
if( vips__get_bytes( filename, buf, 4 ) ) {
if( buf[0] == 0x08 && buf[1] == 0xf2 &&
buf[2] == 0xa6 && buf[3] == 0xb6 )
/* SPARC-order VIPS image.
*/
return( 1 );
else if( buf[3] == 0x08 && buf[2] == 0xf2 &&
buf[1] == 0xa6 && buf[0] == 0xb6 )
/* INTEL-order VIPS image.
*/
return( 1 );
load->flags = VIPS_FILE_PARTIAL;
if( vips__file_magic( file->filename ) == VIPS_MAGIC_INTEL ) {
printf( "vips_file_load_vips_get_flags: "
"%s is intel, setting bigendian\n",
file->filename );
load->flags |= VIPS_FILE_BIGENDIAN;
}
return( 0 );
@ -82,33 +75,45 @@ vips_file_load_vips_is_a( const char *filename )
static int
vips_file_load_vips_header( VipsFileLoad *load )
{
}
VipsFile *file = VIPS_FILE( load );
VipsImage *out;
VipsImage *out2;
static int
vips_file_load_vips_load( VipsFileLoad *load )
{
if( !(out2 = vips_image_new_from_file( file->filename )) )
return( -1 );
/* Remove the @out that's there now.
*/
g_object_get( load, "out", &out, NULL );
g_object_set( load, "out", out2, NULL );
/* Unref after we install the new out to make sure load isn't
* disposed.
*/
g_object_unref( out );
g_object_unref( out );
return( 0 );
}
static const char *vips_suffs[] = { ".v", NULL };
static void
vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
vips_file_load_vips_class_init( VipsFileLoadVipsClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFileClass *file_class = (VipsLoadClass *) class;
VipsFileClass *file_class = (VipsFileClass *) class;
VipsFileLoadClass *load_class = (VipsFileLoadClass *) class;
object_class->nickname = "vipsload";
object_class->description = _( "load vips from file" );
object_class->build = vips_file_load_vips_build;
file_class->suffs = vips_suffs;
load_class->is_a = vips_file_load_vips_is_a;
load_class->get_flags = vips_file_load_vips_get_flags;
load_class->header = vips_file_load_vips_header;
load_class->load = vips_file_load_vips_load;
load_class->load = NULL;
}
static void

View File

@ -61,7 +61,7 @@ vips_file_save_vips_build( VipsObject *object )
build( object ) )
return( -1 );
if( vips_image_write_to_file( save->in, file->filename ) )
if( vips_image_write_to_file( save->ready, file->filename ) )
return( -1 );
return( 0 );
@ -105,7 +105,6 @@ vips_file_save_vips_class_init( VipsFileSaveVipsClass *class )
save_class->saveable = VIPS_SAVEABLE_ANY;
save_class->format_table = vips_bandfmt_vips;
}
static void

View File

@ -104,7 +104,7 @@ void *vips_file_map( const char *base, VipsSListMap2Fn fn, void *a, void *b );
/* Image file properties.
*/
typedef enum {
VIPS_FILE_NONE = 0, /* No flags set */
VIPS_FILE_NONE = 0, /* No flags set */
VIPS_FILE_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */
VIPS_FILE_BIGENDIAN = 2 /* Most-significant byte first */
} VipsFileFlags;
@ -145,11 +145,13 @@ typedef struct _VipsFileLoadClass {
*/
int (*get_flags)( VipsFileLoad * );
/* Read the header into @out.
/* Set the header fields in @out from @filename. If you can read the
* whole image as well with no performance cost (as with vipsload),
* leave ->load() NULL.
*/
int (*header)( VipsFileLoad * );
/* Read the whole image into real. It gets copied to out later.
/* Read the whole image into @real. It gets copied to @out later.
*/
int (*load)( VipsFileLoad * );

View File

@ -107,6 +107,7 @@ void vips__read_4byte( int msb_first, unsigned char *to, unsigned char **from );
void vips__read_2byte( int msb_first, unsigned char *to, unsigned char **from );
void vips__write_4byte( unsigned char **to, unsigned char *from );
void vips__write_2byte( unsigned char **to, unsigned char *from );
guint32 vips__file_magic( const char *filename );
int vips__has_extension_block( VipsImage *im );
void *vips__read_extension_block( VipsImage *im, int *size );
int vips__write_extension_block( VipsImage *im, void *buf, int size );

View File

@ -682,7 +682,7 @@ vips_image_generate( VipsImage *image,
*/
vips_error( "VipsImage",
_( "unable to output to a %s image" ),
VIPS_ENUM_NICK( VIPS_TYPE_DEMAND_STYLE,
VIPS_ENUM_NICK( VIPS_TYPE_IMAGE_TYPE,
image->dtype ) );
return( -1 );
}

View File

@ -460,220 +460,30 @@ vips_image_rewind( VipsObject *object )
image->mode = mode;
}
static gboolean
vips_format_is_vips( VipsFormatClass *format )
{
return( strcmp( VIPS_OBJECT_CLASS( format )->nickname, "vips" ) == 0 );
}
/* Lazy open.
*/
/* What we track during a delayed open.
*/
typedef struct {
VipsImage *image;
VipsFormatClass *format;/* Read in pixels with this */
char *filename; /* Get pixels from here */
gboolean disc; /* Read via disc requested */
VipsImage *real; /* The real decompressed image */
} Lazy;
static void
lazy_free_cb( VipsImage *image, Lazy *lazy )
{
VIPS_DEBUG_MSG( "lazy_free: %p \"%s\"\n", lazy, lazy->filename );
g_free( lazy->filename );
VIPS_UNREF( lazy->real );
g_free( lazy );
}
static Lazy *
lazy_new( VipsImage *image,
VipsFormatClass *format, const char *filename, gboolean disc )
{
Lazy *lazy;
lazy = g_new( Lazy, 1 );
VIPS_DEBUG_MSG( "lazy_new: %p \"%s\"\n", lazy, filename );
lazy->image = image;
lazy->format = format;
lazy->filename = g_strdup( filename );
lazy->disc = disc;
lazy->real = NULL;
g_signal_connect( image, "close", G_CALLBACK( lazy_free_cb ), lazy );
return( lazy );
}
static size_t
disc_threshold( void )
{
static gboolean done = FALSE;
static size_t threshold;
if( !done ) {
const char *env;
done = TRUE;
/* 100mb default.
*/
threshold = 100 * 1024 * 1024;
if( (env = g_getenv( "IM_DISC_THRESHOLD" )) )
threshold = vips__parse_size( env );
if( vips__disc_threshold )
threshold = vips__parse_size( vips__disc_threshold );
VIPS_DEBUG_MSG( "disc_threshold: %zd bytes\n", threshold );
}
return( threshold );
}
/* Make the real underlying image: either a direct disc file, or a temp file
* somewhere.
*/
static VipsImage *
lazy_real_image( Lazy *lazy )
{
VipsImage *real;
/* We open via disc if:
* - 'disc' is set
* - disc_threshold() has not been set to zero
* - the format does not support lazy read
* - the uncompressed image will be larger than disc_threshold()
*/
real = NULL;
if( lazy->disc &&
disc_threshold() &&
!(vips_format_get_flags( lazy->format, lazy->filename ) &
VIPS_FORMAT_PARTIAL) &&
VIPS_IMAGE_SIZEOF_IMAGE( lazy->image ) > disc_threshold() )
if( !(real = vips_image_new_disc_temp( "%s.v" )) )
return( NULL );
/* Otherwise, fall back to a "p".
*/
if( !real &&
!(real = vips_image_new()) )
return( NULL );
return( real );
}
/* Our start function ... do the lazy open, if necessary, and return a region
* on the new image.
*/
static void *
open_lazy_start( VipsImage *out, void *a, void *dummy )
{
Lazy *lazy = (Lazy *) a;
if( !lazy->real ) {
if( !(lazy->real = lazy_real_image( lazy )) ||
lazy->format->load( lazy->filename, lazy->real ) ||
vips_image_pio_input( lazy->real ) ) {
VIPS_UNREF( lazy->real );
return( NULL );
}
}
return( vips_region_new( lazy->real ) );
}
/* Just copy.
*/
static int
open_lazy_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRegion *ir = (VipsRegion *) seq;
VipsRect *r = &or->valid;
/* Ask for input we need.
*/
if( vips_region_prepare( ir, r ) )
return( -1 );
/* Attach output region to that.
*/
if( vips_region_region( or, ir, r, r->left, r->top ) )
return( -1 );
return( 0 );
}
/* Lazy open ... init the header with the first OpenLazyFn, delay actually
* decoding pixels with the second OpenLazyFn until the first generate().
*/
static int
vips_image_open_lazy( VipsImage *image,
VipsFormatClass *format, const char *filename, gboolean disc )
{
Lazy *lazy;
lazy = lazy_new( image, format, filename, disc );
/* Read header fields to init the return image. THINSTRIP since this is
* probably a disc file. We can't tell yet whether we will be opening
* to memory, sadly, so we can't suggest ANY.
*/
if( format->header( filename, image ) )
return( -1 );
vips_demand_hint( image, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
/* Then 'start' creates the real image and 'gen' paints 'out' with
* pixels from the real image on demand.
*/
if( vips_image_generate( image,
open_lazy_start, open_lazy_generate, vips_stop_one,
lazy, NULL ) )
return( -1 );
return( 0 );
}
/* Lazy save.
/* Delayed save.
*/
/* If we write to (eg.) TIFF, actually do the write
* to a "p" and on "written" do im_vips2tiff() or whatever. Track save
* parameters here.
* to a "p" and on "written" do im_vips2tiff() or whatever.
*/
typedef struct {
int (*save_fn)(); /* Save function */
char *filename; /* Save args */
} SaveBlock;
/* From "written" callback: invoke a delayed save.
*/
static void
vips_image_save_cb( VipsImage *image, int *result, SaveBlock *sb )
vips_image_save_cb( VipsImage *image, int *result, char *filename )
{
if( sb->save_fn( image, sb->filename ) )
if( vips_file_write( image, filename, NULL ) )
*result = -1;
g_free( sb->filename );
g_free( sb );
g_free( filename );
}
static void
vips_attach_save( VipsImage *image, int (*save_fn)(), const char *filename )
vips_attach_save( VipsImage *image, const char *filename )
{
SaveBlock *sb;
sb = g_new( SaveBlock, 1 );
sb->save_fn = save_fn;
sb->filename = g_strdup( filename );
g_signal_connect( image, "written",
G_CALLBACK( vips_image_save_cb ), sb );
G_CALLBACK( vips_image_save_cb ),
g_strdup( filename ) );
}
/* Progress feedback.
@ -756,7 +566,7 @@ vips_image_build( VipsObject *object )
const char *filename = image->filename;
const char *mode = image->mode;
const char *file_op;
guint32 magic;
size_t sizeof_image;
VIPS_DEBUG_MSG( "vips_image_build: %p\n", image );
@ -767,62 +577,84 @@ vips_image_build( VipsObject *object )
/* Parse the mode string.
*/
switch( mode[0] ) {
case 'r':
if( !(file_op = vips_file_find_load( filename )) )
case 'v':
/* Used by 'r' for native open of vips, see below.
*/
if( vips_image_open_input( image ) )
return( -1 );
if( vips_format_is_vips( format ) ) {
break;
case 'r':
if( (magic = vips__file_magic( filename )) ) {
/* We may need to byteswap.
*/
VipsFormatFlags flags =
vips_format_get_flags( format, filename );
gboolean native = (flags & VIPS_FORMAT_BIGENDIAN) ==
vips_amiMSBfirst();
guint32 us = vips_amiMSBfirst() ?
VIPS_MAGIC_INTEL : VIPS_MAGIC_SPARC;
if( native ) {
if( magic == us ) {
/* Native open.
*/
if( vips_image_open_input( image ) )
return( -1 );
if( mode[1] == 'w' )
image->dtype = VIPS_IMAGE_MMAPINRW;
}
else {
VipsImage *x;
VipsImage *t;
VipsImage *t2;
if( !(x = vips_image_new()) )
/* Open the image in t, then byteswap to this
* image.
*/
if( !(t = vips_image_new_mode( filename,
"v" )) )
return( -1 );
vips_object_local( image, x );
if( vips_image_open_input( x ) )
if( vips_copy( t, &t2,
"swap", TRUE,
NULL ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
image->dtype = VIPS_IMAGE_PARTIAL;
if( im_copy_swap( x, image ) )
if( vips_image_write( t2, image ) ) {
g_object_unref( t2 );
return( -1 );
}
g_object_unref( t2 );
}
}
else {
/* Make this a partial, generate into it from the
* converter.
*/
image->dtype = VIPS_IMAGE_PARTIAL;
VipsImage *t;
if( vips_image_open_lazy( image, format,
filename, mode[1] == 'd' ) )
if( vips_file_read( filename, &t, NULL ) )
return( -1 );
image->dtype = VIPS_IMAGE_PARTIAL;
if( vips_image_write( t, image ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
}
break;
case 'w':
if( !(format = vips_format_for_name( filename )) )
{
const char *file_op;
if( !(file_op = vips_file_find_save( filename )) )
return( -1 );
if( vips_format_is_vips( format ) )
if( strcmp( file_op, "VipsFileSaveVips" ) == 0 )
image->dtype = VIPS_IMAGE_OPENOUT;
else {
image->dtype = VIPS_IMAGE_PARTIAL;
vips_attach_save( image,
format->save, filename );
vips_attach_save( image, filename );
}
}
break;
case 't':
@ -1964,7 +1796,7 @@ vips_image_write_line( VipsImage *image, int ypos, PEL *linebuffer )
default:
vips_error( "VipsImage",
_( "unable to output to a %s image" ),
VIPS_ENUM_STRING( VIPS_TYPE_DEMAND_STYLE,
VIPS_ENUM_STRING( VIPS_TYPE_IMAGE_TYPE,
image->dtype ) );
return( -1 );
}

View File

@ -1231,19 +1231,61 @@ vips_object_set_argument_from_string( VipsObject *object,
g_assert( argument_class->flags & VIPS_ARGUMENT_INPUT );
if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) ) {
VipsObject *object;
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) &&
(oclass = g_type_class_ref( VIPS_TYPE_FILE_LOAD )) ) {
VipsObject *new_object;
VipsImage *out;
if( !(object = vips_object_new_from_string( oclass, value )) )
/* Use VipsFile to build images, then pull @out from it and
* use that to set the value.
*/
if( !(new_object =
vips_object_new_from_string( oclass, value )) )
return( -1 );
if( vips_object_build( new_object ) ) {
g_object_unref( new_object );
return( -1 );
}
g_object_get( new_object, "out", &out, NULL );
/* Getting @out will have upped it's count and we want to
* hold the only ref to it.
*/
g_object_unref( out );
/* @out holds a ref to new_object, we can drop ours.
*/
g_object_unref( new_object );
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
g_value_set_object( &gvalue, out );
/* Setting gvalue will have upped @out's count again,
* go back to 1 so that gvalue has the only ref.
*/
g_object_unref( out );
}
else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) ) {
VipsObject *new_object;
if( !(new_object =
vips_object_new_from_string( oclass, value )) )
return( -1 );
if( vips_object_build( new_object ) ) {
g_object_unref( new_object );
return( -1 );
}
g_value_init( &gvalue, G_TYPE_OBJECT );
g_value_set_object( &gvalue, object );
g_value_set_object( &gvalue, new_object );
/* The GValue now has a ref, we can drop ours.
*/
g_object_unref( object );
g_object_unref( new_object );
}
else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
gboolean b;
@ -1375,7 +1417,30 @@ vips_object_get_argument_to_string( VipsObject *object,
g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );
if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) &&
(oclass = g_type_class_ref( VIPS_TYPE_FILE_SAVE )) ) {
VipsObject *new_object;
VipsImage *in;
/* Use VipsFile to make a saver, set 'in' on that and run
* build to make it write.
*/
if( !(new_object =
vips_object_new_from_string( oclass, arg )) )
return( -1 );
g_object_get( object, name, &in, NULL );
g_object_set( new_object, "in", in, NULL );
g_object_unref( in );
if( vips_object_build( new_object ) ) {
g_object_unref( new_object );
return( -1 );
}
g_object_unref( new_object );
}
else if( g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) &&
oclass->output_to_arg ) {
VipsObject *value;
@ -1538,11 +1603,6 @@ vips_object_new_from_string( VipsObjectClass *object_class, const char *p )
}
}
if( vips_object_build( object ) ) {
g_object_unref( object );
return( NULL );
}
return( object );
}

View File

@ -218,6 +218,19 @@ vips__write_2byte( unsigned char **to, unsigned char *from )
*to += 2;
}
guint32
vips__file_magic( const char *filename )
{
guint32 magic;
if( vips__get_bytes( filename, (unsigned char *) &magic, 4 ) &&
(magic == VIPS_MAGIC_INTEL ||
magic == VIPS_MAGIC_SPARC ) )
return( magic );
return( 0 );
}
/* offset, read, write functions.
*/
typedef struct _FieldIO {