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:
parent
717266ad2b
commit
fcc33020bd
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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*/
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user