start adding png stream save

doesn't pass the test suite yet
This commit is contained in:
John Cupitt 2019-10-14 18:32:41 +01:00
parent 1bdadeed61
commit 55d2ba8a4d
4 changed files with 146 additions and 86 deletions

View File

@ -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.
*/ */

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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, ... )