revise autorot system
- deprecate vips_autorot_get_angle() since orientation is no longer a simple rotate - add vips_image_get_orientation() and vips_image_get_orientation_swap() - revise tiff and jpeg loader autorotate to just call vips_autorot(), but only if necessary - revise thumbnail autorotate too
This commit is contained in:
parent
30386db775
commit
981d5c4b16
@ -24,6 +24,8 @@
|
||||
behaviour with alpha channels
|
||||
- improve bioformats support with read and write of tiff subifd pyramids
|
||||
- thumbnail exploits subifd pyramids
|
||||
- handle all EXIF orientation cases, deprecate
|
||||
vips_autorot_get_angle() [Elad-Laufer]
|
||||
|
||||
24/4/20 started 8.9.3
|
||||
- better iiif tile naming [IllyaMoskvin]
|
||||
|
@ -8,6 +8,7 @@
|
||||
* - don't remove orientation if it's one of the cases we don't handle
|
||||
* 10/5/20
|
||||
* - handle mirrored images
|
||||
* - deprecate vips_autorot_get_angle()
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -56,8 +57,7 @@ typedef struct _VipsAutorot {
|
||||
VipsImage *in;
|
||||
|
||||
VipsAngle angle;
|
||||
|
||||
gboolean flip;
|
||||
gboolean flip;
|
||||
|
||||
} VipsAutorot;
|
||||
|
||||
@ -65,51 +65,6 @@ typedef VipsConversionClass VipsAutorotClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsAutorot, vips_autorot, VIPS_TYPE_CONVERSION );
|
||||
|
||||
/**
|
||||
* vips_autorot_get_angle:
|
||||
* @image: image to fetch orientation from
|
||||
*
|
||||
* Examine the metadata on @im and return the #VipsAngle to rotate by to turn
|
||||
* the image upright.
|
||||
*
|
||||
* See also: vips_autorot().
|
||||
*
|
||||
* Returns: the #VipsAngle to rotate by to make the image upright.
|
||||
*/
|
||||
VipsAngle
|
||||
vips_autorot_get_angle( VipsImage *im )
|
||||
{
|
||||
int orientation;
|
||||
VipsAngle angle;
|
||||
|
||||
if( !vips_image_get_typeof( im, VIPS_META_ORIENTATION ) ||
|
||||
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:
|
||||
/* Other values do rotate + mirror, don't bother handling them
|
||||
* though, how common can mirroring be.
|
||||
*/
|
||||
angle = VIPS_ANGLE_D0;
|
||||
break;
|
||||
}
|
||||
|
||||
return( angle );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_autorot_remove_angle_sub( VipsImage *image,
|
||||
const char *field, GValue *value, void *my_data )
|
||||
@ -130,14 +85,14 @@ vips_autorot_remove_angle_sub( VipsImage *image,
|
||||
* vips_autorot_remove_angle: (method)
|
||||
* @image: image to remove orientation from
|
||||
*
|
||||
* Remove the orientation tag on @image. Also remove any exif orientation tags.
|
||||
*
|
||||
* See also: vips_autorot_get_angle().
|
||||
* Remove the orientation tag on @image. Also remove any exif orientation tags.
|
||||
* You must vips_copy() the image before calling this function since it
|
||||
* modifies metadata.
|
||||
*/
|
||||
void
|
||||
vips_autorot_remove_angle( VipsImage *image )
|
||||
{
|
||||
(void) vips_image_remove( image, VIPS_META_ORIENTATION );
|
||||
(void) vips_image_remove( image, VIPS_META_ORIENTATION );
|
||||
(void) vips_image_map( image, vips_autorot_remove_angle_sub, NULL );
|
||||
}
|
||||
|
||||
@ -151,88 +106,82 @@ vips_autorot_build( VipsObject *object )
|
||||
if( VIPS_OBJECT_CLASS( vips_autorot_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
int orientation = 0;
|
||||
VipsAngle angle;
|
||||
gboolean flip = FALSE;
|
||||
|
||||
if( !vips_image_get_typeof( autorot->in, VIPS_META_ORIENTATION ) ||
|
||||
vips_image_get_int( autorot->in, VIPS_META_ORIENTATION, &orientation ) )
|
||||
orientation = 1;
|
||||
VipsAngle angle;
|
||||
gboolean flip;
|
||||
VipsImage *in;
|
||||
|
||||
switch( orientation ) {
|
||||
in = autorot->in;
|
||||
|
||||
case 2:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = TRUE;
|
||||
break;
|
||||
switch( vips_image_get_orientation( in ) ) {
|
||||
case 2:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
flip = TRUE;
|
||||
case 3:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
flip = TRUE;
|
||||
case 4:
|
||||
angle = VIPS_ANGLE_D180;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
flip = TRUE;
|
||||
case 5:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
break;
|
||||
|
||||
default:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
}
|
||||
case 6:
|
||||
angle = VIPS_ANGLE_D90;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
g_object_set( object,
|
||||
"angle", angle,
|
||||
NULL );
|
||||
case 7:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
flip = TRUE;
|
||||
break;
|
||||
|
||||
g_object_set( object,
|
||||
"flip", flip,
|
||||
NULL );
|
||||
case 8:
|
||||
angle = VIPS_ANGLE_D270;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
if( angle != VIPS_ANGLE_D0 && flip) {
|
||||
if( vips_rot( autorot->in, &t[0], angle, NULL ) )
|
||||
return( -1 );
|
||||
case 1:
|
||||
default:
|
||||
angle = VIPS_ANGLE_D0;
|
||||
flip = FALSE;
|
||||
break;
|
||||
|
||||
if( vips_flip( t[0], &t[1], VIPS_DIRECTION_HORIZONTAL, NULL ) )
|
||||
return ( -1 );
|
||||
}
|
||||
|
||||
if( vips_copy( t[1], &t[2], NULL ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( angle != VIPS_ANGLE_D0 ) {
|
||||
if( vips_rot( autorot->in, &t[0], angle, NULL))
|
||||
return ( -1 );
|
||||
g_object_set( object,
|
||||
"angle", angle,
|
||||
"flip", flip,
|
||||
NULL );
|
||||
|
||||
if( vips_copy( t[0], &t[2], NULL))
|
||||
return ( -1 );
|
||||
}
|
||||
else if( flip ) {
|
||||
if( vips_flip( autorot->in, &t[0], VIPS_DIRECTION_HORIZONTAL, NULL ) )
|
||||
return ( -1 );
|
||||
if( angle != VIPS_ANGLE_D0 ) {
|
||||
if( vips_rot( in, &t[0], angle, NULL ) )
|
||||
return( -1 );
|
||||
in = t[0];
|
||||
}
|
||||
|
||||
if( vips_copy( t[0], &t[2], NULL ) )
|
||||
return( -1 );
|
||||
} else {
|
||||
if( vips_copy( autorot->in, &t[2], NULL ) )
|
||||
return( -1 );
|
||||
}
|
||||
if( flip ) {
|
||||
if( vips_flip( in, &t[1], VIPS_DIRECTION_HORIZONTAL, NULL ) )
|
||||
return( -1 );
|
||||
in = t[1];
|
||||
}
|
||||
|
||||
vips_autorot_remove_angle( t[2] );
|
||||
|
||||
if( vips_image_write( t[2], conversion->out ) )
|
||||
/* We must copy before modifying metadata.
|
||||
*/
|
||||
if( vips_copy( in, &t[2], NULL ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
vips_autorot_remove_angle( in );
|
||||
|
||||
if( vips_image_write( in, conversion->out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -265,11 +214,11 @@ vips_autorot_class_init( VipsAutorotClass *class )
|
||||
VIPS_TYPE_ANGLE, VIPS_ANGLE_D0 );
|
||||
|
||||
VIPS_ARG_BOOL( class, "flip", 7,
|
||||
_( "Flip" ),
|
||||
_( "Whether the image was flipped or not" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsAutorot, flip ),
|
||||
FALSE);
|
||||
_( "Flip" ),
|
||||
_( "Whether the image was flipped or not" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsAutorot, flip ),
|
||||
FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -288,15 +237,14 @@ vips_autorot_init( VipsAutorot *autorot )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @angle: output #VipsAngle the image was rotated by
|
||||
* * @flip: output whether the image was flipped
|
||||
* * @flip: output %gboolean whether the image was flipped
|
||||
*
|
||||
* Look at the image metadata and rotate the image to make it upright. The
|
||||
* #VIPS_META_ORIENTATION tag is removed from @out to prevent accidental
|
||||
* double rotation.
|
||||
* Look at the image metadata and rotate and flip the image to make it
|
||||
* upright. The #VIPS_META_ORIENTATION tag is removed from @out to prevent
|
||||
* accidental double rotation.
|
||||
*
|
||||
* Read @angle to find the amount the image was rotated by.
|
||||
*
|
||||
* See also: vips_autorot_get_angle(), vips_autorot_remove_angle(), vips_rot().
|
||||
* Read @angle to find the amount the image was rotated by. Read @flip to
|
||||
* see if the image was also flipped.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -801,3 +801,15 @@ vips_warn( const char *domain, const char *fmt, ... )
|
||||
va_end( ap );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_autorot_get_angle:
|
||||
* @image: image to fetch orientation from
|
||||
*
|
||||
* This function is deprecated. Use vips_autorot() instead.
|
||||
*/
|
||||
VipsAngle
|
||||
vips_autorot_get_angle( VipsImage *im )
|
||||
{
|
||||
return( VIPS_ANGLE_D0 );
|
||||
}
|
||||
|
||||
|
@ -523,7 +523,8 @@ vips__exif_parse( VipsImage *image )
|
||||
int orientation;
|
||||
|
||||
orientation = atoi( str );
|
||||
if( orientation < 1 || orientation > 8 )
|
||||
if( orientation < 1 ||
|
||||
orientation > 8 )
|
||||
orientation = 1;
|
||||
vips_image_set_int( image, VIPS_META_ORIENTATION, orientation );
|
||||
}
|
||||
|
@ -830,40 +830,6 @@ read_jpeg_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Auto-rotate, if rotate_image is set.
|
||||
*/
|
||||
static VipsImage *
|
||||
read_jpeg_rotate( VipsObject *process, VipsImage *im )
|
||||
{
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( process, 3 );
|
||||
VipsAngle angle = vips_autorot_get_angle( im );
|
||||
|
||||
if( angle != VIPS_ANGLE_D0 ) {
|
||||
/* Need to copy to memory or disc, we have to stay seq.
|
||||
*/
|
||||
const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE( im );
|
||||
const guint64 disc_threshold = vips_get_disc_threshold();
|
||||
|
||||
if( image_size > disc_threshold )
|
||||
t[0] = vips_image_new_temp_file( "%s.v" );
|
||||
else
|
||||
t[0] = vips_image_new_memory();
|
||||
|
||||
if( vips_image_write( im, t[0] ) ||
|
||||
vips_rot( t[0], &t[1], angle, NULL ) )
|
||||
return( NULL );
|
||||
im = t[1];
|
||||
|
||||
if( vips_copy( im, &t[2], NULL ) )
|
||||
return( NULL );
|
||||
im = t[2];
|
||||
|
||||
vips_autorot_remove_angle( im );
|
||||
}
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Read a cinfo to a VIPS image.
|
||||
*/
|
||||
static int
|
||||
@ -871,7 +837,7 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
{
|
||||
struct jpeg_decompress_struct *cinfo = &jpeg->cinfo;
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 3 );
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *im;
|
||||
|
||||
@ -902,10 +868,16 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
vips_extract_area( t[1], &t[2],
|
||||
0, 0, jpeg->output_width, jpeg->output_height, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
im = t[2];
|
||||
if( jpeg->autorotate )
|
||||
im = read_jpeg_rotate( VIPS_OBJECT( out ), im );
|
||||
|
||||
if( jpeg->autorotate &&
|
||||
vips_image_get_orientation( im ) != 1 ) {
|
||||
/* This will go via a huge memory buffer :-(
|
||||
*/
|
||||
if( vips_autorot( im, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
im = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( im, out ) )
|
||||
return( -1 );
|
||||
@ -948,15 +920,9 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
|
||||
|
||||
/* Swap width and height if we're going to rotate this image.
|
||||
*/
|
||||
if( jpeg->autorotate ) {
|
||||
VipsAngle angle = vips_autorot_get_angle( out );
|
||||
|
||||
if( angle == VIPS_ANGLE_D90 ||
|
||||
angle == VIPS_ANGLE_D270 )
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
|
||||
/* We won't be returning an orientation tag.
|
||||
*/
|
||||
if( jpeg->autorotate &&
|
||||
vips_image_get_orientation_swap( out ) ) {
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
vips_autorot_remove_angle( out );
|
||||
}
|
||||
}
|
||||
|
@ -1862,59 +1862,6 @@ rtiff_seq_stop( void *seq, void *a, void *b )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Auto-rotate handling.
|
||||
*/
|
||||
static int
|
||||
rtiff_autorotate( Rtiff *rtiff, VipsImage *in, VipsImage **out )
|
||||
{
|
||||
VipsAngle angle = vips_autorot_get_angle( in );
|
||||
|
||||
if( rtiff->autorotate &&
|
||||
angle != VIPS_ANGLE_D0 ) {
|
||||
/* Need to copy to memory or disc, we have to stay seq.
|
||||
*/
|
||||
const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE( in );
|
||||
const guint64 disc_threshold = vips_get_disc_threshold();
|
||||
|
||||
VipsImage *im;
|
||||
VipsImage *x;
|
||||
|
||||
if( image_size > disc_threshold )
|
||||
im = vips_image_new_temp_file( "%s.v" );
|
||||
else
|
||||
im = vips_image_new_memory();
|
||||
|
||||
if( vips_image_write( in, im ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_rot( im, &x, angle, NULL ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( im );
|
||||
im = x;
|
||||
|
||||
if( vips_copy( im, out, NULL ) ) {
|
||||
g_object_unref( im );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( im );
|
||||
|
||||
/* We must remove the tag to prevent accidental
|
||||
* double rotations.
|
||||
*/
|
||||
vips_autorot_remove_angle( *out );
|
||||
}
|
||||
else {
|
||||
*out = in;
|
||||
g_object_ref( in );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Unpremultiply associative alpha, if any.
|
||||
*/
|
||||
static int
|
||||
@ -1952,6 +1899,8 @@ rtiff_read_tilewise( Rtiff *rtiff, VipsImage *out )
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: rtiff_read_tilewise\n" );
|
||||
#endif /*DEBUG*/
|
||||
@ -1991,21 +1940,31 @@ rtiff_read_tilewise( Rtiff *rtiff, VipsImage *out )
|
||||
*/
|
||||
vips_image_pipelinev( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||
|
||||
if( vips_image_generate( t[0],
|
||||
rtiff_seq_start, rtiff_fill_region, rtiff_seq_stop,
|
||||
rtiff, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Copy to out, adding a cache. Enough tiles for two complete rows.
|
||||
/* Generate to out, adding a cache. Enough tiles for two complete rows.
|
||||
*/
|
||||
if( vips_tilecache( t[0], &t[1],
|
||||
"tile_width", tile_width,
|
||||
"tile_height", tile_height,
|
||||
"max_tiles", 2 * (1 + t[0]->Xsize / tile_width),
|
||||
NULL ) ||
|
||||
rtiff_autorotate( rtiff, t[1], &t[2] ) ||
|
||||
rtiff_unpremultiply( rtiff, t[2], &t[3] ) ||
|
||||
vips_image_write( t[3], out ) )
|
||||
if(
|
||||
vips_image_generate( t[0],
|
||||
rtiff_seq_start, rtiff_fill_region, rtiff_seq_stop,
|
||||
rtiff, NULL ) ||
|
||||
vips_tilecache( t[0], &t[1],
|
||||
"tile_width", tile_width,
|
||||
"tile_height", tile_height,
|
||||
"max_tiles", 2 * (1 + t[0]->Xsize / tile_width),
|
||||
NULL ) ||
|
||||
rtiff_unpremultiply( rtiff, t[1], &t[2] ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
/* Only do this if we have to.
|
||||
*/
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation( in ) != 1 ) {
|
||||
if( vips_autorot( in, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
in = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -2226,6 +2185,8 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out )
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 4 );
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "tiff2vips: rtiff_read_stripwise\n" );
|
||||
#endif /*DEBUG*/
|
||||
@ -2301,9 +2262,20 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out )
|
||||
vips_sequential( t[0], &t[1],
|
||||
"tile_height", rtiff->header.read_height,
|
||||
NULL ) ||
|
||||
rtiff_autorotate( rtiff, t[1], &t[2] ) ||
|
||||
rtiff_unpremultiply( rtiff, t[2], &t[3] ) ||
|
||||
vips_image_write( t[3], out ) )
|
||||
rtiff_unpremultiply( rtiff, t[1], &t[2] ) )
|
||||
return( -1 );
|
||||
in = t[2];
|
||||
|
||||
/* Only do this if we have to.
|
||||
*/
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation( in ) != 1 ) {
|
||||
if( vips_autorot( in, &t[3], NULL ) )
|
||||
return( -1 );
|
||||
in = t[3];
|
||||
}
|
||||
|
||||
if( vips_image_write( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -2683,29 +2655,6 @@ rtiff_header_read_all( Rtiff *rtiff )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* On a header-only read, we can just swap width/height if orientation is 6 or
|
||||
* 8.
|
||||
*/
|
||||
static void
|
||||
vips__tiff_read_header_orientation( Rtiff *rtiff, VipsImage *out )
|
||||
{
|
||||
int orientation;
|
||||
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_typeof( out, VIPS_META_ORIENTATION ) &&
|
||||
!vips_image_get_int( out,
|
||||
VIPS_META_ORIENTATION, &orientation ) ) {
|
||||
if( orientation == 3 ||
|
||||
orientation == 6 )
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
|
||||
/* We must remove VIPS_META_ORIENTATION to prevent accidental
|
||||
* double rotations.
|
||||
*/
|
||||
vips_image_remove( out, VIPS_META_ORIENTATION );
|
||||
}
|
||||
}
|
||||
|
||||
typedef gboolean (*TiffPropertyFn)( TIFF *tif );
|
||||
|
||||
static gboolean
|
||||
@ -2755,7 +2704,11 @@ vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
if( rtiff_set_header( rtiff, out ) )
|
||||
return( -1 );
|
||||
|
||||
vips__tiff_read_header_orientation( rtiff, out );
|
||||
if( rtiff->autorotate &&
|
||||
vips_image_get_orientation_swap( out ) ) {
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize );
|
||||
vips_autorot_remove_angle( out );
|
||||
}
|
||||
|
||||
/* We never call vips_source_decode() since we need to be able to
|
||||
* seek() the whole way through the file. Just minimise instead,
|
||||
|
@ -292,6 +292,8 @@ void vips_info( const char *domain, const char *fmt, ... )
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void vips_vinfo( const char *domain, const char *fmt, va_list ap );
|
||||
|
||||
VipsAngle vips_autorot_get_angle( VipsImage *image );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -192,7 +192,6 @@ int vips_rot270( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_rot45( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
VipsAngle vips_autorot_get_angle( VipsImage *image );
|
||||
void vips_autorot_remove_angle( VipsImage *image );
|
||||
int vips_autorot( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
@ -179,6 +179,8 @@ double vips_image_get_offset( const VipsImage *image );
|
||||
int vips_image_get_page_height( VipsImage *image );
|
||||
int vips_image_get_n_pages( VipsImage *image );
|
||||
int vips_image_get_n_subifds( VipsImage *image );
|
||||
int vips_image_get_orientation( VipsImage *image );
|
||||
gboolean vips_image_get_orientation_swap( VipsImage *image );
|
||||
const void *vips_image_get_data( VipsImage *image );
|
||||
|
||||
void vips_image_init_fields( VipsImage *image,
|
||||
|
@ -863,6 +863,47 @@ vips_image_get_n_subifds( VipsImage *image )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_orientation: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Fetch and sanity-check #VIPS_META_ORIENTATION. Default to 1 (no rotate,
|
||||
* no flip) if not present or crazy.
|
||||
*
|
||||
* Returns: the image orientation.
|
||||
*/
|
||||
int
|
||||
vips_image_get_orientation( VipsImage *image )
|
||||
{
|
||||
int orientation;
|
||||
|
||||
if( vips_image_get_typeof( image, VIPS_META_ORIENTATION ) &&
|
||||
!vips_image_get_int( image, VIPS_META_ORIENTATION,
|
||||
&orientation ) &&
|
||||
orientation > 0 &&
|
||||
orientation < 9 )
|
||||
return( orientation );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_orientation_swap: (method)
|
||||
* @image: image to get from
|
||||
*
|
||||
* Return %TRUE if applying the orientation would swap width and height.
|
||||
*
|
||||
* Returns: if width/height will swap
|
||||
*/
|
||||
gboolean
|
||||
vips_image_get_orientation_swap( VipsImage *image )
|
||||
{
|
||||
int orientation = vips_image_get_orientation( image );
|
||||
|
||||
return( orientation >= 5 &&
|
||||
orientation <= 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_get_data: (method)
|
||||
* @image: image to get data for
|
||||
@ -957,14 +998,11 @@ static int
|
||||
meta_cp( VipsImage *dst, const VipsImage *src )
|
||||
{
|
||||
if( src->meta ) {
|
||||
/* Loop, copying fields.
|
||||
*/
|
||||
meta_init( dst );
|
||||
|
||||
/* We lock with vips_image_set() to stop races in highly-
|
||||
* threaded applications.
|
||||
*/
|
||||
g_mutex_lock( vips__meta_lock );
|
||||
meta_init( dst );
|
||||
vips_slist_map2( src->meta_traverse,
|
||||
(VipsSListMap2Fn) meta_cp_field, dst, NULL );
|
||||
g_mutex_unlock( vips__meta_lock );
|
||||
@ -1055,8 +1093,6 @@ vips_image_set( VipsImage *image, const char *name, GValue *value )
|
||||
g_assert( name );
|
||||
g_assert( value );
|
||||
|
||||
meta_init( image );
|
||||
|
||||
/* We lock between modifying metadata and copying metadata between
|
||||
* images, see meta_cp().
|
||||
*
|
||||
@ -1065,6 +1101,7 @@ vips_image_set( VipsImage *image, const char *name, GValue *value )
|
||||
* highly-threaded applications.
|
||||
*/
|
||||
g_mutex_lock( vips__meta_lock );
|
||||
meta_init( image );
|
||||
(void) meta_new( image, name, value );
|
||||
g_mutex_unlock( vips__meta_lock );
|
||||
|
||||
|
@ -116,7 +116,8 @@ typedef struct _VipsThumbnail {
|
||||
int input_width;
|
||||
int input_height;
|
||||
int page_height;
|
||||
VipsAngle angle; /* From vips_autorot_get_angle() */
|
||||
int orientation; /* From vips_image_get_orientation() */
|
||||
gboolean swap; /* If we must swap width / height */
|
||||
int n_pages; /* Pages in file */
|
||||
int n_loaded_pages; /* Pages we've loaded from file */
|
||||
int n_subifds; /* Number of subifds */
|
||||
@ -203,7 +204,8 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
|
||||
{
|
||||
thumbnail->input_width = image->Xsize;
|
||||
thumbnail->input_height = image->Ysize;
|
||||
thumbnail->angle = vips_autorot_get_angle( image );
|
||||
thumbnail->orientation = vips_image_get_orientation( image );
|
||||
thumbnail->swap = vips_image_get_orientation_swap( image );
|
||||
thumbnail->page_height = vips_image_get_page_height( image );
|
||||
thumbnail->n_pages = vips_image_get_n_pages( image );
|
||||
thumbnail->n_subifds = vips_image_get_n_subifds( image );
|
||||
@ -390,11 +392,10 @@ static void
|
||||
vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail,
|
||||
int input_width, int input_height, double *hshrink, double *vshrink )
|
||||
{
|
||||
/* If we will be rotating, swap the target width and height.
|
||||
/* If we will be rotating, swap the target width and height.
|
||||
*/
|
||||
gboolean rotate =
|
||||
(thumbnail->angle == VIPS_ANGLE_D90 ||
|
||||
thumbnail->angle == VIPS_ANGLE_D270) &&
|
||||
thumbnail->swap &&
|
||||
thumbnail->auto_rotate;
|
||||
int target_width = rotate ?
|
||||
thumbnail->height : thumbnail->width;
|
||||
@ -831,21 +832,12 @@ vips_thumbnail_build( VipsObject *object )
|
||||
}
|
||||
|
||||
if( thumbnail->auto_rotate &&
|
||||
thumbnail->angle != VIPS_ANGLE_D0 ) {
|
||||
VipsAngle angle = vips_autorot_get_angle( in );
|
||||
|
||||
g_info( "rotating by %s",
|
||||
vips_enum_nick( VIPS_TYPE_ANGLE, angle ) );
|
||||
|
||||
/* Need to copy to memory, we have to stay seq.
|
||||
*/
|
||||
if( !(t[9] = vips_image_copy_memory( in )) ||
|
||||
vips_rot( t[9], &t[10], angle, NULL ) ||
|
||||
vips_copy( t[10], &t[14], NULL ) )
|
||||
return( -1 );
|
||||
thumbnail->orientation != 1 ) {
|
||||
g_info( "rotating by EXIF orientation %d",
|
||||
thumbnail->orientation );
|
||||
if( vips_autorot( in, &t[14], NULL ) )
|
||||
return( -1 );
|
||||
in = t[14];
|
||||
|
||||
vips_autorot_remove_angle( in );
|
||||
}
|
||||
|
||||
/* Crop after rotate so we don't need to rotate the crop box.
|
||||
|
Loading…
Reference in New Issue
Block a user