VipsCopy can change props

VipsCopy has a set of optional input args that you can use to change
header fields
This commit is contained in:
John Cupitt 2011-09-30 09:39:47 +01:00
parent 45b2a9a525
commit 1c65d74325
4 changed files with 105 additions and 81 deletions

2
TODO
View File

@ -14,6 +14,8 @@
copy_swap needs doing too, a separate class I guess
or add a "swap" prop and an enum like VIPS_SWAP8, VIPS_SWAP2 etc.?
- do clip/embed etc. in new style, good to get everything that VipsAdd uses in

View File

@ -73,6 +73,10 @@
*/
/*
*/
#define VIPS_DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
@ -84,6 +88,7 @@
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#include "conversion.h"
@ -95,14 +100,20 @@
* Copy an image, optionally modifying the header. VIPS copies images by
* copying pointers, so this operation is fast, even for very large images.
*
* You can optionally set any or all header fields during the copy. Some
* header fields, such as "xres", the horizontal resolution, are safe to
* change in any way, others, such as "width" will cause immediate crashes if
* they are not set carefully.
*
* Returns: 0 on success, -1 on error.
*/
/* Properties.
*
* Order important! Keep in sync with vips_copy_names[] below.
*/
enum {
PROP_INPUT = 1,
PROP_INTERPRETATION,
PROP_XRES,
PROP_YRES,
@ -164,12 +175,31 @@ vips_copy_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
return( 0 );
}
/* The props we copy, if set, from the operation to the image.
*/
static const char *vips_copy_names[] = {
NULL, /* unused */
NULL, /* PROP_INPUT = 1 */
"interpretation", /* PROP_INTERPRETATION, */
"xres", /* PROP_XRES, */
"yres", /* PROP_YRES, */
"xoffset", /* PROP_XOFFSET, */
"xoffset", /* PROP_YOFFSET, */
"bands", /* PROP_BANDS, */
"format", /* PROP_FORMAT, */
"coding", /* PROP_CODING, */
"width", /* PROP_WIDTH, */
"height" /* PROP_HEIGHT, */
};
static int
vips_copy_build( VipsObject *object )
{
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsCopy *copy = (VipsCopy *) object;
int i;
if( VIPS_OBJECT_CLASS( vips_copy_parent_class )->build( object ) )
return( -1 );
@ -177,12 +207,40 @@ vips_copy_build( VipsObject *object )
vips_image_pio_output( conversion->output ) )
return( -1 );
/* Use props to adjust header fields.
*/
if( vips_image_copy_fields( conversion->output, copy->input ) )
return( -1 );
vips_demand_hint( conversion->output,
VIPS_DEMAND_STYLE_THINSTRIP, copy->input, NULL );
/* Use props to adjust header fields.
*/
for( i = 2; i < PROP_LAST; i++ ) {
const char *name = vips_copy_names[i];
GParamSpec *pspec;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
if( vips_object_get_argument( object, name,
&pspec, &argument_class, &argument_instance ) )
return( -1 );
if( argument_instance->assigned ) {
GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
GValue value = { 0, };
VIPS_DEBUG_MSG( "vips_copy_build: assigning %s\n",
name );
g_value_init( &value, type );
g_object_get_property( G_OBJECT( object ),
name, &value );
g_object_set_property( G_OBJECT( conversion->output ),
name, &value );
g_value_unset( &value );
}
}
if( vips_image_generate( conversion->output,
vips_start_one, vips_copy_gen, vips_stop_one,
copy->input, copy ) )

View File

@ -1260,27 +1260,21 @@ vips_object_set_argument_from_string( VipsObject *object,
gboolean
vips_object_get_argument_needs_string( VipsObject *object, const char *name )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
GParamSpec *pspec;
GType otype;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
VipsObjectClass *oclass;
#ifdef DEBUG
printf( "vips_object_get_argument_needs_string: %s\n", name );
#endif /*DEBUG*/
pspec = g_object_class_find_property( G_OBJECT_CLASS( class ), name );
if( !pspec ) {
vips_error( "VipsObject", _( "%s.%s does not exist" ),
G_OBJECT_TYPE_NAME( object ), name );
if( vips_object_get_argument( object, name,
&pspec, &argument_class, &argument_instance ) )
return( -1 );
}
otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
argument_class = (VipsArgumentClass *)
vips__argument_table_lookup( class->argument_table, pspec );
otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );
@ -1316,11 +1310,10 @@ int
vips_object_get_argument_to_string( VipsObject *object,
const char *name, const char *arg )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
GParamSpec *pspec;
GType otype;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
VipsObjectClass *oclass;
#ifdef DEBUG
@ -1328,16 +1321,11 @@ vips_object_get_argument_to_string( VipsObject *object,
name, arg );
#endif /*DEBUG*/
pspec = g_object_class_find_property( G_OBJECT_CLASS( class ), name );
if( !pspec ) {
vips_error( "VipsObject", _( "%s.%s does not exist" ),
G_OBJECT_TYPE_NAME( object ), name );
if( vips_object_get_argument( object, name,
&pspec, &argument_class, &argument_instance ) )
return( -1 );
}
otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
argument_class = (VipsArgumentClass *)
vips__argument_table_lookup( class->argument_table, pspec );
otype = G_PARAM_SPEC_VALUE_TYPE( pspec );
g_assert( argument_class->flags & VIPS_ARGUMENT_OUTPUT );

View File

@ -311,11 +311,6 @@ vips_operation_set_valist_required( VipsOperation *operation, va_list ap )
static int
vips_operation_set_valist_optional( VipsOperation *operation, va_list ap )
{
VipsOperationClass *class =
VIPS_OPERATION_GET_CLASS( operation );
VipsArgumentTable *argument_table =
VIPS_OBJECT_CLASS( class )->argument_table;
char *name;
VIPS_DEBUG_MSG( "vips_operation_set_valist_optional:\n" );
@ -325,29 +320,22 @@ vips_operation_set_valist_optional( VipsOperation *operation, va_list ap )
while( name ) {
GParamSpec *pspec;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name );
if( !(pspec = g_object_class_find_property(
G_OBJECT_CLASS( class ), name )) ) {
vips_error( VIPS_OBJECT_CLASS( class )->description,
_( "class `%s' has no property named `%s'\n" ),
G_OBJECT_TYPE_NAME( operation ), name );
if( vips_object_get_argument( VIPS_OBJECT( operation ), name,
&pspec, &argument_class, &argument_instance ) )
return( -1 );
}
argument_class = (VipsArgumentClass *)
vips__argument_table_lookup( argument_table, pspec );
if( argument_class ) {
VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap );
VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap );
g_object_set_property( G_OBJECT( operation ),
name, &value );
g_object_set_property( G_OBJECT( operation ),
name, &value );
VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap );
VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap );
VIPS_OPERATION_COLLECT_END
}
VIPS_OPERATION_COLLECT_END
name = va_arg( ap, char * );
}
@ -402,11 +390,6 @@ vips_operation_get_valist_required( VipsOperation *operation, va_list ap )
static int
vips_operation_get_valist_optional( VipsOperation *operation, va_list ap )
{
VipsOperationClass *class =
VIPS_OPERATION_GET_CLASS( operation );
VipsArgumentTable *argument_table =
VIPS_OBJECT_CLASS( class )->argument_table;
char *name;
VIPS_DEBUG_MSG( "vips_operation_get_valist_optional:\n" );
@ -416,54 +399,47 @@ vips_operation_get_valist_optional( VipsOperation *operation, va_list ap )
while( name ) {
GParamSpec *pspec;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name );
if( !(pspec = g_object_class_find_property(
G_OBJECT_CLASS( class ), name )) ) {
vips_error( VIPS_OBJECT_CLASS( class )->description,
_( "class `%s' has no property named `%s'\n" ),
G_OBJECT_TYPE_NAME( operation ), name );
if( vips_object_get_argument( VIPS_OBJECT( operation ), name,
&pspec, &argument_class, &argument_instance ) )
return( -1 );
}
argument_class = (VipsArgumentClass *)
vips__argument_table_lookup( argument_table, pspec );
if( argument_class ) {
VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap );
VIPS_OPERATION_COLLECT_SET( pspec, argument_class, ap );
g_object_set_property( G_OBJECT( operation ),
name, &value );
g_object_set_property( G_OBJECT( operation ),
name, &value );
VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap );
VIPS_OPERATION_COLLECT_GET( pspec, argument_class, ap );
#ifdef VIPS_DEBUG
printf( "\twriting %s to %p\n",
g_param_spec_get_name( pspec ), arg );
printf( "\twriting %s to %p\n",
g_param_spec_get_name( pspec ), arg );
#endif /*VIPS_DEBUG */
/* If the dest pointer is NULL, skip the read.
/* If the dest pointer is NULL, skip the read.
*/
if( arg ) {
g_object_get( G_OBJECT( operation ),
g_param_spec_get_name( pspec ), arg,
NULL );
/* If the pspec is an object, that will up
* the ref count. We want to hand over the
* ref, so we have to knock it down again.
*/
if( arg ) {
g_object_get( G_OBJECT( operation ),
g_param_spec_get_name( pspec ), arg,
NULL );
if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
GObject *object;
/* If the pspec is an object, that will up
* the ref count. We want to hand over the
* ref, so we have to knock it down again.
*/
if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
GObject *object;
object = *((GObject **) arg);
g_object_unref( object );
}
object = *((GObject **) arg);
g_object_unref( object );
}
VIPS_OPERATION_COLLECT_END
}
VIPS_OPERATION_COLLECT_END
name = va_arg( ap, char * );
}