start adding png stream save
doesn't pass the test suite yet
This commit is contained in:
parent
1bdadeed61
commit
55d2ba8a4d
@ -190,14 +190,10 @@ int vips__png_read_stream( VipsStreamInput *input, VipsImage *out,
|
|||||||
gboolean vips__png_isinterlaced_stream( VipsStreamInput *input );
|
gboolean vips__png_isinterlaced_stream( VipsStreamInput *input );
|
||||||
extern const char *vips__png_suffs[];
|
extern const char *vips__png_suffs[];
|
||||||
|
|
||||||
int vips__png_write( VipsImage *in, const char *filename,
|
int vips__png_write_stream( VipsImage *in, VipsStreamOutput *output,
|
||||||
int compress, int interlace, const char *profile,
|
int compress, int interlace, const char *profile,
|
||||||
VipsForeignPngFilter filter, gboolean strip,
|
VipsForeignPngFilter filter, gboolean strip,
|
||||||
gboolean palette, int colours, int Q, double dither );
|
gboolean palette, int colours, int Q, double dither );
|
||||||
int vips__png_write_buf( VipsImage *in,
|
|
||||||
void **obuf, size_t *olen, int compression, int interlace,
|
|
||||||
const char *profile, VipsForeignPngFilter filter, gboolean strip,
|
|
||||||
gboolean palette, int colours, int Q, double dither );
|
|
||||||
|
|
||||||
/* Map WEBP metadata names to vips names.
|
/* Map WEBP metadata names to vips names.
|
||||||
*/
|
*/
|
||||||
|
@ -179,6 +179,63 @@ vips_foreign_save_png_init( VipsForeignSavePng *png )
|
|||||||
png->dither = 1.0;
|
png->dither = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsForeignSavePngStream {
|
||||||
|
VipsForeignSavePng parent_object;
|
||||||
|
|
||||||
|
VipsStreamOutput *output;
|
||||||
|
} VipsForeignSavePngStream;
|
||||||
|
|
||||||
|
typedef VipsForeignSavePngClass VipsForeignSavePngStreamClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignSavePngStream, vips_foreign_save_png_stream,
|
||||||
|
vips_foreign_save_png_get_type() );
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_save_png_stream_build( VipsObject *object )
|
||||||
|
{
|
||||||
|
VipsForeignSave *save = (VipsForeignSave *) object;
|
||||||
|
VipsForeignSavePng *png = (VipsForeignSavePng *) object;
|
||||||
|
VipsForeignSavePngStream *stream = (VipsForeignSavePngStream *) object;
|
||||||
|
|
||||||
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_png_stream_parent_class )->
|
||||||
|
build( object ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( vips__png_write_stream( save->ready, stream->output,
|
||||||
|
png->compression, png->interlace, png->profile, png->filter,
|
||||||
|
save->strip, png->palette, png->colours, png->Q, png->dither ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_save_png_stream_class_init( VipsForeignSavePngStreamClass *class )
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||||
|
|
||||||
|
gobject_class->set_property = vips_object_set_property;
|
||||||
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
|
object_class->nickname = "pngsave_stream";
|
||||||
|
object_class->description = _( "save image to png stream" );
|
||||||
|
object_class->build = vips_foreign_save_png_stream_build;
|
||||||
|
|
||||||
|
VIPS_ARG_OBJECT( class, "output", 1,
|
||||||
|
_( "Output" ),
|
||||||
|
_( "Stream to save to" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignSavePngStream, output ),
|
||||||
|
VIPS_TYPE_STREAM_OUTPUT );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_save_png_stream_init( VipsForeignSavePngStream *stream )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _VipsForeignSavePngFile {
|
typedef struct _VipsForeignSavePngFile {
|
||||||
VipsForeignSavePng parent_object;
|
VipsForeignSavePng parent_object;
|
||||||
|
|
||||||
@ -197,15 +254,23 @@ vips_foreign_save_png_file_build( VipsObject *object )
|
|||||||
VipsForeignSavePng *png = (VipsForeignSavePng *) object;
|
VipsForeignSavePng *png = (VipsForeignSavePng *) object;
|
||||||
VipsForeignSavePngFile *png_file = (VipsForeignSavePngFile *) object;
|
VipsForeignSavePngFile *png_file = (VipsForeignSavePngFile *) object;
|
||||||
|
|
||||||
|
VipsStreamOutput *output;
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_foreign_save_png_file_parent_class )->
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_png_file_parent_class )->
|
||||||
build( object ) )
|
build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( vips__png_write( save->ready,
|
if( !(output = vips_stream_output_new_from_filename(
|
||||||
png_file->filename, png->compression, png->interlace,
|
png_file->filename )) )
|
||||||
png->profile, png->filter, save->strip, png->palette,
|
|
||||||
png->colours, png->Q, png->dither ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
if( vips__png_write_stream( save->ready, output,
|
||||||
|
png->compression, png->interlace,
|
||||||
|
png->profile, png->filter, save->strip, png->palette,
|
||||||
|
png->colours, png->Q, png->dither ) ) {
|
||||||
|
VIPS_UNREF( output );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
VIPS_UNREF( output );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -252,27 +317,32 @@ vips_foreign_save_png_buffer_build( VipsObject *object )
|
|||||||
{
|
{
|
||||||
VipsForeignSave *save = (VipsForeignSave *) object;
|
VipsForeignSave *save = (VipsForeignSave *) object;
|
||||||
VipsForeignSavePng *png = (VipsForeignSavePng *) object;
|
VipsForeignSavePng *png = (VipsForeignSavePng *) object;
|
||||||
|
VipsForeignSavePngBuffer *buffer = (VipsForeignSavePngBuffer *) object;
|
||||||
|
|
||||||
void *obuf;
|
VipsStreamOutput *output;
|
||||||
size_t olen;
|
|
||||||
VipsBlob *blob;
|
VipsBlob *blob;
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_foreign_save_png_buffer_parent_class )->
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_png_buffer_parent_class )->
|
||||||
build( object ) )
|
build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( vips__png_write_buf( save->ready, &obuf, &olen,
|
if( !(output = vips_stream_output_new_memory()) )
|
||||||
png->compression, png->interlace, png->profile, png->filter,
|
|
||||||
save->strip, png->palette, png->colours, png->Q, png->dither ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* vips__png_write_buf() makes a buffer that needs g_free(), not
|
if( vips__png_write_stream( save->ready, output,
|
||||||
* vips_free().
|
png->compression, png->interlace, png->profile, png->filter,
|
||||||
*/
|
save->strip, png->palette, png->colours, png->Q,
|
||||||
blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen );
|
png->dither ) ) {
|
||||||
g_object_set( object, "buffer", blob, NULL );
|
VIPS_UNREF( output );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_get( output, "blob", &blob, NULL );
|
||||||
|
g_object_set( buffer, "buffer", blob, NULL );
|
||||||
vips_area_unref( VIPS_AREA( blob ) );
|
vips_area_unref( VIPS_AREA( blob ) );
|
||||||
|
|
||||||
|
VIPS_UNREF( output );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,3 +497,39 @@ vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
|||||||
|
|
||||||
return( result );
|
return( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vips_pngsave_stream: (method)
|
||||||
|
* @in: image to save
|
||||||
|
* @output: save image to this stream
|
||||||
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* * @compression: compression level
|
||||||
|
* * @interlace: interlace image
|
||||||
|
* * @profile: ICC profile to embed
|
||||||
|
* * @filter: libpng row filter flag(s)
|
||||||
|
* * @palette: enable quantisation to 8bpp palette
|
||||||
|
* * @colours: max number of palette colours for quantisation
|
||||||
|
* * @Q: quality for 8bpp quantisation (does not exceed @colours)
|
||||||
|
* * @dither: amount of dithering for 8bpp quantization
|
||||||
|
*
|
||||||
|
* As vips_pngsave(), but save to a stream.
|
||||||
|
*
|
||||||
|
* See also: vips_pngsave(), vips_image_write_to_stream().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vips_pngsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
va_start( ap, output );
|
||||||
|
result = vips_call_split( "pngsave_stream", ap, in, output );
|
||||||
|
va_end( ap );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
@ -780,8 +780,7 @@ typedef struct {
|
|||||||
VipsImage *in;
|
VipsImage *in;
|
||||||
VipsImage *memory;
|
VipsImage *memory;
|
||||||
|
|
||||||
FILE *fp;
|
VipsStreamOutput *output;
|
||||||
VipsDbuf dbuf;
|
|
||||||
|
|
||||||
png_structp pPng;
|
png_structp pPng;
|
||||||
png_infop pInfo;
|
png_infop pInfo;
|
||||||
@ -791,9 +790,8 @@ typedef struct {
|
|||||||
static void
|
static void
|
||||||
write_finish( Write *write )
|
write_finish( Write *write )
|
||||||
{
|
{
|
||||||
VIPS_FREEF( fclose, write->fp );
|
|
||||||
VIPS_UNREF( write->memory );
|
VIPS_UNREF( write->memory );
|
||||||
vips_dbuf_destroy( &write->dbuf );
|
VIPS_UNREF( write->output );
|
||||||
if( write->pPng )
|
if( write->pPng )
|
||||||
png_destroy_write_struct( &write->pPng, &write->pInfo );
|
png_destroy_write_struct( &write->pPng, &write->pInfo );
|
||||||
}
|
}
|
||||||
@ -804,8 +802,17 @@ write_destroy( VipsImage *out, Write *write )
|
|||||||
write_finish( write );
|
write_finish( write );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
user_write_data( png_structp pPng, png_bytep data, png_size_t length )
|
||||||
|
{
|
||||||
|
Write *write = (Write *) png_get_io_ptr( pPng );
|
||||||
|
|
||||||
|
if( vips_stream_output_write( write->output, data, length ) )
|
||||||
|
png_error( pPng, "not enough data" );
|
||||||
|
}
|
||||||
|
|
||||||
static Write *
|
static Write *
|
||||||
write_new( VipsImage *in )
|
write_new( VipsImage *in, VipsStreamOutput *output )
|
||||||
{
|
{
|
||||||
Write *write;
|
Write *write;
|
||||||
|
|
||||||
@ -814,8 +821,8 @@ write_new( VipsImage *in )
|
|||||||
memset( write, 0, sizeof( Write ) );
|
memset( write, 0, sizeof( Write ) );
|
||||||
write->in = in;
|
write->in = in;
|
||||||
write->memory = NULL;
|
write->memory = NULL;
|
||||||
write->fp = NULL;
|
write->output = output;
|
||||||
vips_dbuf_init( &write->dbuf );
|
g_object_ref( output );
|
||||||
g_signal_connect( in, "close",
|
g_signal_connect( in, "close",
|
||||||
G_CALLBACK( write_destroy ), write );
|
G_CALLBACK( write_destroy ), write );
|
||||||
|
|
||||||
@ -833,6 +840,8 @@ write_new( VipsImage *in )
|
|||||||
PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON );
|
PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON );
|
||||||
#endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/
|
#endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/
|
||||||
|
|
||||||
|
png_set_write_fn( write->pPng, write, user_write_data, NULL );
|
||||||
|
|
||||||
/* Catch PNG errors from png_create_info_struct().
|
/* Catch PNG errors from png_create_info_struct().
|
||||||
*/
|
*/
|
||||||
if( setjmp( png_jmpbuf( write->pPng ) ) )
|
if( setjmp( png_jmpbuf( write->pPng ) ) )
|
||||||
@ -1176,80 +1185,25 @@ write_vips( Write *write,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips__png_write( VipsImage *in, const char *filename,
|
vips__png_write_stream( VipsImage *in, VipsStreamOutput *output,
|
||||||
int compress, int interlace, const char *profile,
|
int compression, int interlace,
|
||||||
VipsForeignPngFilter filter, gboolean strip,
|
|
||||||
gboolean palette, int colours, int Q, double dither )
|
|
||||||
{
|
|
||||||
Write *write;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "vips__png_write: writing \"%s\"\n", filename );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
if( !(write = write_new( in )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Make output.
|
|
||||||
*/
|
|
||||||
if( !(write->fp = vips__file_open_write( filename, FALSE )) )
|
|
||||||
return( -1 );
|
|
||||||
png_init_io( write->pPng, write->fp );
|
|
||||||
|
|
||||||
/* Convert it!
|
|
||||||
*/
|
|
||||||
if( write_vips( write,
|
|
||||||
compress, interlace, profile, filter, strip, palette,
|
|
||||||
colours, Q, dither ) ) {
|
|
||||||
vips_error( "vips2png",
|
|
||||||
_( "unable to write \"%s\"" ), filename );
|
|
||||||
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
write_finish( write );
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "vips__png_write: done\n" );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
user_write_data( png_structp png_ptr, png_bytep data, png_size_t length )
|
|
||||||
{
|
|
||||||
Write *write = (Write *) png_get_io_ptr( png_ptr );
|
|
||||||
|
|
||||||
vips_dbuf_write( &write->dbuf, data, length );
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
vips__png_write_buf( VipsImage *in,
|
|
||||||
void **obuf, size_t *olen, int compression, int interlace,
|
|
||||||
const char *profile, VipsForeignPngFilter filter, gboolean strip,
|
const char *profile, VipsForeignPngFilter filter, gboolean strip,
|
||||||
gboolean palette, int colours, int Q, double dither )
|
gboolean palette, int colours, int Q, double dither )
|
||||||
{
|
{
|
||||||
Write *write;
|
Write *write;
|
||||||
|
|
||||||
if( !(write = write_new( in )) )
|
if( !(write = write_new( in, output )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
png_set_write_fn( write->pPng, write, user_write_data, NULL );
|
|
||||||
|
|
||||||
/* Convert it!
|
|
||||||
*/
|
|
||||||
if( write_vips( write,
|
if( write_vips( write,
|
||||||
compression, interlace, profile, filter, strip, palette,
|
compression, interlace, profile, filter, strip, palette,
|
||||||
colours, Q, dither ) ) {
|
colours, Q, dither ) ) {
|
||||||
|
write_finish( write );
|
||||||
vips_error( "vips2png",
|
vips_error( "vips2png",
|
||||||
"%s", _( "unable to write to buffer" ) );
|
"%s", _( "unable to write to buffer" ) );
|
||||||
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
*obuf = vips_dbuf_steal( &write->dbuf, olen );
|
|
||||||
|
|
||||||
write_finish( write );
|
write_finish( write );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
@ -369,6 +369,8 @@ int vips_jpegload( const char *filename, VipsImage **out, ... )
|
|||||||
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
|
||||||
|
int vips_jpegsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
int vips_jpegsave( VipsImage *in, const char *filename, ... )
|
int vips_jpegsave( VipsImage *in, const char *filename, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
int vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
int vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
||||||
@ -547,6 +549,8 @@ int vips_pngload( const char *filename, VipsImage **out, ... )
|
|||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
int vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
int vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
int vips_pngsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
int vips_pngsave( VipsImage *in, const char *filename, ... )
|
int vips_pngsave( VipsImage *in, const char *filename, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
int vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
int vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
||||||
|
Loading…
Reference in New Issue
Block a user