im_jpeg2vips() ignores weird APP1 chunks

Some JPEGs seem to have multiple APP1 chunks. There should only be one,
and it should only contain EXIF data (I think), but some seem to have
many.

This was causing problems: the loader was trying to read exif
from all chunks, and a second chunk with invalid data was zapping the
stored exif meta tag. As a result, things like

  vips im_copy a.jpg b.jpg

would appear to lose EXIF info if a.jpg had spurious APP1.
This commit is contained in:
John Cupitt 2011-02-21 17:01:00 +00:00
parent d5d312aa91
commit a7d2288bad
4 changed files with 27 additions and 18 deletions

View File

@ -31,6 +31,7 @@
- set MAP_NOCACHE on OS X, otherwise performance dives off a cliff with - set MAP_NOCACHE on OS X, otherwise performance dives off a cliff with
files larger than memory files larger than memory
- removed man pages, we are all gtk-doc now - removed man pages, we are all gtk-doc now
- im_jpeg2vips() ignores weird APP1 chunks
30/11/10 started 7.24.0 30/11/10 started 7.24.0
- bump for new stable - bump for new stable

View File

@ -30,6 +30,9 @@
* - gtkdoc * - gtkdoc
* 4/12/10 * 4/12/10
* - attach the jpeg thumbnail and multiscan fields (thanks Mike) * - attach the jpeg thumbnail and multiscan fields (thanks Mike)
* 21/2/10
* - only accept the first APP1 block which starts "Exif..." as exif
* data, some jpegs seem to have several APP1s, argh
*/ */
/* /*
@ -59,8 +62,8 @@
*/ */
/* /*
#define DEBUG
#define DEBUG_VERBOSE #define DEBUG_VERBOSE
#define DEBUG
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -396,7 +399,18 @@ attach_thumbnail( IMAGE *im, ExifData *ed )
static int static int
read_exif( IMAGE *im, void *data, int data_length ) read_exif( IMAGE *im, void *data, int data_length )
{ {
char *data_copy; char *data_copy;
/* Horrifyingly, some JPEGs have several APP1 sections. We must only
* use the first one that starts "Exif.."
*/
if( ((char *) data)[0] != 'E' ||
((char *) data)[1] != 'x' ||
((char *) data)[2] != 'i' ||
((char *) data)[3] != 'f' )
return( 0 );
if( im_header_get_typeof( im, IM_META_EXIF_NAME ) )
return( 0 );
/* Always attach a copy of the unparsed exif data. /* Always attach a copy of the unparsed exif data.
*/ */
@ -424,10 +438,11 @@ char *data_copy;
/* Attach informational fields for what we find. /* Attach informational fields for what we find.
FIXME ... better to have this in the UI layer? FIXME ... better to have this in the UI layer?
Or we could attach non-human-readable tags here (int, double Or we could attach non-human-readable tags here (int,
etc) and then move the human stuff to the UI layer? double etc) and then move the human stuff to the UI
layer?
*/ */
exif_data_foreach_content( ed, exif_data_foreach_content( ed,
@ -521,7 +536,7 @@ read_jpeg_header( struct jpeg_decompress_struct *cinfo,
/* EXIF data. /* EXIF data.
*/ */
#ifdef DEBUG #ifdef DEBUG
printf( "read_jpeg_header: seen %d bytes of EXIF\n", printf( "read_jpeg_header: seen %d bytes of APP1\n",
p->data_length ); p->data_length );
#endif /*DEBUG*/ #endif /*DEBUG*/
if( read_exif( out, p->data, p->data_length ) ) if( read_exif( out, p->data, p->data_length ) )
@ -532,7 +547,7 @@ read_jpeg_header( struct jpeg_decompress_struct *cinfo,
/* ICC profile. /* ICC profile.
*/ */
#ifdef DEBUG #ifdef DEBUG
printf( "read_jpeg_header: seen %d bytes of ICC\n", printf( "read_jpeg_header: seen %d bytes of APP2\n",
p->data_length ); p->data_length );
#endif /*DEBUG*/ #endif /*DEBUG*/

View File

@ -376,7 +376,7 @@ write_exif( Write *write )
else else
ed = exif_data_new(); ed = exif_data_new();
/* Set EXIF resolution from VIPS. /* Update EXIF resolution from VIPS.
*/ */
if( set_exif_resolution( ed, write->in ) ) { if( set_exif_resolution( ed, write->in ) ) {
exif_data_free( ed ); exif_data_free( ed );

View File

@ -1,13 +1,4 @@
/* @(#) Function which copies IMAGE descriptor image2 to image1; /* copy descriptors between images
* @(#) data, fd and filename are not copied
* @(#) used to make programs simpler by copying most parameters
* @(#)
* @(#) int
* @(#) im_cp_desc( image1, image2 )
* @(#) IMAGE *image1, *image2;
* @(#)
* @(#) Returns 0 on success or -1 on fail.
* @(#)
* *
* Copyright: Nicos Dessipris * Copyright: Nicos Dessipris
* Written on: 09/02/1990 * Written on: 09/02/1990
@ -30,6 +21,8 @@
* - simplified ... no more skip the first line stuff * - simplified ... no more skip the first line stuff
* 4/1/07 * 4/1/07
* - merge hists with history_list instead * - merge hists with history_list instead
* 20/1/10
* - gtk-doc
*/ */
/* /*