diff --git a/ChangeLog b/ChangeLog index bb2890d6..e4cccc5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +12/10/11 started 7.26.5 +- jpeg read/write copies over XMP data + 12/9/11 started 7.26.4 - fallback vips_init() - im_openout() compat stub was wrong, breaking ruby-vips diff --git a/libvips/format/im_jpeg2vips.c b/libvips/format/im_jpeg2vips.c index e0e2541b..3da27c66 100644 --- a/libvips/format/im_jpeg2vips.c +++ b/libvips/format/im_jpeg2vips.c @@ -35,6 +35,8 @@ * data, some jpegs seem to have several APP1s, argh * 20/4/2011 * - added im_bufjpeg2vips() + * 12/10/2011 + * - read XMP data */ /* @@ -402,16 +404,19 @@ read_exif( IMAGE *im, void *data, int data_length ) { char *data_copy; - /* Horrifyingly, some JPEGs have several APP1 sections. We must only - * use the first one that starts "Exif.." + /* Only use the first one. */ - 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 ) ) + if( im_header_get_typeof( im, IM_META_EXIF_NAME ) ) { +#ifdef DEBUG + printf( "read_exif: second EXIF block, ignoring\n" ); +#endif /*DEBUG*/ + return( 0 ); + } + +#ifdef DEBUG + printf( "read_exif: attaching %d bytes of exif\n", data_length ); +#endif /*DEBUG*/ /* Always attach a copy of the unparsed exif data. */ @@ -464,10 +469,43 @@ read_exif( IMAGE *im, void *data, int data_length ) return( 0 ); } -/* Number of app2 sections we can capture. Each one can be 64k, so 640k should +static int +read_xmp( IMAGE *im, void *data, int data_length ) +{ + char *data_copy; + + /* XMP sections start "http". Only use the first one. + */ + if( im_header_get_typeof( im, VIPS_META_XMP_NAME ) ) { +#ifdef DEBUG + printf( "read_xmp: second XMP block, ignoring\n" ); +#endif /*DEBUG*/ + + return( 0 ); + } + +#ifdef DEBUG + printf( "read_xmp: attaching %d bytes of XMP\n", data_length ); +#endif /*DEBUG*/ + + /* Always attach a copy of the unparsed exif data. + */ + if( !(data_copy = im_malloc( NULL, data_length )) ) + return( -1 ); + memcpy( data_copy, data, data_length ); + if( im_meta_set_blob( im, VIPS_META_XMP_NAME, + (im_callback_fn) im_free, data_copy, data_length ) ) { + im_free( data_copy ); + return( -1 ); + } + + return( 0 ); +} + +/* Number of app2 sections we can capture. Each one can be 64k, so 6400k should * be enough for anyone (haha). */ -#define MAX_APP2_SECTIONS (10) +#define MAX_APP2_SECTIONS (100) /* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to * do 255-pel. @@ -532,26 +570,38 @@ read_jpeg_header( struct jpeg_decompress_struct *cinfo, /* Look for EXIF and ICC profile. */ for( p = cinfo->marker_list; p; p = p->next ) { +#ifdef DEBUG +{ + int i; + + printf( "read_jpeg_header: seen %d bytes of APP%d\n", + p->data_length, + p->marker - JPEG_APP0 ); + + for( i = 0; i < 10; i++ ) + printf( "\t%d) '%c' (%d)\n", + i, p->data[i], p->data[i] ); +} +#endif /*DEBUG*/ + switch( p->marker ) { case JPEG_APP0 + 1: - /* EXIF data. + /* Possible EXIF or XMP data. */ -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of APP1\n", - p->data_length ); -#endif /*DEBUG*/ - if( read_exif( out, p->data, p->data_length ) ) + if( p->data_length > 4 && + im_isprefix( "Exif", (char *) p->data ) && + read_exif( out, p->data, p->data_length ) ) return( -1 ); + + if( p->data_length > 4 && + im_isprefix( "http", (char *) p->data ) && + read_xmp( out, p->data, p->data_length ) ) + break; case JPEG_APP0 + 2: /* ICC profile. */ -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of APP2\n", - p->data_length ); -#endif /*DEBUG*/ - if( p->data_length > 14 && im_isprefix( "ICC_PROFILE", (char *) p->data ) ) { @@ -570,10 +620,6 @@ read_jpeg_header( struct jpeg_decompress_struct *cinfo, break; default: -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of data\n", - p->data_length ); -#endif /*DEBUG*/ break; } } diff --git a/libvips/format/im_vips2jpeg.c b/libvips/format/im_vips2jpeg.c index 7769b1f9..abf8eb9a 100644 --- a/libvips/format/im_vips2jpeg.c +++ b/libvips/format/im_vips2jpeg.c @@ -40,6 +40,8 @@ * longer overallocate or underallocate * 8/7/11 * - oop CMYK write was not inverting, thanks Ole + * 12/10/2011 + * - write XMP data */ /* @@ -413,7 +415,7 @@ write_exif( Write *write ) return( -1 ); #ifdef DEBUG - printf( "im_vips2jpeg: attaching %d bytes of EXIF\n", + printf( "im_vips2jpeg: attaching %zd bytes of EXIF\n", data_length ); #endif /*DEBUG*/ @@ -425,6 +427,31 @@ write_exif( Write *write ) return( 0 ); } +static int +write_xmp( Write *write ) +{ + unsigned char *data; + size_t data_length; + + /* No libexif ... just copy the embedded EXIF over. + */ + if( im_header_get_typeof( write->in, VIPS_META_XMP_NAME ) ) { + if( im_meta_get_blob( write->in, VIPS_META_XMP_NAME, + (void *) &data, &data_length ) ) + return( -1 ); + +#ifdef DEBUG + printf( "im_vips2jpeg: attaching %zd bytes of XMP\n", + data_length ); +#endif /*DEBUG*/ + + jpeg_write_marker( &write->cinfo, JPEG_APP0 + 1, + data, data_length ); + } + + return( 0 ); +} + /* ICC writer from lcms, slight tweaks. */ @@ -629,6 +656,9 @@ write_vips( Write *write, int qfac, const char *profile ) if( write_exif( write ) ) return( -1 ); + if( write_xmp( write ) ) + return( -1 ); + /* A profile supplied as an argument overrides an embedded profile. * "none" means don't attach a profile. */ diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index 3ab9f554..d082fd97 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -44,6 +44,13 @@ extern "C" { */ #define VIPS_META_EXIF_NAME "exif-data" +/** + * VIPS_META_XMP_NAME: + * + * The name that JPEG read and write operations use for the image's XMP data. + */ +#define VIPS_META_XMP_NAME "xmp-data" + /** * VIPS_META_ICC_NAME: *