456 lines
12 KiB
C
456 lines
12 KiB
C
/* im_header_int, im_header_double, im_header_string: output various fields
|
|
* from the VIPS header
|
|
*
|
|
* 9/7/02 JC
|
|
* - first version
|
|
* 7/6/05
|
|
* - now reads meta fields too
|
|
* - cleaned up
|
|
* - added im_header_exists(), im_header_map()
|
|
* 1/8/05
|
|
* - now im_header_get_type() and im_header_get() rather than
|
|
* im_header_exists()
|
|
* 4/1/07
|
|
* - removed Hist from standard fields ... now a separate function
|
|
* 29/8/09
|
|
* - im_header_get_type() renamed as im_header_get_typeof() to prevent
|
|
* confusion with GObject-style type definers
|
|
* 1/10/09
|
|
* - rename as header.c
|
|
* - gtkdoc comments
|
|
*/
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif /*HAVE_CONFIG_H*/
|
|
#include <vips/intl.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <vips/vips.h>
|
|
#include <vips/internal.h>
|
|
|
|
#ifdef WITH_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif /*WITH_DMALLOC*/
|
|
|
|
/**
|
|
* SECTION: header
|
|
* @short_description: get, set and walk image headers
|
|
* @stability: Stable
|
|
* @see_also: <link linkend="libvips-meta">meta</link>,
|
|
* <link linkend="libvips-check">check</link>
|
|
* @include: vips/vips.h
|
|
*
|
|
* These functions let you get at image header data (including metadata) in a
|
|
* uniform way. They are handy for language bindings but less useful for C
|
|
* users.
|
|
*
|
|
* They first search the
|
|
* VIPS header
|
|
* fields (see <link linkend="libvips-image">image</link>), then search for
|
|
* a metadata field of that name (see
|
|
* <link linkend="libvips-meta">meta</link>).
|
|
* Use im_header_get_typeof() to test for the
|
|
* existance and #GType
|
|
* of a header field.
|
|
*
|
|
* See <link linkend="libvips-meta">meta</link>
|
|
* for a set of functions for adding new metadata to an image.
|
|
*/
|
|
|
|
|
|
/* Name, offset pair.
|
|
*/
|
|
typedef struct _HeaderField {
|
|
const char *field;
|
|
glong offset;
|
|
} HeaderField;
|
|
|
|
/* Built in fields and struct offsets.
|
|
*/
|
|
static HeaderField int_field[] = {
|
|
{ "Xsize", G_STRUCT_OFFSET( IMAGE, Xsize ) },
|
|
{ "Ysize", G_STRUCT_OFFSET( IMAGE, Ysize ) },
|
|
{ "Bands", G_STRUCT_OFFSET( IMAGE, Bands ) },
|
|
{ "Bbits", G_STRUCT_OFFSET( IMAGE, Bbits ) },
|
|
{ "BandFmt", G_STRUCT_OFFSET( IMAGE, BandFmt ) },
|
|
{ "Coding", G_STRUCT_OFFSET( IMAGE, Coding ) },
|
|
{ "Type", G_STRUCT_OFFSET( IMAGE, Type ) },
|
|
{ "Xoffset", G_STRUCT_OFFSET( IMAGE, Xoffset ) },
|
|
{ "Yoffset", G_STRUCT_OFFSET( IMAGE, Yoffset ) }
|
|
};
|
|
|
|
/* These are actually floats :-( how annoying. We report them as doubles for
|
|
* consistency with the im_meta_*() functions.
|
|
*/
|
|
static HeaderField double_field[] = {
|
|
{ "Xres", G_STRUCT_OFFSET( IMAGE, Xres ) },
|
|
{ "Yres", G_STRUCT_OFFSET( IMAGE, Yres ) }
|
|
};
|
|
|
|
static HeaderField string_field[] = {
|
|
{ "filename", G_STRUCT_OFFSET( IMAGE, filename ) }
|
|
};
|
|
|
|
/**
|
|
* im_header_int:
|
|
* @im: image to get the header field from
|
|
* @field: field name
|
|
* @out: return field value
|
|
*
|
|
* Gets @out from @im under the name @field. This function searches for
|
|
* int-valued fields.
|
|
*
|
|
* See also: im_header_get(), im_header_get_typeof()
|
|
*
|
|
* Returns: 0 on success, -1 otherwise.
|
|
*/
|
|
int
|
|
im_header_int( IMAGE *im, const char *field, int *out )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( int_field ); i++ )
|
|
if( strcmp( field, int_field[i].field ) == 0 ) {
|
|
*out = G_STRUCT_MEMBER( int, im,
|
|
int_field[i].offset );
|
|
break;
|
|
}
|
|
|
|
if( i == VIPS_NUMBER( int_field ) &&
|
|
im_meta_get_int( im, field, out ) ) {
|
|
vips_error( "im_header_int",
|
|
_( "no such int field \"%s\"" ), field );
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_header_double:
|
|
* @im: image to get the header field from
|
|
* @field: field name
|
|
* @out: return field value
|
|
*
|
|
* Gets @out from @im under the name @field.
|
|
* This function searches for
|
|
* double-valued fields.
|
|
*
|
|
* See also: im_header_get(), im_header_get_typeof()
|
|
*
|
|
* Returns: 0 on success, -1 otherwise.
|
|
*/
|
|
int
|
|
im_header_double( IMAGE *im, const char *field, double *out )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( double_field ); i++ )
|
|
if( strcmp( field, double_field[i].field ) == 0 ) {
|
|
*out = G_STRUCT_MEMBER( float, im,
|
|
double_field[i].offset );
|
|
break;
|
|
}
|
|
|
|
if( i == VIPS_NUMBER( double_field ) &&
|
|
im_meta_get_double( im, field, out ) ) {
|
|
vips_error( "im_header_double",
|
|
_( "no such double field \"%s\"" ), field );
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_header_string:
|
|
* @im: image to get the header field from
|
|
* @field: field name
|
|
* @out: return field value
|
|
*
|
|
* Gets @out from @im under the name @field.
|
|
* This function searches for string-valued fields.
|
|
*
|
|
* Do not free @out.
|
|
*
|
|
* See also: im_header_get(), im_header_get_typeof()
|
|
*
|
|
* Returns: 0 on success, -1 otherwise.
|
|
*/
|
|
int
|
|
im_header_string( IMAGE *im, const char *field, char **out )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( string_field ); i++ )
|
|
if( strcmp( field, string_field[i].field ) == 0 ) {
|
|
*out = G_STRUCT_MEMBER( char *, im,
|
|
string_field[i].offset );
|
|
break;
|
|
}
|
|
|
|
if( i == VIPS_NUMBER( string_field ) &&
|
|
im_meta_get_string( im, field, out ) ) {
|
|
vips_error( "im_header_string",
|
|
_( "no such string field \"%s\"" ), field );
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_header_as_string:
|
|
* @im: image to get the header field from
|
|
* @field: field name
|
|
* @out: return field value as string
|
|
*
|
|
* Gets @out from @im under the name @field.
|
|
* This function will read any field, returning it as a printable string.
|
|
* You need to free the string with g_free() when you are done with it.
|
|
*
|
|
* See also: im_header_get(), im_header_get_typeof().
|
|
*
|
|
* Returns: 0 on success, -1 otherwise.
|
|
*/
|
|
int
|
|
im_header_as_string( IMAGE *im, const char *field, char **out )
|
|
{
|
|
GValue value = { 0 };
|
|
GType type;
|
|
|
|
if( im_header_get( im, field, &value ) )
|
|
return( -1 );
|
|
|
|
/* Display the save form, if there is one. This way we display
|
|
* something useful for ICC profiles, xml fields, etc.
|
|
*/
|
|
type = G_VALUE_TYPE( &value );
|
|
if( g_value_type_transformable( type, IM_TYPE_SAVE_STRING ) ) {
|
|
GValue save_value = { 0 };
|
|
|
|
g_value_init( &save_value, IM_TYPE_SAVE_STRING );
|
|
if( !g_value_transform( &value, &save_value ) )
|
|
return( -1 );
|
|
*out = g_strdup( im_save_string_get( &save_value ) );
|
|
g_value_unset( &save_value );
|
|
}
|
|
else
|
|
*out = g_strdup_value_contents( &value );
|
|
|
|
g_value_unset( &value );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_header_get_typeof:
|
|
* @im: image to test
|
|
* @field: the name to search for
|
|
*
|
|
* Read the GType for a header field. Returns zero if there is no
|
|
* field of that name.
|
|
*
|
|
* See also: im_header_get().
|
|
*
|
|
* Returns: the GType of the field, or zero if there is no
|
|
* field of that name.
|
|
*/
|
|
GType
|
|
im_header_get_typeof( IMAGE *im, const char *field )
|
|
{
|
|
int i;
|
|
GType type;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( int_field ); i++ )
|
|
if( strcmp( field, int_field[i].field ) == 0 )
|
|
return( G_TYPE_INT );
|
|
for( i = 0; i < VIPS_NUMBER( double_field ); i++ )
|
|
if( strcmp( field, double_field[i].field ) == 0 )
|
|
return( G_TYPE_DOUBLE );
|
|
for( i = 0; i < VIPS_NUMBER( string_field ); i++ )
|
|
if( strcmp( field, string_field[i].field ) == 0 )
|
|
return( G_TYPE_STRING );
|
|
if( (type = im_meta_get_typeof( im, field )) )
|
|
return( type );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Fill value_copy with a copy of the value, -1 on error. value_copy must be
|
|
* zeroed but uninitialised. User must g_value_unset( value ).
|
|
*/
|
|
|
|
/**
|
|
* im_header_get:
|
|
* @im: image to get the field from from
|
|
* @field: the name to give the metadata
|
|
* @value_copy: the GValue is copied into this
|
|
*
|
|
* Fill @value_copy with a copy of the header field. @value_copy must be zeroed
|
|
* but uninitialised.
|
|
*
|
|
* This will return -1 and add a message to the error buffer if the field
|
|
* does not exist. Use im_header_get_typeof() to test for the
|
|
* existence
|
|
* of a field first if you are not certain it will be there.
|
|
*
|
|
* For example, to read a double from an image (though of course you would use
|
|
* im_header_double() in practice):
|
|
*
|
|
* |[
|
|
* GValue value = { 0 };
|
|
* double d;
|
|
*
|
|
* if( im_header_get( im, field, &value ) )
|
|
* return( -1 );
|
|
*
|
|
* if( G_VALUE_TYPE( &value ) != G_TYPE_DOUBLE ) {
|
|
* vips_error( "mydomain", _( "field \"%s\" is of type %s, not double" ),
|
|
* field, g_type_name( G_VALUE_TYPE( &value ) ) );
|
|
* g_value_unset( &value );
|
|
* return( -1 );
|
|
* }
|
|
*
|
|
* d = g_value_get_double( &value );
|
|
* g_value_unset( &value );
|
|
*
|
|
* return( 0 );
|
|
* ]|
|
|
*
|
|
* See also: im_header_get_typeof(), im_header_double().
|
|
*
|
|
* Returns: 0 on success, -1 otherwise.
|
|
*/
|
|
int
|
|
im_header_get( IMAGE *im, const char *field, GValue *value_copy )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( int_field ); i++ )
|
|
if( strcmp( field, int_field[i].field ) == 0 ) {
|
|
g_value_init( value_copy, G_TYPE_INT );
|
|
g_value_set_int( value_copy,
|
|
G_STRUCT_MEMBER( int, im,
|
|
int_field[i].offset ) );
|
|
return( 0 );
|
|
}
|
|
|
|
for( i = 0; i < VIPS_NUMBER( double_field ); i++ )
|
|
if( strcmp( field, double_field[i].field ) == 0 ) {
|
|
g_value_init( value_copy, G_TYPE_DOUBLE );
|
|
g_value_set_double( value_copy,
|
|
G_STRUCT_MEMBER( float, im,
|
|
double_field[i].offset ) );
|
|
return( 0 );
|
|
}
|
|
|
|
for( i = 0; i < VIPS_NUMBER( string_field ); i++ )
|
|
if( strcmp( field, string_field[i].field ) == 0 ) {
|
|
g_value_init( value_copy, G_TYPE_STRING );
|
|
g_value_set_static_string( value_copy,
|
|
G_STRUCT_MEMBER( char *, im,
|
|
string_field[i].offset ) );
|
|
return( 0 );
|
|
}
|
|
|
|
if( !im_meta_get( im, field, value_copy ) )
|
|
return( 0 );
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
static void *
|
|
header_map_fn( Meta *meta, im_header_map_fn fn, void *a )
|
|
{
|
|
return( fn( meta->im, meta->field, &meta->value, a ) );
|
|
}
|
|
|
|
/**
|
|
* im_header_map:
|
|
* @im: image to map over
|
|
* @fn: function to call for each header field
|
|
* @a: user data for function
|
|
*
|
|
* This function calls @fn for every header field, including every item of
|
|
* metadata.
|
|
*
|
|
* Like all _map functions, the user function should return %NULL to continue
|
|
* iteration, or a non-%NULL pointer to indicate early termination.
|
|
*
|
|
* See also: im_header_get_typeof(), im_header_get().
|
|
*
|
|
* Returns: %NULL on success, the failing pointer otherwise.
|
|
*/
|
|
void *
|
|
im_header_map( IMAGE *im, im_header_map_fn fn, void *a )
|
|
{
|
|
int i;
|
|
GValue value = { 0 };
|
|
void *result;
|
|
|
|
for( i = 0; i < VIPS_NUMBER( int_field ); i++ ) {
|
|
im_header_get( im, int_field[i].field, &value );
|
|
result = fn( im, int_field[i].field, &value, a );
|
|
g_value_unset( &value );
|
|
|
|
if( result )
|
|
return( result );
|
|
}
|
|
|
|
for( i = 0; i < VIPS_NUMBER( double_field ); i++ ) {
|
|
im_header_get( im, double_field[i].field, &value );
|
|
result = fn( im, double_field[i].field, &value, a );
|
|
g_value_unset( &value );
|
|
|
|
if( result )
|
|
return( result );
|
|
}
|
|
|
|
for( i = 0; i < VIPS_NUMBER( string_field ); i++ ) {
|
|
im_header_get( im, string_field[i].field, &value );
|
|
result = fn( im, string_field[i].field, &value, a );
|
|
g_value_unset( &value );
|
|
|
|
if( result )
|
|
return( result );
|
|
}
|
|
|
|
if( im->Meta_traverse &&
|
|
(result = im_slist_map2( im->Meta_traverse,
|
|
(VSListMap2Fn) header_map_fn, fn, a )) )
|
|
return( result );
|
|
|
|
return( NULL );
|
|
}
|