Add ImageMagick buffer support

This commits adds buffer support for the ImageMagick backend, using the Blob
API.
This commit is contained in:
Maurus Cuelenaere 2015-02-14 18:09:31 +01:00
parent be5052d0c3
commit dba1b1d81b
9 changed files with 267 additions and 2 deletions

View File

@ -226,6 +226,8 @@ static VImage openslideload( char * filename , VOption *options = 0 )
throw( VError );
static VImage magickload( char * filename , VOption *options = 0 )
throw( VError );
static VImage magickload_buffer( VipsBlob * buffer , VOption *options = 0 )
throw( VError );
static VImage fitsload( char * filename , VOption *options = 0 )
throw( VError );
static VImage openexrload( char * filename , VOption *options = 0 )

View File

@ -1567,6 +1567,19 @@ VImage VImage::magickload( char * filename , VOption *options )
return( out );
}
VImage VImage::magickload_buffer( VipsBlob * buffer , VOption *options )
throw( VError )
{
VImage out;
call( "magickload_buffer" ,
(options ? options : VImage::option()) ->
set( "buffer", buffer ) ->
set( "out", &out ) );
return( out );
}
VImage VImage::fitsload( char * filename , VOption *options )
throw( VError )
{

View File

@ -641,6 +641,11 @@
<entry>load file with ImageMagick</entry>
<entry>vips_magickload()</entry>
</row>
<row>
<entry>magickload_buffer</entry>
<entry>load image from buffer with ImageMagick</entry>
<entry>vips_magickload_buffer()</entry>
</row>
<row>
<entry>fitsload</entry>
<entry>load a FITS image</entry>

View File

@ -1546,6 +1546,7 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_raw_get_type( void );
extern GType vips_foreign_save_raw_fd_get_type( void );
extern GType vips_foreign_load_magick_get_type( void );
extern GType vips_foreign_load_magick_buffer_get_type( void );
extern GType vips_foreign_save_dz_get_type( void );
extern GType vips_foreign_load_webp_file_get_type( void );
extern GType vips_foreign_load_webp_buffer_get_type( void );
@ -1610,6 +1611,7 @@ vips_foreign_operation_init( void )
#ifdef HAVE_MAGICK
vips_foreign_load_magick_get_type();
vips_foreign_load_magick_buffer_get_type();
#endif /*HAVE_MAGICK*/
#ifdef HAVE_CFITSIO
@ -1668,6 +1670,48 @@ vips_magickload( const char *filename, VipsImage **out, ... )
return( result );
}
/**
* vips_magickload_buffer:
* @buf: memory area to load
* @len: size of memory area
* @out: decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @all_frames: %gboolean, load all frames in sequence
* @density: string, canvas resolution for rendering vector formats like SVG
*
* Read an image memory block using libMagick into a VIPS image. Exactly as
* vips_magickload(), but read from a memory source.
*
* You must not free the buffer while @out is active. The
* #VipsObject::postclose signal on @out is a good place to free.
*
* See also: vips_magickload().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_magickload_buffer( void *buf, size_t len, VipsImage **out, ... )
{
va_list ap;
VipsBlob *blob;
int result;
/* We don't take a copy of the data or free it.
*/
blob = vips_blob_new( NULL, buf, len );
va_start( ap, out );
result = vips_call_split( "magickload_buffer", ap, blob, out );
va_end( ap );
vips_area_unref( VIPS_AREA( blob ) );
return( result );
}
/**
* vips_tiffload:
* @filename: file to load

View File

@ -40,6 +40,11 @@ int vips__magick_read( const char *filename,
int vips__magick_read_header( const char *filename,
VipsImage *out, gboolean all_frames, const char *density );
int vips__magick_read_buffer( const void *buf, const size_t len,
VipsImage *out, gboolean all_frames, const char *density );
int vips__magick_read_buffer_header( const void *buf, const size_t len,
VipsImage *out, gboolean all_frames, const char *density );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -160,7 +160,7 @@ read_new( const char *filename, VipsImage *im, gboolean all_frames,
if( !(read = VIPS_NEW( im, Read )) )
return( NULL );
read->filename = g_strdup( filename );
read->filename = filename ? g_strdup( filename ) : NULL;
read->all_frames = all_frames;
read->im = im;
read->image = NULL;
@ -176,7 +176,9 @@ read_new( const char *filename, VipsImage *im, gboolean all_frames,
if( !read->image_info )
return( NULL );
vips_strncpy( read->image_info->filename, filename, MaxTextExtent );
if (filename) {
vips_strncpy( read->image_info->filename, filename, MaxTextExtent );
}
/* Canvas resolution for rendering vector formats like SVG.
*/
@ -740,5 +742,86 @@ vips__magick_read_header( const char *filename, VipsImage *im,
return( 0 );
}
int
vips__magick_read_buffer( const void *buf, const size_t len, VipsImage *out,
gboolean all_frames, const char *density )
{
Read *read;
#ifdef DEBUG
printf( "magick2vips: vips__magick_read_buffer: %p %zu\n", buf, len );
#endif /*DEBUG*/
if( !(read = read_new( NULL, out, all_frames, density )) )
return( -1 );
#ifdef HAVE_SETIMAGEOPTION
/* When reading DICOM images, we want to ignore any
* window_center/_width setting, since it may put pixels outside the
* 0-65535 range and lose data.
*
* These window settings are attached as vips metadata, so our caller
* can interpret them if it wants.
*/
SetImageOption( read->image_info, "dcm:display-range", "reset" );
#endif /*HAVE_SETIMAGEOPTION*/
#ifdef DEBUG
printf( "magick2vips: calling BlobToImage() ...\n" );
#endif /*DEBUG*/
read->image = BlobToImage( read->image_info, buf, len, &read->exception );
if( !read->image ) {
vips_error( "magick2vips", _( "unable to read buffer\n"
"libMagick error: %s %s" ),
read->exception.reason, read->exception.description );
return( -1 );
}
if( parse_header( read ) )
return( -1 );
if( vips_image_generate( out,
NULL, magick_fill_region, NULL, read, NULL ) )
return( -1 );
return( 0 );
}
int
vips__magick_read_buffer_header( const void *buf, const size_t len,
VipsImage *im, gboolean all_frames, const char *density )
{
Read *read;
#ifdef DEBUG
printf( "vips__magick_read_buffer_header: %p %zu\n", buf, len );
#endif /*DEBUG*/
if( !(read = read_new( NULL, im, all_frames, density )) )
return( -1 );
#ifdef DEBUG
printf( "vips__magick_read_buffer_header: pinging blob ...\n" );
#endif /*DEBUG*/
read->image = PingBlob( read->image_info, buf, len, &read->exception );
if( !read->image ) {
vips_error( "magick2vips", _( "unable to ping blob\n"
"libMagick error: %s %s" ),
read->exception.reason, read->exception.description );
return( -1 );
}
if( parse_header( read ) )
return( -1 );
if( im->Xsize <= 0 || im->Ysize <= 0 ) {
vips_error( "magick2vips", "%s", _( "bad image size" ) );
return( -1 );
}
return( 0 );
}
#endif /*HAVE_MAGICK*/

View File

@ -175,4 +175,114 @@ vips_foreign_load_magick_init( VipsForeignLoadMagick *magick )
{
}
typedef struct _VipsForeignLoadMagickBuffer {
VipsForeignLoad parent_object;
VipsArea *buf;
gboolean all_frames;
char *density;
} VipsForeignLoadMagickBuffer;
typedef VipsForeignLoadClass VipsForeignLoadMagickBufferClass;
G_DEFINE_TYPE( VipsForeignLoadMagickBuffer, vips_foreign_load_magick_buffer,
VIPS_TYPE_FOREIGN_LOAD );
static gboolean
vips_foreign_load_magick_buffer_is_a_buffer ( void* buf, size_t len )
{
VipsImage *t;
int result;
t = vips_image_new();
vips_error_freeze();
result = vips__magick_read_buffer_header( buf, len, t, FALSE, NULL );
g_object_unref( t );
vips_error_thaw();
return( result == 0 );
}
static VipsForeignFlags
vips_foreign_load_magick_buffer_get_flags( VipsForeignLoad *load )
{
return( VIPS_FOREIGN_PARTIAL );
}
static int
vips_foreign_load_magick_buffer_header( VipsForeignLoad *load )
{
VipsForeignLoadMagickBuffer *magick = (VipsForeignLoadMagickBuffer *) load;
if( vips__magick_read_buffer_header( magick->buf->data, magick->buf->length,
load->out, magick->all_frames, magick->density ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_magick_buffer_load( VipsForeignLoad *load )
{
VipsForeignLoadMagickBuffer *magick = (VipsForeignLoadMagickBuffer *) load;
if( vips__magick_read_buffer( magick->buf->data, magick->buf->length,
load->real, magick->all_frames, magick->density ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_magick_buffer_class_init( VipsForeignLoadMagickBufferClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "magickload_buffer";
object_class->description = _( "load buffer with ImageMagick" );
/* We need to be well to the back of the queue since the vips's
* dedicated loaders are usually preferable.
*/
foreign_class->priority = -100;
load_class->is_a_buffer = vips_foreign_load_magick_buffer_is_a_buffer;
load_class->get_flags = vips_foreign_load_magick_buffer_get_flags;
load_class->header = vips_foreign_load_magick_buffer_header;
load_class->load = vips_foreign_load_magick_buffer_load;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadMagickBuffer, buf ),
VIPS_TYPE_BLOB );
VIPS_ARG_BOOL( class, "all_frames", 3,
_( "all_frames" ),
_( "Read all frames from an image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadMagickBuffer, all_frames ),
FALSE );
VIPS_ARG_STRING( class, "density", 4,
_( "Density" ),
_( "Canvas resolution for rendering vector formats like SVG" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadMagickBuffer, density ),
NULL );
}
static void
vips_foreign_load_magick_buffer_init( VipsForeignLoadMagickBuffer *buffer )
{
}
#endif /*HAVE_MAGICK*/

View File

@ -435,6 +435,8 @@ int vips_matrixprint( VipsImage *in, ... )
int vips_magickload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_magickload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
/**
* VipsForeignPngFilter:

View File

@ -993,6 +993,7 @@ class_methods = [
"tiffload_buffer",
"openslideload",
"magickload",
"magickload_buffer",
"fitsload",
"openexrload"]