better exif handling

- track ifd numbers for each item of exif
- be more careful about which ones we update
- don't update xres/yres in vips_shrink()
This commit is contained in:
John Cupitt 2012-11-16 10:03:31 +00:00
parent 717266ad2b
commit fcc33020bd
4 changed files with 71 additions and 61 deletions

View File

@ -20,6 +20,7 @@
- remove no threads option, glib no longer support it
- better --help output for vips driver prog
- vipsthumbnail -o allows absolute file names
- much better exif handling for jpg images (thanks Gary)
14/11/12 started 7.30.6
- capture tiff warnings earlier

View File

@ -281,25 +281,28 @@ show_entry( ExifEntry *entry, void *client )
static void
show_ifd( ExifContent *content, void *client )
{
int *ifd = (int *) client;
printf( "- ifd %d\n", *ifd );
exif_content_foreach_entry( content, show_entry, client );
printf( "-\n" );
*ifd += 1;
}
void
show_values( ExifData *data )
{
ExifByteOrder order;
int ifd;
order = exif_data_get_byte_order( data );
printf( "EXIF tags in '%s' byte order\n",
exif_byte_order_get_name( order ) );
printf( "%-20.20s", "Tag" );
printf( "|" );
printf( "%-58.58s", "Value" );
printf( "\n" );
printf( "Title|Value|Format|Size\n" );
exif_data_foreach_content( data, show_ifd, NULL );
ifd = 0;
exif_data_foreach_content( data, show_ifd, &ifd );
if( data->size )
printf( "contains thumbnail of %d bytes\n", data->size );
@ -416,7 +419,9 @@ attach_exif_entry( ExifEntry *entry, VipsExif *ve )
char value_txt[256];
VipsBuf value = VIPS_BUF_STATIC( value_txt );
vips_buf_appendf( &name, "exif-%s", exif_tag_get_title( entry->tag ) );
vips_buf_appendf( &name, "exif-ifd%d-%s",
exif_entry_get_ifd( entry ),
exif_tag_get_title( entry->tag ) );
vips_exif_to_s( ve->ed, entry, &value );
/* Can't do anything sensible with the error return.
@ -432,29 +437,12 @@ attach_exif_content( ExifContent *content, VipsExif *ve )
(ExifContentForeachEntryFunc) attach_exif_entry, ve );
}
/* Just find the first occurence of the tag (is this correct?)
*/
static ExifEntry *
find_entry( ExifData *ed, ExifTag tag )
{
int i;
for( i = 0; i < EXIF_IFD_COUNT; i++ ) {
ExifEntry *entry;
if( (entry = exif_content_get_entry( ed->ifd[i], tag )) )
return( entry );
}
return( NULL );
}
static int
get_entry_rational( ExifData *ed, ExifTag tag, double *out )
get_entry_rational( ExifData *ed, int ifd, ExifTag tag, double *out )
{
ExifEntry *entry;
if( !(entry = find_entry( ed, tag )) ||
if( !(entry = exif_content_get_entry( ed->ifd[ifd], tag )) ||
entry->format != EXIF_FORMAT_RATIONAL ||
entry->components != 1 )
return( -1 );
@ -463,11 +451,11 @@ get_entry_rational( ExifData *ed, ExifTag tag, double *out )
}
static int
get_entry_short( ExifData *ed, ExifTag tag, int *out )
get_entry_short( ExifData *ed, int ifd, ExifTag tag, int *out )
{
ExifEntry *entry;
if( !(entry = find_entry( ed, tag )) ||
if( !(entry = exif_content_get_entry( ed->ifd[ifd], tag )) ||
entry->format != EXIF_FORMAT_SHORT ||
entry->components != 1 )
return( -1 );
@ -481,14 +469,22 @@ set_vips_resolution( VipsImage *im, ExifData *ed )
double xres, yres;
int unit;
if( get_entry_rational( ed, EXIF_TAG_X_RESOLUTION, &xres ) ||
get_entry_rational( ed, EXIF_TAG_Y_RESOLUTION, &yres ) ||
get_entry_short( ed, EXIF_TAG_RESOLUTION_UNIT, &unit ) ) {
/* The main image xres/yres are in ifd0. ifd1 has xres/yres of the
* image thumbnail, if any.
*/
if( get_entry_rational( ed, 0, EXIF_TAG_X_RESOLUTION, &xres ) ||
get_entry_rational( ed, 0, EXIF_TAG_Y_RESOLUTION, &yres ) ||
get_entry_short( ed, 0, EXIF_TAG_RESOLUTION_UNIT, &unit ) ) {
vips_warn( "VipsJpeg",
"%s", _( "error reading resolution" ) );
return;
}
#ifdef DEBUG
printf( "set_vips_resolution: seen exif tags "
"xres = %g, yres = %g, unit = %d\n", xres, yres, unit );
#endif /*DEBUG*/
switch( unit ) {
case 2:
/* In inches.
@ -701,6 +697,11 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
if( cinfo->saw_JFIF_marker &&
cinfo->X_density != 1U &&
cinfo->Y_density != 1U ) {
#ifdef DEBUG
printf( "read_jpeg_header: seen jfif _density %d, %d\n",
cinfo->X_density, cinfo->Y_density );
#endif /*DEBUG*/
switch( cinfo->density_unit ) {
case 1:
/* Pixels per inch.

View File

@ -80,6 +80,7 @@
/*
#define DEBUG
#define VIPS_DEBUG
*/
#ifdef HAVE_CONFIG_H
@ -282,6 +283,10 @@ vips_exif_set_double( ExifData *ed,
rational.numerator = value * scale;
rational.denominator = scale;
VIPS_DEBUG_MSG( "vips_exif_set_double: %g / %g\n",
(double) rational.numerator,
(double) rational.denominator );
exif_set_rational( entry->data + offset, bo, rational );
}
else if( entry->format == EXIF_FORMAT_SRATIONAL ) {
@ -293,6 +298,9 @@ vips_exif_set_double( ExifData *ed,
rational.numerator = value * scale;
rational.denominator = scale;
VIPS_DEBUG_MSG( "vips_exif_set_double: %d / %d\n",
rational.numerator, rational.denominator );
exif_set_srational( entry->data + offset, bo, rational );
}
}
@ -300,38 +308,26 @@ vips_exif_set_double( ExifData *ed,
typedef void (*write_fn)( ExifData *ed,
ExifEntry *entry, unsigned long component, void *data );
/* Write a component in a tag everywhere it appears.
/* Write a tag. Update what's there, or make a new one.
*/
static int
write_tag( ExifData *ed,
write_tag( ExifData *ed, int ifd,
ExifTag tag, ExifFormat format, write_fn fn, void *data )
{
int found;
int i;
ExifEntry *entry;
found = 0;
for( i = 0; i < EXIF_IFD_COUNT; i++ ) {
ExifEntry *entry;
if( (entry = exif_content_get_entry( ed->ifd[i], tag )) &&
entry->format == format ) {
if( (entry = exif_content_get_entry( ed->ifd[ifd], tag )) ) {
if( entry->format == format )
fn( ed, entry, 0, data );
found = 1;
}
}
if( !found ) {
/* There was no tag we could update ... make one in ifd[0].
*/
ExifEntry *entry;
else {
entry = exif_entry_new();
/* tag must be set before calling exif_content_add_entry.
*/
entry->tag = tag;
exif_content_add_entry( ed->ifd[0], entry );
exif_content_add_entry( ed->ifd[ifd], entry );
exif_entry_initialize( entry, tag );
exif_entry_unref( entry );
@ -351,6 +347,9 @@ set_exif_resolution( ExifData *ed, VipsImage *im )
char *p;
int unit;
VIPS_DEBUG_MSG( "set_exif_resolution: vips res of %g, %g\n",
im->Xres, im->Yres );
/* Default to inches, more progs support it.
*/
unit = 2;
@ -376,11 +375,14 @@ set_exif_resolution( ExifData *ed, VipsImage *im )
return( 0 );
}
if( write_tag( ed, EXIF_TAG_X_RESOLUTION, EXIF_FORMAT_RATIONAL,
/* Main image xres/yres/unit are in ifd0. ifd1 has the thumbnail
* xres/yres/unit.
*/
if( write_tag( ed, 0, EXIF_TAG_X_RESOLUTION, EXIF_FORMAT_RATIONAL,
vips_exif_set_double, (void *) &xres ) ||
write_tag( ed, EXIF_TAG_Y_RESOLUTION, EXIF_FORMAT_RATIONAL,
write_tag( ed, 0, EXIF_TAG_Y_RESOLUTION, EXIF_FORMAT_RATIONAL,
vips_exif_set_double, (void *) &yres ) ||
write_tag( ed, EXIF_TAG_RESOLUTION_UNIT, EXIF_FORMAT_SHORT,
write_tag( ed, 0, EXIF_TAG_RESOLUTION_UNIT, EXIF_FORMAT_SHORT,
vips_exif_set_int, (void *) &unit ) ) {
vips_error( "VipsJpeg",
"%s", _( "error setting JPEG resolution" ) );
@ -453,7 +455,9 @@ vips_exif_update_entry( ExifEntry *entry, VipsExif *ve )
char name[256];
char *value;
vips_snprintf( name, 256, "exif-%s", exif_tag_get_title( entry->tag ) );
vips_snprintf( name, 256, "exif-ifd%d-%s",
exif_entry_get_ifd( entry ),
exif_tag_get_title( entry->tag ) );
if( vips_image_get_typeof( ve->image, name ) ) {
(void) vips_image_get_string( ve->image, name, &value );
vips_exif_from_s( ve->ed, entry, value );
@ -539,7 +543,7 @@ write_exif( Write *write )
data_length = idl;
#ifdef DEBUG
printf( "VipsJpeg: attaching %zd bytes of EXIF\n", data_length );
printf( "write_exif: attaching %zd bytes of EXIF\n", data_length );
#endif /*DEBUG*/
exif_data_free( ed );
@ -554,7 +558,7 @@ write_exif( Write *write )
return( -1 );
#ifdef DEBUG
printf( "VipsJpeg: attaching %zd bytes of EXIF\n",
printf( "write_exif: attaching %zd bytes of EXIF\n",
data_length );
#endif /*DEBUG*/
@ -580,7 +584,7 @@ write_xmp( Write *write )
return( -1 );
#ifdef DEBUG
printf( "VipsJpeg: attaching %zd bytes of XMP\n",
printf( "write_xmp: attaching %zd bytes of XMP\n",
data_length );
#endif /*DEBUG*/
@ -677,7 +681,7 @@ write_profile_file( Write *write, const char *profile )
(JOCTET *) write->profile_bytes, write->profile_length );
#ifdef DEBUG
printf( "VipsJpeg: attached profile \"%s\"\n", profile );
printf( "write_profile_file: attached profile \"%s\"\n", profile );
#endif /*DEBUG*/
return( 0 );
@ -696,7 +700,7 @@ write_profile_meta( Write *write )
write_profile_data( &write->cinfo, data, data_length );
#ifdef DEBUG
printf( "VipsJpeg: attached %zd byte profile from VIPS header\n",
printf( "write_profile_meta: attached %zd byte profile from header\n",
data_length );
#endif /*DEBUG*/

View File

@ -34,6 +34,8 @@
* - redone as a class
* - warn about non-int shrinks
* - some tuning .. tried an int coordinate path, not worthwhile
* 16/11/12
* - don't change xres/yres, see comment below
*/
/*
@ -336,11 +338,13 @@ vips_shrink_build( VipsObject *object )
VIPS_DEMAND_STYLE_ANY, resample->in, NULL );
/* Size output. Note: we round the output width down!
*
* Don't change xres/yres, leave that to the application layer. For
* example, vipsthumbnail knows the true shrink factor (including the
* fractional part), we just see the integer part here.
*/
resample->out->Xsize = resample->in->Xsize / shrink->xshrink;
resample->out->Ysize = resample->in->Ysize / shrink->yshrink;
resample->out->Xres = resample->in->Xres / shrink->xshrink;
resample->out->Yres = resample->in->Yres / shrink->yshrink;
if( resample->out->Xsize <= 0 ||
resample->out->Ysize <= 0 ) {
vips_error( class->nickname,