Merge remote-tracking branch 'origin/format-hacking' into format-hacking
This commit is contained in:
commit
c4c1dad8a6
21
TODO
21
TODO
@ -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?
|
||||
|
||||
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -852,7 +852,6 @@ vips_file_save_jpeg_class_init( VipsFileSaveJpegClass *class )
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsFileSaveJpeg, profile ),
|
||||
NULL );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 * );
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user