done, just a few things left

- tif->jpg copy seems to loose tag

- add tests
This commit is contained in:
John Cupitt 2016-05-27 09:48:08 +01:00
parent 5a9f2c787b
commit 094470c9c1
6 changed files with 117 additions and 108 deletions

31
TODO
View File

@ -1,33 +1,14 @@
- set tiff orientation tag on write, also copy orientation between tiff iamges
- save a 16-bit image to tiff with jpg compression ... should it autoconvert?
- switch jpeg read/write over to new orientation tag
- try
- support orientation tag in tiff images
vips copy orientation-test.jpg x.tif
vips copy x.tif x.jpg
see
orientation tag not preserved for tif->jpg
http://www.awaresystems.be/imaging/tiff/tifftags/orientation.html
- add a set of tests for orientation
seems to be the same values used for exif
jpg uses "exif-ifd0-Orientation", see conversion/autorot.c
instead, standardize on "orientation" and give it an int value
VIPS_META_ORIENTATION
jpg load and save need to use this in preference to the exif value
tiff load and save need to set and recover this value
tiff load needs an autorot flag
don't touch parse_header()
on header-only read, just swap width/height and delete the tag
on full image read, use read_jpeg_rotate(), broken out into a separate
func
see https://github.com/jcupitt/libvips/issues/243

View File

@ -59,42 +59,6 @@ typedef VipsConversionClass VipsAutorotClass;
G_DEFINE_TYPE( VipsAutorot, vips_autorot, VIPS_TYPE_CONVERSION );
static void *
vips_autorot_get_angle_sub( VipsImage *image,
const char *field, GValue *value, void *my_data )
{
VipsAngle *angle = (VipsAngle *) my_data;
const char *orientation;
if( vips_isprefix( "exif-", field ) &&
vips_ispostfix( field, "-Orientation" ) &&
!vips_image_get_string( image, field, &orientation ) ) {
if( vips_isprefix( "6", orientation ) )
*angle = VIPS_ANGLE_D90;
else if( vips_isprefix( "8", orientation ) )
*angle = VIPS_ANGLE_D270;
else if( vips_isprefix( "3", orientation ) )
*angle = VIPS_ANGLE_D180;
else
*angle = VIPS_ANGLE_D0;
/* Other values do rotate + mirror, don't bother handling them
* though, how common can mirroring be.
*
* See:
*
* http://www.80sidea.com/archives/2316
*/
/* Stop searching.
*/
return( image );
}
return( NULL );
}
/**
* vips_autorot_get_angle:
* @image: image to fetch orientation from
@ -107,18 +71,40 @@ vips_autorot_get_angle_sub( VipsImage *image,
* Returns: the #VipsAngle to rotate by to make the image upright.
*/
VipsAngle
vips_autorot_get_angle( VipsImage *image )
vips_autorot_get_angle( VipsImage *im )
{
int orientation;
VipsAngle angle;
angle = VIPS_ANGLE_D0;
(void) vips_image_map( image, vips_autorot_get_angle_sub, &angle );
if( vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) )
orientation = 1;
#ifdef DEBUG
printf( "vips_autorot_get_angle: %d\n", angle );
#endif /*DEBUG*/
switch( orientation ) {
case 6:
angle = VIPS_ANGLE_D90;
break;
return( angle );
case 8:
angle = VIPS_ANGLE_D270;
break;
case 3:
angle = VIPS_ANGLE_D180;
break;
default:
/* Other values do rotate + mirror, don't bother handling them
* though, how common can mirroring be.
*
* See:
*
* http://www.80sidea.com/archives/2316
*/
angle = VIPS_ANGLE_D0;
break;
}
return( angle );
}
static void *
@ -141,13 +127,14 @@ vips_autorot_remove_angle_sub( VipsImage *image,
* vips_autorot_remove_angle:
* @im: image to remove orientation from
*
* Remove any EXIF tag on @im which looks like orientation.
* Remove the orientation tag on @im. Also remove any exif orientation tags.
*
* See also: vips_autorot_get_angle().
*/
void
vips_autorot_remove_angle( VipsImage *image )
{
(void) vips_image_remove( image, VIPS_META_ORIENTATION );
(void) vips_image_map( image, vips_autorot_remove_angle_sub, NULL );
}

View File

@ -72,6 +72,8 @@
* 21/2/16
* - _destroy the decompress object as soon as we can, frees loads of
* memory for progressive jpg files
* 26/5/16
* - switch to new orientation tag
*/
/*
@ -692,6 +694,27 @@ attach_blob( VipsImage *im, const char *field, void *data, int data_length )
return( 0 );
}
static void *
read_jpeg_orientation_sub( VipsImage *image,
const char *field, GValue *value, void *data )
{
const char *orientation_str;
if( vips_isprefix( "exif-", field ) &&
vips_ispostfix( field, "-Orientation" ) &&
!vips_image_get_string( image, field, &orientation_str ) ) {
int orientation;
orientation = atoi( orientation_str );
orientation = VIPS_CLIP( 1, orientation, 8 );
vips_image_set_int( image, VIPS_META_ORIENTATION, orientation );
return( image );
}
return( NULL );
}
/* Number of app2 sections we can capture. Each one can be 64k, so 6400k should
* be enough for anyone (haha).
*/
@ -911,6 +934,12 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
(VipsCallbackFn) vips_free, data, data_length );
}
/* Orientation handling. We look for the first Orientation EXIF tag
* (there can be many of them) and use that to set our own
* VIPS_META_ORIENTATION.
*/
(void) vips_image_map( out, read_jpeg_orientation_sub, NULL );
return( 0 );
}
@ -991,8 +1020,6 @@ read_jpeg_generate( VipsRegion *or,
return( 0 );
}
#define ORIENTATION ("exif-ifd0-Orientation")
/* Auto-rotate, if rotate_image is set.
*/
static VipsImage *
@ -1016,7 +1043,8 @@ read_jpeg_rotate( VipsObject *process, VipsImage *im )
vips_rot( t[0], &t[1], angle, NULL ) )
return( NULL );
im = t[1];
(void) vips_image_remove( im, ORIENTATION );
vips_autorot_remove_angle( im );
}
return( im );
@ -1085,7 +1113,7 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
{
int i;
/* Handy for debubgging ... spot any extra markers.
/* Handy for debugging ... spot any extra markers.
*/
for( i = 0; i < 16; i++ )
jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + i, 0xffff );
@ -1109,7 +1137,7 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
/* We won't be returning an orientation tag.
*/
(void) vips_image_remove( out, ORIENTATION );
vips_autorot_remove_angle( out );
}
}
else {

View File

@ -1433,41 +1433,10 @@ tiff_seq_stop( void *seq, void *a, void *b )
/* Auto-rotate handling.
*/
static VipsAngle
vips_tiff_get_angle( VipsImage *im )
{
int orientation;
VipsAngle angle;
if( vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) )
orientation = 1;
switch( orientation ) {
case 6:
angle = VIPS_ANGLE_D90;
break;
case 8:
angle = VIPS_ANGLE_D270;
break;
case 3:
angle = VIPS_ANGLE_D180;
break;
default:
angle = VIPS_ANGLE_D0;
break;
}
return( angle );
}
static int
vips_tiff_autorotate( ReadTiff *rtiff, VipsImage *in, VipsImage **out )
{
VipsAngle angle = vips_tiff_get_angle( in );
VipsAngle angle = vips_autorot_get_angle( in );
if( rtiff->autorotate &&
angle != VIPS_ANGLE_D0 ) {
@ -1490,10 +1459,10 @@ vips_tiff_autorotate( ReadTiff *rtiff, VipsImage *in, VipsImage **out )
}
g_object_unref( x );
/* We must remove VIPS_META_ORIENTATION to prevent accidental
/* We must remove the tag to prevent accidental
* double rotations.
*/
(void) vips_image_remove( *out, VIPS_META_ORIENTATION );
vips_autorot_remove_angle( *out );
}
else {
*out = in;

View File

@ -76,6 +76,8 @@
* - remove deleted exif fields more carefully
* 9/5/16 felixbuenemann
* - add quant_table
* 26/5/16
* - switch to new orientation tag
*/
/*
@ -531,6 +533,27 @@ set_exif_dimensions( ExifData *ed, VipsImage *im )
return( 0 );
}
/* And orientation.
*/
static int
set_exif_orientation( ExifData *ed, VipsImage *im )
{
int orientation;
/* We set the tag, even if it's been deleted, since it's a required
* field.
*/
if( !vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) )
orientation = 1;
VIPS_DEBUG_MSG( "set_exif_orientation: %d\n", orientation );
write_tag( ed, 0, EXIF_TAG_ORIENTATION,
vips_exif_set_int, (void *) &orientation );
return( 0 );
}
/* See also vips_exif_to_s() ... keep in sync.
*/
static void
@ -655,6 +678,14 @@ vips_exif_exif_entry( ExifEntry *entry, VipsExif *ve )
*/
if( !vips_image_get_typeof( ve->image, vips_buf_all( &vips_name ) ) )
ve->to_remove = g_slist_prepend( ve->to_remove, entry );
/* Orientation is really set from the vips
* VIPS_META_ORIENTATION tag. If that's been deleted, we must delete
* any matching EXIF tags too.
*/
if( strcmp( tag_name, "Orientation" ) == 0 &&
vips_image_get_typeof( ve->image, VIPS_META_ORIENTATION ) )
ve->to_remove = g_slist_prepend( ve->to_remove, entry );
}
static void *
@ -802,6 +833,13 @@ write_exif( Write *write )
return( -1 );
}
/* Update EXIF orientation from the vips image header.
*/
if( set_exif_orientation( ed, write->in ) ) {
exif_data_free( ed );
return( -1 );
}
/* Reserialise and write. exif_data_save_data() returns an int for some
* reason.
*/

View File

@ -554,6 +554,7 @@ write_tiff_header( Write *write, Layer *layer )
TIFF *tif = layer->tif;
int format;
int orientation;
/* Output base header fields.
*/
@ -584,6 +585,10 @@ write_tiff_header( Write *write, Layer *layer )
write_embed_imagedescription( write, tif ) )
return( -1 );
if( !vips_image_get_int( write->im,
VIPS_META_ORIENTATION, &orientation ) )
TIFFSetField( tif, TIFFTAG_ORIENTATION, orientation );
/* And colour fields.
*/
if( write->im->Coding == VIPS_CODING_LABQ ) {
@ -1497,6 +1502,7 @@ write_copy_tiff( Write *write, TIFF *out, TIFF *in )
CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 );
CopyField( TIFFTAG_BITSPERSAMPLE, i16 );
CopyField( TIFFTAG_PHOTOMETRIC, i16 );
CopyField( TIFFTAG_ORIENTATION, i16 );
CopyField( TIFFTAG_TILEWIDTH, i32 );
CopyField( TIFFTAG_TILELENGTH, i32 );
CopyField( TIFFTAG_ROWSPERSTRIP, i32 );