compiles
needs testing etc.
This commit is contained in:
parent
ac2ce4228b
commit
5a9f2c787b
73
TODO
73
TODO
@ -1,3 +1,44 @@
|
|||||||
|
- set tiff orientation tag on write, also copy orientation between tiff iamges
|
||||||
|
|
||||||
|
- switch jpeg read/write over to new orientation tag
|
||||||
|
|
||||||
|
- support orientation tag in tiff images
|
||||||
|
|
||||||
|
see
|
||||||
|
|
||||||
|
http://www.awaresystems.be/imaging/tiff/tifftags/orientation.html
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- tiff write does not support [strip]
|
- tiff write does not support [strip]
|
||||||
|
|
||||||
- add more webp tests to py suite
|
- add more webp tests to py suite
|
||||||
@ -62,39 +103,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
- support orientation tag in tiff images
|
|
||||||
|
|
||||||
see
|
|
||||||
|
|
||||||
http://www.awaresystems.be/imaging/tiff/tifftags/orientation.html
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- why can't we do
|
- why can't we do
|
||||||
|
|
||||||
|
|
||||||
im = Vips.Image.new_from_file("/data/john/pics/k2.jpg", access = "sequential")
|
im = Vips.Image.new_from_file("/data/john/pics/k2.jpg", access = "sequential")
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,11 +94,11 @@ tiff2vips( const char *name, IMAGE *out, gboolean header_only )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( header_only ) {
|
if( header_only ) {
|
||||||
if( vips__tiff_read_header( filename, out, page ) )
|
if( vips__tiff_read_header( filename, out, page, FALSE ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if( vips__tiff_read( filename, out, page, TRUE ) )
|
if( vips__tiff_read( filename, out, page, FALSE, TRUE ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -157,6 +157,7 @@ vips_foreign_load_jpeg_class_init( VipsForeignLoadJpegClass *class )
|
|||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ),
|
G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ),
|
||||||
FALSE );
|
FALSE );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -354,7 +355,8 @@ vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer )
|
|||||||
*
|
*
|
||||||
* * @shrink: %gint, shrink by this much on load
|
* * @shrink: %gint, shrink by this much on load
|
||||||
* * @fail: %gboolean, fail on warnings
|
* * @fail: %gboolean, fail on warnings
|
||||||
* * @autorotate: %gboolean, use exif Orientation tag to rotate the image during load
|
* * @autorotate: %gboolean, use exif Orientation tag to rotate the image
|
||||||
|
* during load
|
||||||
*
|
*
|
||||||
* Read a JPEG file into a VIPS image. It can read most 8-bit JPEG images,
|
* Read a JPEG file into a VIPS image. It can read most 8-bit JPEG images,
|
||||||
* including CMYK and YCbCr.
|
* including CMYK and YCbCr.
|
||||||
|
@ -52,17 +52,18 @@ int vips__tiff_write( VipsImage *in, const char *filename,
|
|||||||
gboolean rgbjpeg,
|
gboolean rgbjpeg,
|
||||||
gboolean properties );
|
gboolean properties );
|
||||||
|
|
||||||
int vips__tiff_read_header( const char *filename, VipsImage *out, int page );
|
int vips__tiff_read_header( const char *filename, VipsImage *out,
|
||||||
|
int page, gboolean autorotate );
|
||||||
int vips__tiff_read( const char *filename, VipsImage *out,
|
int vips__tiff_read( const char *filename, VipsImage *out,
|
||||||
int page, gboolean readbehind );
|
int page, gboolean autorotate, gboolean readbehind );
|
||||||
gboolean vips__istifftiled( const char *filename );
|
gboolean vips__istifftiled( const char *filename );
|
||||||
gboolean vips__istiff_buffer( const void *buf, size_t len );
|
gboolean vips__istiff_buffer( const void *buf, size_t len );
|
||||||
gboolean vips__istiff( const char *filename );
|
gboolean vips__istiff( const char *filename );
|
||||||
|
|
||||||
int vips__tiff_read_header_buffer( const void *buf, size_t len, VipsImage *out,
|
int vips__tiff_read_header_buffer( const void *buf, size_t len, VipsImage *out,
|
||||||
int page );
|
int page, gboolean autorotate );
|
||||||
int vips__tiff_read_buffer( const void *buf, size_t len, VipsImage *out,
|
int vips__tiff_read_buffer( const void *buf, size_t len, VipsImage *out,
|
||||||
int page, gboolean readbehind );
|
int page, gboolean autorotate, gboolean readbehind );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,8 @@
|
|||||||
* 11/4/16
|
* 11/4/16
|
||||||
* - non-int RGB images are tagged as scRGB ... matches photoshop
|
* - non-int RGB images are tagged as scRGB ... matches photoshop
|
||||||
* convention
|
* convention
|
||||||
|
* 26/5/16
|
||||||
|
* - add autorotate support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -195,8 +197,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define DEBUG
|
|
||||||
*/
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -233,6 +235,7 @@ typedef struct _ReadTiff {
|
|||||||
size_t len;
|
size_t len;
|
||||||
VipsImage *out;
|
VipsImage *out;
|
||||||
int page;
|
int page;
|
||||||
|
gboolean autorotate;
|
||||||
gboolean readbehind;
|
gboolean readbehind;
|
||||||
|
|
||||||
/* The TIFF we read.
|
/* The TIFF we read.
|
||||||
@ -263,6 +266,7 @@ typedef struct _ReadTiff {
|
|||||||
int bits_per_sample;
|
int bits_per_sample;
|
||||||
int photometric_interpretation;
|
int photometric_interpretation;
|
||||||
int sample_format;
|
int sample_format;
|
||||||
|
int orientation;
|
||||||
|
|
||||||
/* Turn on separate plane reading.
|
/* Turn on separate plane reading.
|
||||||
*/
|
*/
|
||||||
@ -1134,6 +1138,17 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint16 v;
|
||||||
|
|
||||||
|
rtiff->orientation = ORIENTATION_TOPLEFT;
|
||||||
|
|
||||||
|
if( TIFFGetFieldDefaulted( rtiff->tiff, TIFFTAG_ORIENTATION, &v ) )
|
||||||
|
/* Can have mad values.
|
||||||
|
*/
|
||||||
|
rtiff->orientation = VIPS_CLIP( 1, v, 8 );
|
||||||
|
}
|
||||||
|
|
||||||
/* Arbitrary sanity-checking limits.
|
/* Arbitrary sanity-checking limits.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1171,6 +1186,8 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
|
|||||||
rtiff->bits_per_sample );
|
rtiff->bits_per_sample );
|
||||||
printf( "parse_header: sample_format = %d\n",
|
printf( "parse_header: sample_format = %d\n",
|
||||||
rtiff->sample_format );
|
rtiff->sample_format );
|
||||||
|
printf( "parse_header: orientation = %d\n",
|
||||||
|
rtiff->orientation );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
/* We have a range of output paths. Look at the tiff header and try to
|
/* We have a range of output paths. Look at the tiff header and try to
|
||||||
@ -1246,6 +1263,11 @@ parse_header( ReadTiff *rtiff, VipsImage *out )
|
|||||||
VIPS_META_IMAGEDESCRIPTION, (char *) data );
|
VIPS_META_IMAGEDESCRIPTION, (char *) data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the "orientation" tag. This is picked up later by autorot, if
|
||||||
|
* requested.
|
||||||
|
*/
|
||||||
|
vips_image_set_int( out, VIPS_META_ORIENTATION, rtiff->orientation );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1409,14 +1431,86 @@ tiff_seq_stop( void *seq, void *a, void *b )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 );
|
||||||
|
|
||||||
|
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 *x;
|
||||||
|
|
||||||
|
if( image_size > disc_threshold )
|
||||||
|
x = vips_image_new_temp_file( "%s.v" );
|
||||||
|
else
|
||||||
|
x = vips_image_new_memory();
|
||||||
|
|
||||||
|
if( vips_image_write( in, x ) ||
|
||||||
|
vips_rot( x, out, angle, NULL ) ) {
|
||||||
|
g_object_unref( x );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
g_object_unref( x );
|
||||||
|
|
||||||
|
/* We must remove VIPS_META_ORIENTATION to prevent accidental
|
||||||
|
* double rotations.
|
||||||
|
*/
|
||||||
|
(void) vips_image_remove( *out, VIPS_META_ORIENTATION );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*out = in;
|
||||||
|
g_object_ref( in );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/* Tile-type TIFF reader core - pass in a per-tile transform. Generate into
|
/* Tile-type TIFF reader core - pass in a per-tile transform. Generate into
|
||||||
* the im and do it all partially.
|
* the im and do it all partially.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
read_tilewise( ReadTiff *rtiff, VipsImage *out )
|
read_tilewise( ReadTiff *rtiff, VipsImage *out )
|
||||||
{
|
{
|
||||||
VipsImage *raw;
|
VipsImage **t = (VipsImage **)
|
||||||
VipsImage *t;
|
vips_object_local_array( VIPS_OBJECT( out ), 3 );
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "tiff2vips: read_tilewise\n" );
|
printf( "tiff2vips: read_tilewise\n" );
|
||||||
@ -1438,12 +1532,11 @@ read_tilewise( ReadTiff *rtiff, VipsImage *out )
|
|||||||
|
|
||||||
/* Read to this image, then cache to out, see below.
|
/* Read to this image, then cache to out, see below.
|
||||||
*/
|
*/
|
||||||
raw = vips_image_new();
|
t[0] = vips_image_new();
|
||||||
vips_object_local( out, raw );
|
|
||||||
|
|
||||||
/* Parse the TIFF header and set up raw.
|
/* Parse the TIFF header and set up.
|
||||||
*/
|
*/
|
||||||
if( parse_header( rtiff, raw ) )
|
if( parse_header( rtiff, t[0] ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Double check: in memcpy mode, the vips tilesize should exactly
|
/* Double check: in memcpy mode, the vips tilesize should exactly
|
||||||
@ -1452,7 +1545,7 @@ read_tilewise( ReadTiff *rtiff, VipsImage *out )
|
|||||||
if( rtiff->memcpy ) {
|
if( rtiff->memcpy ) {
|
||||||
size_t vips_tile_size;
|
size_t vips_tile_size;
|
||||||
|
|
||||||
vips_tile_size = VIPS_IMAGE_SIZEOF_PEL( raw ) *
|
vips_tile_size = VIPS_IMAGE_SIZEOF_PEL( t[0] ) *
|
||||||
rtiff->twidth * rtiff->theight;
|
rtiff->twidth * rtiff->theight;
|
||||||
|
|
||||||
if( tiff_tile_size( rtiff ) != vips_tile_size ) {
|
if( tiff_tile_size( rtiff ) != vips_tile_size ) {
|
||||||
@ -1466,26 +1559,25 @@ read_tilewise( ReadTiff *rtiff, VipsImage *out )
|
|||||||
* the cache we are quite happy serving that if anything downstream
|
* the cache we are quite happy serving that if anything downstream
|
||||||
* would like it.
|
* would like it.
|
||||||
*/
|
*/
|
||||||
vips_image_pipelinev( raw, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
vips_image_pipelinev( t[0], VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||||
|
|
||||||
if( vips_image_generate( raw,
|
if( vips_image_generate( t[0],
|
||||||
tiff_seq_start, tiff_fill_region, tiff_seq_stop,
|
tiff_seq_start, tiff_fill_region, tiff_seq_stop,
|
||||||
rtiff, NULL ) )
|
rtiff, NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Copy to out, adding a cache. Enough tiles for two complete rows.
|
/* Copy to out, adding a cache. Enough tiles for two complete rows.
|
||||||
*/
|
*/
|
||||||
if( vips_tilecache( raw, &t,
|
if( vips_tilecache( t[0], &t[1],
|
||||||
"tile_width", rtiff->twidth,
|
"tile_width", rtiff->twidth,
|
||||||
"tile_height", rtiff->theight,
|
"tile_height", rtiff->theight,
|
||||||
"max_tiles", 2 * (1 + raw->Xsize / rtiff->twidth),
|
"max_tiles", 2 * (1 + t[0]->Xsize / rtiff->twidth),
|
||||||
NULL ) )
|
NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
if( vips_image_write( t, out ) ) {
|
if( vips_tiff_autorotate( rtiff, t[1], &t[2] ) )
|
||||||
g_object_unref( t );
|
return( -1 );
|
||||||
|
if( vips_image_write( t[2], out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
g_object_unref( t );
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -1645,7 +1737,6 @@ read_stripwise( ReadTiff *rtiff, VipsImage *out )
|
|||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
t[0] = vips_image_new();
|
t[0] = vips_image_new();
|
||||||
|
|
||||||
if( parse_header( rtiff, t[0] ) )
|
if( parse_header( rtiff, t[0] ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -1738,7 +1829,8 @@ read_stripwise( ReadTiff *rtiff, VipsImage *out )
|
|||||||
VIPS_ACCESS_SEQUENTIAL :
|
VIPS_ACCESS_SEQUENTIAL :
|
||||||
VIPS_ACCESS_SEQUENTIAL_UNBUFFERED,
|
VIPS_ACCESS_SEQUENTIAL_UNBUFFERED,
|
||||||
NULL ) ||
|
NULL ) ||
|
||||||
vips_image_write( t[1], out ) )
|
vips_tiff_autorotate( rtiff, t[1], &t[2] ) ||
|
||||||
|
vips_image_write( t[2], out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -1759,7 +1851,8 @@ readtiff_close( VipsObject *object, ReadTiff *rtiff )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ReadTiff *
|
static ReadTiff *
|
||||||
readtiff_new( VipsImage *out, int page, gboolean readbehind )
|
readtiff_new( VipsImage *out,
|
||||||
|
int page, gboolean autorotate, gboolean readbehind )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
|
|
||||||
@ -1771,6 +1864,7 @@ readtiff_new( VipsImage *out, int page, gboolean readbehind )
|
|||||||
rtiff->len = 0;
|
rtiff->len = 0;
|
||||||
rtiff->out = out;
|
rtiff->out = out;
|
||||||
rtiff->page = page;
|
rtiff->page = page;
|
||||||
|
rtiff->autorotate = autorotate;
|
||||||
rtiff->readbehind = readbehind;
|
rtiff->readbehind = readbehind;
|
||||||
rtiff->tiff = NULL;
|
rtiff->tiff = NULL;
|
||||||
rtiff->sfn = NULL;
|
rtiff->sfn = NULL;
|
||||||
@ -1796,13 +1890,13 @@ readtiff_new( VipsImage *out, int page, gboolean readbehind )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ReadTiff *
|
static ReadTiff *
|
||||||
readtiff_new_filename( const char *filename, VipsImage *out, int page,
|
readtiff_new_filename( const char *filename, VipsImage *out,
|
||||||
gboolean readbehind )
|
int page, gboolean autorotate, gboolean readbehind )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new( out, page, readbehind )) )
|
if( !(rtiff = readtiff_new( out, page, autorotate, readbehind )) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
||||||
rtiff->filename = vips_strdup( VIPS_OBJECT( out ), filename );
|
rtiff->filename = vips_strdup( VIPS_OBJECT( out ), filename );
|
||||||
@ -1897,13 +1991,13 @@ my_tiff_unmap( thandle_t st, tdata_t start, toff_t len )
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ReadTiff *
|
static ReadTiff *
|
||||||
readtiff_new_buffer( const void *buf, size_t len, VipsImage *out, int page,
|
readtiff_new_buffer( const void *buf, size_t len, VipsImage *out,
|
||||||
gboolean readbehind )
|
int page, gboolean autorotate, gboolean readbehind )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new( out, page, readbehind )) )
|
if( !(rtiff = readtiff_new( out, page, autorotate, readbehind )) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
||||||
rtiff->buf = buf;
|
rtiff->buf = buf;
|
||||||
@ -1951,8 +2045,8 @@ istiffpyramid( const char *name )
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__tiff_read( const char *filename, VipsImage *out, int page,
|
vips__tiff_read( const char *filename, VipsImage *out,
|
||||||
gboolean readbehind )
|
int page, gboolean autorotate, gboolean readbehind )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
|
|
||||||
@ -1964,7 +2058,7 @@ vips__tiff_read( const char *filename, VipsImage *out, int page,
|
|||||||
vips__tiff_init();
|
vips__tiff_init();
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new_filename( filename,
|
if( !(rtiff = readtiff_new_filename( filename,
|
||||||
out, page, readbehind )) )
|
out, page, autorotate, readbehind )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( TIFFIsTiled( rtiff->tiff ) ) {
|
if( TIFFIsTiled( rtiff->tiff ) ) {
|
||||||
@ -1979,19 +2073,45 @@ vips__tiff_read( const char *filename, VipsImage *out, int page,
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* On a header-only read, we can just swap width/height if orientaion is 6 or
|
||||||
|
* 8.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vips__tiff_read_header_orientation( ReadTiff *rtiff, VipsImage *out )
|
||||||
|
{
|
||||||
|
int orientation;
|
||||||
|
|
||||||
|
if( rtiff->autorotate &&
|
||||||
|
!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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__tiff_read_header( const char *filename, VipsImage *out, int page )
|
vips__tiff_read_header( const char *filename, VipsImage *out,
|
||||||
|
int page, gboolean autorotate )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
|
|
||||||
vips__tiff_init();
|
vips__tiff_init();
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new_filename( filename, out, page, FALSE )) )
|
if( !(rtiff = readtiff_new_filename( filename, out,
|
||||||
|
page, autorotate, FALSE )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( parse_header( rtiff, out ) )
|
if( parse_header( rtiff, out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
|
vips__tiff_read_header_orientation( rtiff, out );
|
||||||
|
|
||||||
/* Just a header read: we can free the tiff read early and save an fd.
|
/* Just a header read: we can free the tiff read early and save an fd.
|
||||||
*/
|
*/
|
||||||
readtiff_free( rtiff );
|
readtiff_free( rtiff );
|
||||||
@ -2045,25 +2165,28 @@ vips__istiff( const char *filename )
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__tiff_read_header_buffer( const void *buf, size_t len,
|
vips__tiff_read_header_buffer( const void *buf, size_t len, VipsImage *out,
|
||||||
VipsImage *out, int page )
|
int page, gboolean autorotate )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
|
|
||||||
vips__tiff_init();
|
vips__tiff_init();
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new_buffer( buf, len, out, page, FALSE )) )
|
if( !(rtiff = readtiff_new_buffer( buf, len, out,
|
||||||
|
page, autorotate, FALSE )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( parse_header( rtiff, out ) )
|
if( parse_header( rtiff, out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
|
vips__tiff_read_header_orientation( rtiff, out );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__tiff_read_buffer( const void *buf, size_t len,
|
vips__tiff_read_buffer( const void *buf, size_t len,
|
||||||
VipsImage *out, int page, gboolean readbehind )
|
VipsImage *out, int page, gboolean autorotate, gboolean readbehind )
|
||||||
{
|
{
|
||||||
ReadTiff *rtiff;
|
ReadTiff *rtiff;
|
||||||
|
|
||||||
@ -2074,7 +2197,8 @@ vips__tiff_read_buffer( const void *buf, size_t len,
|
|||||||
|
|
||||||
vips__tiff_init();
|
vips__tiff_init();
|
||||||
|
|
||||||
if( !(rtiff = readtiff_new_buffer( buf, len, out, page, readbehind )) )
|
if( !(rtiff = readtiff_new_buffer( buf, len, out,
|
||||||
|
page, autorotate, readbehind )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( TIFFIsTiled( rtiff->tiff ) ) {
|
if( TIFFIsTiled( rtiff->tiff ) ) {
|
||||||
|
@ -59,6 +59,10 @@ typedef struct _VipsForeignLoadTiff {
|
|||||||
*/
|
*/
|
||||||
int page;
|
int page;
|
||||||
|
|
||||||
|
/* Autorotate using orientation tag.
|
||||||
|
*/
|
||||||
|
gboolean autorotate;
|
||||||
|
|
||||||
} VipsForeignLoadTiff;
|
} VipsForeignLoadTiff;
|
||||||
|
|
||||||
typedef VipsForeignLoadClass VipsForeignLoadTiffClass;
|
typedef VipsForeignLoadClass VipsForeignLoadTiffClass;
|
||||||
@ -91,6 +95,13 @@ vips_foreign_load_tiff_class_init( VipsForeignLoadTiffClass *class )
|
|||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsForeignLoadTiff, page ),
|
G_STRUCT_OFFSET( VipsForeignLoadTiff, page ),
|
||||||
0, 100000, 0 );
|
0, 100000, 0 );
|
||||||
|
|
||||||
|
VIPS_ARG_BOOL( class, "autorotate", 11,
|
||||||
|
_( "Autorotate" ),
|
||||||
|
_( "Rotate image using orientation tag" ),
|
||||||
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadTiff, autorotate ),
|
||||||
|
FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -142,7 +153,8 @@ vips_foreign_load_tiff_file_header( VipsForeignLoad *load )
|
|||||||
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
||||||
VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load;
|
VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load;
|
||||||
|
|
||||||
if( vips__tiff_read_header( file->filename, load->out, tiff->page ) )
|
if( vips__tiff_read_header( file->filename, load->out,
|
||||||
|
tiff->page, tiff->autorotate ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
VIPS_SETSTR( load->out->filename, file->filename );
|
VIPS_SETSTR( load->out->filename, file->filename );
|
||||||
@ -157,7 +169,7 @@ vips_foreign_load_tiff_file_load( VipsForeignLoad *load )
|
|||||||
VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load;
|
VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) load;
|
||||||
|
|
||||||
if( vips__tiff_read( file->filename, load->real, tiff->page,
|
if( vips__tiff_read( file->filename, load->real, tiff->page,
|
||||||
load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
tiff->autorotate, load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -227,7 +239,7 @@ vips_foreign_load_tiff_buffer_header( VipsForeignLoad *load )
|
|||||||
|
|
||||||
if( vips__tiff_read_header_buffer(
|
if( vips__tiff_read_header_buffer(
|
||||||
buffer->buf->data, buffer->buf->length, load->out,
|
buffer->buf->data, buffer->buf->length, load->out,
|
||||||
tiff->page ) )
|
tiff->page, tiff->autorotate ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -241,7 +253,7 @@ vips_foreign_load_tiff_buffer_load( VipsForeignLoad *load )
|
|||||||
|
|
||||||
if( vips__tiff_read_buffer(
|
if( vips__tiff_read_buffer(
|
||||||
buffer->buf->data, buffer->buf->length, load->real,
|
buffer->buf->data, buffer->buf->length, load->real,
|
||||||
tiff->page,
|
tiff->page, tiff->autorotate,
|
||||||
load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -290,6 +302,8 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer )
|
|||||||
* Optional arguments:
|
* Optional arguments:
|
||||||
*
|
*
|
||||||
* * @page: int, load this page
|
* * @page: int, load this page
|
||||||
|
* * @autorotate: %gboolean, use Orientation tag to rotate the image
|
||||||
|
* during load
|
||||||
*
|
*
|
||||||
* Read a TIFF file into a VIPS image. It is a full baseline TIFF 6 reader,
|
* Read a TIFF file into a VIPS image. It is a full baseline TIFF 6 reader,
|
||||||
* with extensions for tiled images, multipage images, LAB colour space,
|
* with extensions for tiled images, multipage images, LAB colour space,
|
||||||
@ -298,6 +312,14 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer )
|
|||||||
* @page means load this page from the file. By default the first page (page
|
* @page means load this page from the file. By default the first page (page
|
||||||
* 0) is read.
|
* 0) is read.
|
||||||
*
|
*
|
||||||
|
* Setting @autorotate to %TRUE will make the loader interpret the
|
||||||
|
* Orientation field and automatically rotate the image appropriately during
|
||||||
|
* load. After rotation, the Orientation tag will be removed to prevent
|
||||||
|
* accidental double-rotation.
|
||||||
|
*
|
||||||
|
* Using @autorotate can be much slower than doing the rotate later
|
||||||
|
* in processing. See vips_autorot().
|
||||||
|
*
|
||||||
* Any ICC profile is read and attached to the VIPS image. Any XMP metadata is
|
* Any ICC profile is read and attached to the VIPS image. Any XMP metadata is
|
||||||
* read and attached to the image.
|
* read and attached to the image.
|
||||||
*
|
*
|
||||||
|
@ -108,6 +108,14 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define VIPS_META_LOADER "vips-loader"
|
#define VIPS_META_LOADER "vips-loader"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VIPS_META_ORIENTATION:
|
||||||
|
*
|
||||||
|
* The orientation tag for this image. An int from 1 - 8 using the standard
|
||||||
|
* exif/tiff meanings.
|
||||||
|
*/
|
||||||
|
#define VIPS_META_ORIENTATION "orientation"
|
||||||
|
|
||||||
guint64 vips_format_sizeof( VipsBandFormat format );
|
guint64 vips_format_sizeof( VipsBandFormat format );
|
||||||
|
|
||||||
int vips_image_get_width( const VipsImage *image );
|
int vips_image_get_width( const VipsImage *image );
|
||||||
|
Loading…
Reference in New Issue
Block a user