new-style vips load/save works

also image.c uses the new system instead of VipsFormat
This commit is contained in:
John Cupitt 2011-11-25 18:01:25 +00:00
parent 19b3c7eeb2
commit 43587801f7
8 changed files with 88 additions and 223 deletions

5
TODO
View File

@ -1,9 +1,6 @@
- need vips load/save class, so we can detect vips files for native read /
write
- we have to open the image to see flags argh
jpeg load needs to set suffs
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

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 );

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

@ -46,7 +46,7 @@
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 )
@ -79,24 +79,53 @@ vips_file_load_vips_is_a( const char *filename )
return( 0 );
}
static int
vips_file_load_vips_get_flags( VipsFileLoad *load )
{
VipsFile *file = VIPS_FILE( load );
unsigned char buf[4];
load->flags = VIPS_FILE_PARTIAL;
if( vips__get_bytes( file->filename, buf, 4 ) &&
buf[0] == 0x08 &&
buf[1] == 0xf2 &&
buf[2] == 0xa6 &&
buf[3] == 0xb6 )
load->flags |= VIPS_FORMAT_BIGENDIAN;
return( 0 );
}
static int
vips_file_load_vips_header( VipsFileLoad *load )
{
VipsFile *file = VIPS_FILE( load );
if( !(load->out = vips_image_new_from_file( file->filename )) )
return( -1 );
return( 0 );
}
static int
vips_file_load_vips_load( VipsFileLoad *load )
{
VipsFile *file = VIPS_FILE( load );
if( !(load->real = vips_image_new_from_file( file->filename )) )
return( -1 );
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";
@ -106,9 +135,9 @@ vips_file_load_jpeg_class_init( VipsFileLoadJpegClass *class )
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;
}
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;

View File

@ -460,187 +460,7 @@ 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
@ -648,7 +468,7 @@ vips_image_open_lazy( VipsImage *image,
* parameters here.
*/
typedef struct {
int (*save_fn)(); /* Save function */
const char *file_op; /* Save function */
char *filename; /* Save args */
} SaveBlock;
@ -657,7 +477,7 @@ typedef struct {
static void
vips_image_save_cb( VipsImage *image, int *result, SaveBlock *sb )
{
if( sb->save_fn( image, sb->filename ) )
if( vips_call( sb->file_op, image, sb->filename, NULL ) )
*result = -1;
g_free( sb->filename );
@ -665,12 +485,12 @@ vips_image_save_cb( VipsImage *image, int *result, SaveBlock *sb )
}
static void
vips_attach_save( VipsImage *image, int (*save_fn)(), const char *filename )
vips_attach_save( VipsImage *image, const char *file_op, const char *filename )
{
SaveBlock *sb;
sb = g_new( SaveBlock, 1 );
sb->save_fn = save_fn;
sb->file_op = file_op;
sb->filename = g_strdup( filename );
g_signal_connect( image, "written",
G_CALLBACK( vips_image_save_cb ), sb );
@ -771,15 +591,24 @@ vips_image_build( VipsObject *object )
if( !(file_op = vips_file_find_load( filename )) )
return( -1 );
if( vips_format_is_vips( format ) ) {
if( strcmp( file_op, "vipsload" ) == 0 ) {
/* We may need to byteswap.
*/
VipsFormatFlags flags =
vips_format_get_flags( format, filename );
gboolean native = (flags & VIPS_FORMAT_BIGENDIAN) ==
vips_amiMSBfirst();
VipsImage *t;
VipsFormatFlags flags;
if( vips_call( file_op, filename, &t,
"flags", &flags,
NULL ) )
return( -1 );
if( (flags & VIPS_FORMAT_BIGENDIAN) ==
vips_amiMSBfirst() ) {
/* Native byte order .. open directly into
* this image.
*/
g_object_unref( t );
if( native ) {
if( vips_image_open_input( image ) )
return( -1 );
@ -787,41 +616,49 @@ vips_image_build( VipsObject *object )
image->dtype = VIPS_IMAGE_MMAPINRW;
}
else {
VipsImage *x;
VipsImage *t2;
if( !(x = vips_image_new()) )
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 );
/* Byteswap t and copy into this image.
*/
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_call( file_op, filename, &t, NULL ) )
return( -1 );
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 )) )
if( !(file_op = vips_file_find_save( filename )) )
return( -1 );
if( vips_format_is_vips( format ) )
if( strcmp( file_op, "vipssave" ) == 0 )
image->dtype = VIPS_IMAGE_OPENOUT;
else {
image->dtype = VIPS_IMAGE_PARTIAL;
vips_attach_save( image,
format->save, filename );
vips_attach_save( image, file_op, filename );
}
break;