add png load from buffer
though untested as yet
This commit is contained in:
parent
1dbff8f5c0
commit
005984226e
@ -1583,6 +1583,7 @@ vips_foreign_operation_init( void )
|
||||
extern GType vips_foreign_load_ppm_get_type( void );
|
||||
extern GType vips_foreign_save_ppm_get_type( void );
|
||||
extern GType vips_foreign_load_png_get_type( void );
|
||||
extern GType vips_foreign_load_png_buffer_get_type( void );
|
||||
extern GType vips_foreign_save_png_file_get_type( void );
|
||||
extern GType vips_foreign_save_png_buffer_get_type( void );
|
||||
extern GType vips_foreign_load_csv_get_type( void );
|
||||
@ -1623,6 +1624,7 @@ vips_foreign_operation_init( void )
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
vips_foreign_load_png_get_type();
|
||||
vips_foreign_load_png_buffer_get_type();
|
||||
vips_foreign_save_png_file_get_type();
|
||||
vips_foreign_save_png_buffer_get_type();
|
||||
#endif /*HAVE_PNG*/
|
||||
@ -2224,6 +2226,47 @@ vips_pngload( const char *filename, VipsImage **out, ... )
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_pngload_buffer:
|
||||
* @buf: memory area to load
|
||||
* @len: size of memory area
|
||||
* @out: image to write
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Read a PNG-formatted memory block into a VIPS image. It can read all png
|
||||
* images, including 8- and 16-bit images, 1 and 3 channel, with and without
|
||||
* an alpha channel.
|
||||
*
|
||||
* Any ICC profile is read and attached to the VIPS image.
|
||||
*
|
||||
* Caution: on return only the header will have been read, the pixel data is
|
||||
* not decompressed until the first pixel is read. Therefore you must not free
|
||||
* @buf until you have read pixel data from @out.
|
||||
*
|
||||
* See also: vips_pngload().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
VipsArea *area;
|
||||
int result;
|
||||
|
||||
/* We don't take a copy of the data or free it.
|
||||
*/
|
||||
area = vips_area_new_blob( NULL, buf, len );
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "pngload_buffer", ap, area, out );
|
||||
va_end( ap );
|
||||
|
||||
vips_area_unref( area );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_pngsave:
|
||||
* @in: image to save
|
||||
|
@ -73,9 +73,9 @@ vips_foreign_load_png_get_flags_filename( const char *filename )
|
||||
|
||||
flags = 0;
|
||||
if( vips__png_isinterlaced( filename ) )
|
||||
flags = VIPS_FOREIGN_PARTIAL;
|
||||
flags |= VIPS_FOREIGN_PARTIAL;
|
||||
else
|
||||
flags = VIPS_FOREIGN_SEQUENTIAL;
|
||||
flags |= VIPS_FOREIGN_SEQUENTIAL;
|
||||
|
||||
return( flags );
|
||||
}
|
||||
@ -146,4 +146,72 @@ vips_foreign_load_png_init( VipsForeignLoadPng *png )
|
||||
{
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignLoadPngBuffer {
|
||||
VipsForeignLoad parent_object;
|
||||
|
||||
/* Load from a buffer.
|
||||
*/
|
||||
VipsArea *buf;
|
||||
|
||||
} VipsForeignLoadPngBuffer;
|
||||
|
||||
typedef VipsForeignLoadClass VipsForeignLoadPngBufferClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer,
|
||||
VIPS_TYPE_FOREIGN_LOAD );
|
||||
|
||||
static int
|
||||
vips_foreign_load_png_buffer_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadPngBuffer *png = (VipsForeignLoadPngBuffer *) load;
|
||||
|
||||
if( vips__png_header_buffer( load->out,
|
||||
png->buf->data, png->buf->length ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_png_buffer_load( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadPngBuffer *png = (VipsForeignLoadPngBuffer *) load;
|
||||
|
||||
if( vips__png_read_buffer( load->out,
|
||||
png->buf->data, png->buf->length ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_png_buffer_class_init( VipsForeignLoadPngBufferClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) 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 = "pngload_buffer";
|
||||
object_class->description = _( "load png from buffer" );
|
||||
|
||||
load_class->header = vips_foreign_load_png_buffer_header;
|
||||
load_class->load = vips_foreign_load_png_buffer_load;
|
||||
|
||||
VIPS_ARG_BOXED( class, "buffer", 1,
|
||||
_( "Buffer" ),
|
||||
_( "Buffer to load from" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadPngBuffer, buf ),
|
||||
VIPS_TYPE_BLOB );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *png )
|
||||
{
|
||||
}
|
||||
|
||||
#endif /*HAVE_PNG*/
|
||||
|
||||
|
@ -125,11 +125,20 @@ typedef struct {
|
||||
char *name;
|
||||
VipsImage *out;
|
||||
|
||||
FILE *fp;
|
||||
int y_pos;
|
||||
png_structp pPng;
|
||||
png_infop pInfo;
|
||||
png_bytep *row_pointer;
|
||||
|
||||
/* For FILE input.
|
||||
*/
|
||||
FILE *fp;
|
||||
|
||||
/* For memory input.
|
||||
*/
|
||||
char *buffer;
|
||||
size_t length;
|
||||
size_t read_pos;
|
||||
} Read;
|
||||
|
||||
static void
|
||||
@ -142,27 +151,27 @@ read_destroy( VipsImage *out, Read *read )
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new( const char *name, VipsImage *out )
|
||||
read_new( VipsImage *out )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = VIPS_NEW( out, Read )) )
|
||||
return( NULL );
|
||||
|
||||
read->name = vips_strdup( VIPS_OBJECT( out ), name );
|
||||
read->name = NULL;
|
||||
read->out = out;
|
||||
read->fp = NULL;
|
||||
read->y_pos = 0;
|
||||
read->pPng = NULL;
|
||||
read->pInfo = NULL;
|
||||
read->row_pointer = NULL;
|
||||
read->fp = NULL;
|
||||
read->buffer = NULL;
|
||||
read->length = 0;
|
||||
read->read_pos = 0;
|
||||
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( read_destroy ), read );
|
||||
|
||||
if( !(read->fp = vips__file_open_read( name, NULL, FALSE )) )
|
||||
return( NULL );
|
||||
|
||||
if( !(read->pPng = png_create_read_struct(
|
||||
PNG_LIBPNG_VER_STRING, NULL,
|
||||
user_error_function, user_warning_function )) )
|
||||
@ -176,6 +185,22 @@ read_new( const char *name, VipsImage *out )
|
||||
if( !(read->pInfo = png_create_info_struct( read->pPng )) )
|
||||
return( NULL );
|
||||
|
||||
return( read );
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new_filename( VipsImage *out, const char *name )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( out )) )
|
||||
return( NULL );
|
||||
|
||||
read->name = vips_strdup( VIPS_OBJECT( out ), name );
|
||||
|
||||
if( !(read->fp = vips__file_open_read( name, NULL, FALSE )) )
|
||||
return( NULL );
|
||||
|
||||
/* Read enough of the file that png_get_interlace_type() will start
|
||||
* working.
|
||||
*/
|
||||
@ -366,7 +391,7 @@ vips__png_header( const char *name, VipsImage *out )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( name, out )) ||
|
||||
if( !(read = read_new_filename( out, name )) ||
|
||||
png2vips_header( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
@ -465,7 +490,7 @@ vips__png_isinterlaced( const char *filename )
|
||||
int interlace_type;
|
||||
|
||||
image = vips_image_new();
|
||||
if( !(read = read_new( filename, image )) ) {
|
||||
if( !(read = read_new_filename( image, filename )) ) {
|
||||
g_object_unref( image );
|
||||
return( -1 );
|
||||
}
|
||||
@ -475,24 +500,13 @@ vips__png_isinterlaced( const char *filename )
|
||||
return( interlace_type != PNG_INTERLACE_NONE );
|
||||
}
|
||||
|
||||
int
|
||||
vips__png_read( const char *filename, VipsImage *out )
|
||||
static int
|
||||
read_all( Read *read, VipsImage *out )
|
||||
{
|
||||
int interlace_type = png_get_interlace_type( read->pPng, read->pInfo );
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( VIPS_OBJECT( out ), 3 );
|
||||
|
||||
Read *read;
|
||||
int interlace_type;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__png_read: reading \"%s\"\n", filename );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !(read = read_new( filename, out )) )
|
||||
return( -1 );
|
||||
|
||||
interlace_type = png_get_interlace_type( read->pPng, read->pInfo );
|
||||
|
||||
if( interlace_type != PNG_INTERLACE_NONE ) {
|
||||
/* Arg awful interlaced image. We have to load to a huge mem
|
||||
* buffer, then copy to out.
|
||||
@ -516,6 +530,22 @@ vips__png_read( const char *filename, VipsImage *out )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__png_read( const char *filename, VipsImage *out )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__png_read: reading \"%s\"\n", filename );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( !(read = read_new_filename( out, filename )) ||
|
||||
read_all( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips__png_read: done\n" );
|
||||
#endif /*DEBUG*/
|
||||
@ -532,6 +562,63 @@ vips__png_ispng( const char *filename )
|
||||
!png_sig_cmp( buf, 0, 8 ) );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_png_read_buffer( png_structp pPng, png_bytep data, png_size_t length )
|
||||
{
|
||||
Read *read = png_get_io_ptr( pPng );
|
||||
|
||||
if( read->read_pos + length > read->length )
|
||||
png_error( pPng, "not enough data in buffer" );
|
||||
|
||||
memcpy( data, read->buffer + read->read_pos, length );
|
||||
read->read_pos += length;
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new_buffer( VipsImage *out, char *buffer, size_t length )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( out )) )
|
||||
return( NULL );
|
||||
|
||||
read->buffer = buffer;
|
||||
read->length = length;
|
||||
|
||||
png_set_read_fn( read->pPng, read, vips_png_read_buffer );
|
||||
|
||||
/* Read enough of the file that png_get_interlace_type() will start
|
||||
* working.
|
||||
*/
|
||||
png_read_info( read->pPng, read->pInfo );
|
||||
|
||||
return( read );
|
||||
}
|
||||
|
||||
int
|
||||
vips__png_header_buffer( VipsImage *out, char *buffer, size_t length )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new_buffer( out, buffer, length )) ||
|
||||
png2vips_header( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__png_read_buffer( VipsImage *out, char *buffer, size_t length )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new_buffer( out, buffer, length )) ||
|
||||
read_all( read, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
const char *vips__png_suffs[] = { ".png", NULL };
|
||||
|
||||
/* What we track during a PNG write.
|
||||
|
@ -40,6 +40,8 @@ int vips__png_read( const char *name, VipsImage *out );
|
||||
int vips__png_ispng( const char *filename );
|
||||
gboolean vips__png_isinterlaced( const char *filename );
|
||||
extern const char *vips__png_suffs[];
|
||||
int vips__png_read_buffer( VipsImage *out, char *buffer, size_t length );
|
||||
int vips__png_header_buffer( VipsImage *out, char *buffer, size_t length );
|
||||
|
||||
int vips__png_write( VipsImage *in, const char *filename,
|
||||
int compress, int interlace );
|
||||
|
@ -407,6 +407,8 @@ int vips_magickload( const char *filename, VipsImage **out, ... )
|
||||
|
||||
int vips_pngload( const char *filename, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_pngsave( VipsImage *in, const char *filename, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
||||
|
Loading…
Reference in New Issue
Block a user