done, just a few things left
- tif->jpg copy seems to loose tag - add tests
This commit is contained in:
parent
5a9f2c787b
commit
094470c9c1
31
TODO
31
TODO
|
@ -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
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue