first try, not very good
This commit is contained in:
parent
2acd185ee2
commit
14d7ce1e91
15
TODO
15
TODO
@ -1,11 +1,14 @@
|
||||
- the jpeg loader needs _header() and _load() to return the same dimensions
|
||||
|
||||
- python:
|
||||
this is going to be tough with read_jpeg_image(): it uses the read-header
|
||||
thing to set up the image that it generates
|
||||
|
||||
- update examples with new image constant rules
|
||||
|
||||
update blog post with new examples/try12.py
|
||||
|
||||
- do more tests
|
||||
|
||||
- update blog post with new examples/try12.py
|
||||
|
||||
- fix up aconv
|
||||
|
||||
- put exif autorotate into jpeg load
|
||||
|
||||
@ -13,12 +16,12 @@
|
||||
|
||||
https://github.com/jcupitt/ruby-vips/issues/53
|
||||
|
||||
- more python tests
|
||||
|
||||
- can we pick the vipsthumbnail int shrink factor more intelligently?
|
||||
|
||||
- vips_resize() should use vipsthumbnail's block/cache/affine/sharpen chain
|
||||
|
||||
- fix up aconv
|
||||
|
||||
- rewrite im_conv() etc. as vips_conv(), also the mosaicing functions
|
||||
|
||||
finally finish --disable-deprecated option
|
||||
|
@ -113,7 +113,7 @@ jpeg2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
if( vips__jpeg_read_file( filename, out,
|
||||
header_only, shrink, fail_on_warn, TRUE ) )
|
||||
header_only, shrink, fail_on_warn, TRUE, FALSE ) )
|
||||
return( -1 );
|
||||
#else
|
||||
vips_error( "im_jpeg2vips",
|
||||
|
@ -682,36 +682,6 @@ vips_foreign_load_new_from_string( const char *string )
|
||||
return( VIPS_OBJECT( load ) );
|
||||
}
|
||||
|
||||
static guint64
|
||||
vips_get_disc_threshold( void )
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
static guint64 threshold;
|
||||
|
||||
if( !done ) {
|
||||
const char *env;
|
||||
|
||||
done = TRUE;
|
||||
|
||||
/* 100mb default.
|
||||
*/
|
||||
threshold = 100 * 1024 * 1024;
|
||||
|
||||
if( (env = g_getenv( "VIPS_DISC_THRESHOLD" )) ||
|
||||
(env = g_getenv( "IM_DISC_THRESHOLD" )) )
|
||||
threshold = vips__parse_size( env );
|
||||
|
||||
if( vips__disc_threshold )
|
||||
threshold = vips__parse_size( vips__disc_threshold );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_get_disc_threshold: %zd bytes\n", threshold );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
|
||||
return( threshold );
|
||||
}
|
||||
|
||||
static VipsImage *
|
||||
vips_foreign_load_temp( VipsForeignLoad *load )
|
||||
{
|
||||
@ -742,12 +712,10 @@ vips_foreign_load_temp( VipsForeignLoad *load )
|
||||
|
||||
/* We open via disc if:
|
||||
* - 'disc' is set
|
||||
* - disc-threshold has not been set to zero
|
||||
* - the uncompressed image will be larger than
|
||||
* vips_get_disc_threshold()
|
||||
*/
|
||||
if( load->disc &&
|
||||
disc_threshold &&
|
||||
image_size > disc_threshold ) {
|
||||
#ifdef DEBUG
|
||||
printf( "vips_foreign_load_temp: disc temp\n" );
|
||||
|
@ -59,6 +59,8 @@
|
||||
* - don't write to our input buffer, thanks Lovell
|
||||
* 9/9/14
|
||||
* - support "none" as a resolution unit
|
||||
* 16/10/14
|
||||
* - add "autorotate" option
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -131,6 +133,12 @@
|
||||
typedef struct _ReadJpeg {
|
||||
VipsImage *out;
|
||||
|
||||
/* The raw image size: out may have width and height swapped if we are
|
||||
* autorotating.
|
||||
*/
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* Shrink by this much during load. 1, 2, 4, 8.
|
||||
*/
|
||||
int shrink;
|
||||
@ -158,6 +166,10 @@ typedef struct _ReadJpeg {
|
||||
/* Track the y pos during a read with this.
|
||||
*/
|
||||
int y_pos;
|
||||
|
||||
/* Use exif tags to automatically rotate and flip image.
|
||||
*/
|
||||
gboolean autorotate;
|
||||
} ReadJpeg;
|
||||
|
||||
static int
|
||||
@ -211,7 +223,8 @@ readjpeg_close( VipsObject *object, ReadJpeg *jpeg )
|
||||
}
|
||||
|
||||
static ReadJpeg *
|
||||
readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean readbehind )
|
||||
readjpeg_new( VipsImage *out,
|
||||
int shrink, gboolean fail, gboolean readbehind, gboolean autorotate )
|
||||
{
|
||||
ReadJpeg *jpeg;
|
||||
|
||||
@ -224,13 +237,12 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean readbehind )
|
||||
jpeg->readbehind = readbehind;
|
||||
jpeg->filename = NULL;
|
||||
jpeg->decompressing = FALSE;
|
||||
|
||||
jpeg->cinfo.err = jpeg_std_error( &jpeg->eman.pub );
|
||||
jpeg->eman.pub.error_exit = vips__new_error_exit;
|
||||
jpeg->eman.pub.output_message = vips__new_output_message;
|
||||
jpeg->eman.fp = NULL;
|
||||
|
||||
jpeg->y_pos = 0;
|
||||
jpeg->autorotate = autorotate;
|
||||
|
||||
/* jpeg_create_decompress() can fail on some sanity checks. Don't
|
||||
* readjpeg_free() since we don't want to jpeg_destroy_decompress().
|
||||
@ -678,6 +690,35 @@ attach_blob( VipsImage *im, const char *field, void *data, int data_length )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#define ORIENTATION ("exif-ifd0-Orientation")
|
||||
|
||||
static VipsAngle
|
||||
get_angle( VipsImage *im )
|
||||
{
|
||||
VipsAngle angle;
|
||||
const char *orientation;
|
||||
|
||||
angle = VIPS_ANGLE_D0;
|
||||
if( vips_image_get_typeof( im, ORIENTATION ) &&
|
||||
!vips_image_get_string( im, ORIENTATION, &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;
|
||||
/* Other values do rotate + mirror, don't bother handling them
|
||||
* though, how common can mirroring be.
|
||||
*
|
||||
* See:
|
||||
*
|
||||
* http://www.80sidea.com/archives/2316
|
||||
*/
|
||||
}
|
||||
|
||||
return( angle );
|
||||
}
|
||||
|
||||
/* Number of app2 sections we can capture. Each one can be 64k, so 6400k should
|
||||
* be enough for anyone (haha).
|
||||
*/
|
||||
@ -892,6 +933,20 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out )
|
||||
(VipsCallbackFn) vips_free, data, data_length );
|
||||
}
|
||||
|
||||
/* Swap width and height if we're going to rotate this image. Keep the
|
||||
* unrotated dimensions around too.
|
||||
*/
|
||||
jpeg->width = out->Xsize;
|
||||
jpeg->height = out->Ysize;
|
||||
|
||||
if( jpeg->autorotate ) {
|
||||
VipsAngle angle = get_angle( out );
|
||||
|
||||
if( angle == VIPS_ANGLE_D90 ||
|
||||
angle == VIPS_ANGLE_D270 )
|
||||
VIPS_SWAP( int, out->Xsize, out->Ysize )
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -966,6 +1021,35 @@ 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, 2 );
|
||||
VipsAngle angle = 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];
|
||||
(void) vips_image_remove( im, ORIENTATION );
|
||||
}
|
||||
|
||||
return( im );
|
||||
}
|
||||
|
||||
/* Read a cinfo to a VIPS image.
|
||||
*/
|
||||
static int
|
||||
@ -975,6 +1059,8 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 3 );
|
||||
|
||||
VipsImage *im;
|
||||
|
||||
/* Here for longjmp() from vips__new_error_exit().
|
||||
*/
|
||||
if( setjmp( jpeg->eman.jmp ) )
|
||||
@ -1002,8 +1088,14 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
"access", jpeg->readbehind ?
|
||||
VIPS_ACCESS_SEQUENTIAL :
|
||||
VIPS_ACCESS_SEQUENTIAL_UNBUFFERED,
|
||||
NULL ) ||
|
||||
vips_image_write( t[1], out ) )
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
|
||||
im = t[1];
|
||||
if( jpeg->autorotate )
|
||||
im = read_jpeg_rotate( VIPS_OBJECT( out ), im );
|
||||
|
||||
if( vips_image_write( im, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -1013,12 +1105,14 @@ read_jpeg_image( ReadJpeg *jpeg, VipsImage *out )
|
||||
*/
|
||||
int
|
||||
vips__jpeg_read_file( const char *filename, VipsImage *out,
|
||||
gboolean header_only, int shrink, gboolean fail, gboolean readbehind )
|
||||
gboolean header_only, int shrink, gboolean fail, gboolean readbehind,
|
||||
gboolean autorotate )
|
||||
{
|
||||
ReadJpeg *jpeg;
|
||||
int result;
|
||||
|
||||
if( !(jpeg = readjpeg_new( out, shrink, fail, readbehind )) )
|
||||
if( !(jpeg = readjpeg_new( out,
|
||||
shrink, fail, readbehind, autorotate )) )
|
||||
return( -1 );
|
||||
|
||||
/* Here for longjmp() from vips__new_error_exit() during startup.
|
||||
@ -1231,12 +1325,14 @@ readjpeg_buffer (ReadJpeg *jpeg, void *buf, size_t len)
|
||||
|
||||
int
|
||||
vips__jpeg_read_buffer( void *buf, size_t len, VipsImage *out,
|
||||
gboolean header_only, int shrink, int fail, gboolean readbehind )
|
||||
gboolean header_only, int shrink, int fail, gboolean readbehind,
|
||||
gboolean autorotate )
|
||||
{
|
||||
ReadJpeg *jpeg;
|
||||
int result;
|
||||
|
||||
if( !(jpeg = readjpeg_new( out, shrink, fail, readbehind )) )
|
||||
if( !(jpeg = readjpeg_new( out,
|
||||
shrink, fail, readbehind, autorotate )) )
|
||||
return( -1 );
|
||||
|
||||
if( setjmp( jpeg->eman.jmp ) ) {
|
||||
|
@ -81,6 +81,10 @@ typedef struct _VipsForeignLoadJpeg {
|
||||
*/
|
||||
gboolean fail;
|
||||
|
||||
/* Autorotate using exif orientation tag.
|
||||
*/
|
||||
gboolean autorotate;
|
||||
|
||||
} VipsForeignLoadJpeg;
|
||||
|
||||
typedef VipsForeignLoadClass VipsForeignLoadJpegClass;
|
||||
@ -146,6 +150,13 @@ vips_foreign_load_jpeg_class_init( VipsForeignLoadJpegClass *class )
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadJpeg, fail ),
|
||||
FALSE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "autorotate", 12,
|
||||
_( "Autorotate" ),
|
||||
_( "Automatically rotate image using exif orientation" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadJpeg, autorotate ),
|
||||
FALSE );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -189,7 +200,7 @@ vips_foreign_load_jpeg_file_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) load;
|
||||
|
||||
if( vips__jpeg_read_file( file->filename, load->out,
|
||||
TRUE, jpeg->shrink, jpeg->fail, FALSE ) )
|
||||
TRUE, jpeg->shrink, jpeg->fail, FALSE, jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_SETSTR( load->out->filename, file->filename );
|
||||
@ -205,7 +216,7 @@ vips_foreign_load_jpeg_file_load( VipsForeignLoad *load )
|
||||
|
||||
if( vips__jpeg_read_file( file->filename, load->real,
|
||||
FALSE, jpeg->shrink, jpeg->fail,
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL, jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -269,7 +280,8 @@ vips_foreign_load_jpeg_buffer_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) load;
|
||||
|
||||
if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length,
|
||||
load->out, TRUE, jpeg->shrink, jpeg->fail, FALSE ) )
|
||||
load->out, TRUE, jpeg->shrink, jpeg->fail, FALSE,
|
||||
jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -283,7 +295,7 @@ vips_foreign_load_jpeg_buffer_load( VipsForeignLoad *load )
|
||||
|
||||
if( vips__jpeg_read_buffer( buffer->buf->data, buffer->buf->length,
|
||||
load->real, FALSE, jpeg->shrink, jpeg->fail,
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL ) )
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL, jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
|
@ -49,9 +49,11 @@ int vips__jpeg_write_buffer( VipsImage *in,
|
||||
int vips__isjpeg_buffer( void *buf, size_t len );
|
||||
int vips__isjpeg( const char *filename );
|
||||
int vips__jpeg_read_file( const char *name, VipsImage *out,
|
||||
gboolean header_only, int shrink, gboolean fail, gboolean readbehind );
|
||||
gboolean header_only, int shrink, gboolean fail, gboolean readbehind,
|
||||
gboolean autorotate );
|
||||
int vips__jpeg_read_buffer( void *buf, size_t len, VipsImage *out,
|
||||
gboolean header_only, int shrink, int fail, gboolean readbehind );
|
||||
gboolean header_only, int shrink, int fail, gboolean readbehind,
|
||||
gboolean autorotate );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -427,6 +427,7 @@ VipsImage *vips_image_new_matrix_from_array( int width, int height,
|
||||
double *array, int size );
|
||||
void vips_image_set_delete_on_close( VipsImage *image,
|
||||
gboolean delete_on_close );
|
||||
guint64 vips_get_disc_threshold( void );
|
||||
VipsImage *vips_image_new_temp_file( const char *format );
|
||||
|
||||
int vips_image_write( VipsImage *image, VipsImage *out );
|
||||
|
@ -2204,6 +2204,46 @@ vips_image_set_delete_on_close( VipsImage *image, gboolean delete_on_close )
|
||||
VIPS_SETSTR( image->delete_on_close_filename, image->filename );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_get_disc_threshold:
|
||||
*
|
||||
* Return the number of bytes at which we flip between open via memory and
|
||||
* open via disc. This defaults to 100mb, but can be changed with the
|
||||
* VIPS_DISC_THRESHOLD environment variable or the --vips-disc-threshold
|
||||
* command-line flag. See vips_image_new_from_file().
|
||||
*
|
||||
* Returns: disc threshold in bytes.
|
||||
*/
|
||||
guint64
|
||||
vips_get_disc_threshold( void )
|
||||
{
|
||||
static gboolean done = FALSE;
|
||||
static guint64 threshold;
|
||||
|
||||
if( !done ) {
|
||||
const char *env;
|
||||
|
||||
done = TRUE;
|
||||
|
||||
/* 100mb default.
|
||||
*/
|
||||
threshold = 100 * 1024 * 1024;
|
||||
|
||||
if( (env = g_getenv( "VIPS_DISC_THRESHOLD" )) ||
|
||||
(env = g_getenv( "IM_DISC_THRESHOLD" )) )
|
||||
threshold = vips__parse_size( env );
|
||||
|
||||
if( vips__disc_threshold )
|
||||
threshold = vips__parse_size( vips__disc_threshold );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_get_disc_threshold: %zd bytes\n", threshold );
|
||||
#endif /*DEBUG*/
|
||||
}
|
||||
|
||||
return( threshold );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_new_temp_file:
|
||||
* @format: format of file
|
||||
|
Loading…
Reference in New Issue
Block a user