webp write is stream-based

This commit is contained in:
John Cupitt 2019-10-15 16:56:03 +01:00
parent 98410042ac
commit ad7d2b796f
5 changed files with 159 additions and 81 deletions

View File

@ -2025,6 +2025,7 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_load_webp_stream_get_type( void );
extern GType vips_foreign_load_webp_file_get_type( void );
extern GType vips_foreign_load_webp_buffer_get_type( void );
extern GType vips_foreign_save_webp_stream_get_type( void );
extern GType vips_foreign_save_webp_file_get_type( void );
extern GType vips_foreign_save_webp_buffer_get_type( void );
extern GType vips_foreign_load_pdf_get_type( void );
@ -2126,6 +2127,7 @@ vips_foreign_operation_init( void )
vips_foreign_load_webp_stream_get_type();
vips_foreign_load_webp_file_get_type();
vips_foreign_load_webp_buffer_get_type();
vips_foreign_save_webp_stream_get_type();
vips_foreign_save_webp_file_get_type();
vips_foreign_save_webp_buffer_get_type();
#endif /*HAVE_LIBWEBP*/

View File

@ -214,13 +214,7 @@ int vips__webp_read_header_stream( VipsStreamInput *input, VipsImage *out,
int vips__webp_read_stream( VipsStreamInput *input, VipsImage *out,
int page, int n, double scale );
int vips__webp_write_file( VipsImage *out, const char *filename,
int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample, gboolean near_lossless,
int alpha_q, int reduction_effort,
gboolean min_size, int kmin, int kmax,
gboolean strip );
int vips__webp_write_buffer( VipsImage *out, void **buf, size_t *len,
int vips__webp_write_stream( VipsImage *image, VipsStreamOutput *output,
int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample, gboolean near_lossless,
int alpha_q, int reduction_effort,

View File

@ -16,6 +16,8 @@
* - support array of delays
* 8/7/19
* - set loop even if we strip
* 14/10/19
* - revise for stream IO
*/
/*
@ -508,52 +510,7 @@ vips_webp_add_metadata( VipsWebPWrite *write, VipsImage *image, gboolean strip )
}
int
vips__webp_write_file( VipsImage *image, const char *filename,
int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample, gboolean near_lossless,
int alpha_q, int reduction_effort,
gboolean min_size, int kmin, int kmax,
gboolean strip )
{
VipsWebPWrite write;
FILE *fp;
if( vips_webp_write_init( &write, image,
Q, lossless, preset, smart_subsample, near_lossless,
alpha_q, reduction_effort, min_size, kmin, kmax, strip ) )
return( -1 );
if( write_webp( &write, image ) ) {
vips_webp_write_unset( &write );
return( -1 );
}
if( vips_webp_add_metadata( &write, image, strip ) ) {
vips_webp_write_unset( &write );
return( -1 );
}
if( !(fp = vips__file_open_write( filename, FALSE )) ) {
vips_webp_write_unset( &write );
return( -1 );
}
if( vips__file_write(
write.memory_writer.mem, write.memory_writer.size, 1, fp ) ) {
fclose( fp );
vips_webp_write_unset( &write );
return( -1 );
}
fclose( fp );
vips_webp_write_unset( &write );
return( 0 );
}
int
vips__webp_write_buffer( VipsImage *image, void **obuf, size_t *olen,
vips__webp_write_stream( VipsImage *image, VipsStreamOutput *output,
int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample, gboolean near_lossless,
int alpha_q, int reduction_effort,
@ -577,11 +534,13 @@ vips__webp_write_buffer( VipsImage *image, void **obuf, size_t *olen,
return( -1 );
}
*obuf = write.memory_writer.mem;
*olen = write.memory_writer.size;
write.memory_writer.mem = NULL;
write.memory_writer.size = 0;
write.memory_writer.max_size = 0;
if( vips_stream_output_write( output,
write.memory_writer.mem, write.memory_writer.size ) ) {
vips_webp_write_unset( &write );
return( -1 );
}
vips_stream_output_finish( output );
vips_webp_write_unset( &write );

View File

@ -219,6 +219,69 @@ vips_foreign_save_webp_init( VipsForeignSaveWebp *webp )
webp->kmax = INT_MAX;
}
typedef struct _VipsForeignSaveWebpStream {
VipsForeignSaveWebp parent_object;
VipsStreamOutput *output;
} VipsForeignSaveWebpStream;
typedef VipsForeignSaveWebpClass VipsForeignSaveWebpStreamClass;
G_DEFINE_TYPE( VipsForeignSaveWebpStream, vips_foreign_save_webp_stream,
vips_foreign_save_webp_get_type() );
static int
vips_foreign_save_webp_stream_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
VipsForeignSaveWebpStream *stream =
(VipsForeignSaveWebpStream *) object;
if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_stream_parent_class )->
build( object ) )
return( -1 );
if( vips__webp_write_stream( save->ready, stream->output,
webp->Q, webp->lossless, webp->preset,
webp->smart_subsample, webp->near_lossless,
webp->alpha_q, webp->reduction_effort,
webp->min_size, webp->kmin, webp->kmax,
save->strip ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_save_webp_stream_class_init(
VipsForeignSaveWebpStreamClass *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 = "webpsave_stream";
object_class->description = _( "save image to webp stream" );
object_class->build = vips_foreign_save_webp_stream_build;
VIPS_ARG_OBJECT( class, "output", 1,
_( "Output" ),
_( "Stream to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveWebpStream, output ),
VIPS_TYPE_STREAM_OUTPUT );
}
static void
vips_foreign_save_webp_stream_init( VipsForeignSaveWebpStream *stream )
{
}
typedef struct _VipsForeignSaveWebpFile {
VipsForeignSaveWebp parent_object;
@ -240,17 +303,24 @@ vips_foreign_save_webp_file_build( VipsObject *object )
VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
VipsForeignSaveWebpFile *file = (VipsForeignSaveWebpFile *) object;
VipsStreamOutput *output;
if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_file_parent_class )->
build( object ) )
return( -1 );
if( vips__webp_write_file( save->ready, file->filename,
if( !(output = vips_stream_output_new_from_filename( file->filename )) )
return( -1 );
if( vips__webp_write_stream( save->ready, output,
webp->Q, webp->lossless, webp->preset,
webp->smart_subsample, webp->near_lossless,
webp->alpha_q, webp->reduction_effort,
webp->min_size, webp->kmin, webp->kmax,
save->strip ) )
save->strip ) ) {
VIPS_UNREF( output );
return( -1 );
}
VIPS_UNREF( output );
return( 0 );
}
@ -300,28 +370,31 @@ vips_foreign_save_webp_buffer_build( VipsObject *object )
{
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
VipsForeignSaveWebpBuffer *file = (VipsForeignSaveWebpBuffer *) object;
VipsForeignSaveWebpBuffer *buffer =
(VipsForeignSaveWebpBuffer *) object;
void *obuf;
size_t olen;
VipsStreamOutput *output;
VipsBlob *blob;
if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_buffer_parent_class )->
build( object ) )
return( -1 );
if( vips__webp_write_buffer( save->ready, &obuf, &olen,
if( !(output = vips_stream_output_new_memory()) )
return( -1 );
if( vips__webp_write_stream( save->ready, output,
webp->Q, webp->lossless, webp->preset,
webp->smart_subsample, webp->near_lossless,
webp->alpha_q, webp->reduction_effort,
webp->min_size, webp->kmin, webp->kmax,
save->strip ) )
save->strip ) ) {
VIPS_UNREF( output );
return( -1 );
}
/* obuf is a g_free() buffer, not vips_free().
*/
blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen );
g_object_set( file, "buffer", blob, NULL );
g_object_get( output, "blob", &blob, NULL );
g_object_set( buffer, "buffer", blob, NULL );
vips_area_unref( VIPS_AREA( blob ) );
return( 0 );
@ -370,31 +443,40 @@ vips_foreign_save_webp_mime_build( VipsObject *object )
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
void *obuf;
size_t olen;
VipsStreamOutput *output;
VipsBlob *blob;
void *data;
size_t len;
if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_mime_parent_class )->
build( object ) )
return( -1 );
if( vips__webp_write_buffer( save->ready, &obuf, &olen,
if( !(output = vips_stream_output_new_memory()) )
return( -1 );
if( vips__webp_write_stream( save->ready, output,
webp->Q, webp->lossless, webp->preset,
webp->smart_subsample, webp->near_lossless,
webp->alpha_q, webp->reduction_effort,
webp->min_size, webp->kmin, webp->kmax,
save->strip ) )
return( -1 );
printf( "Content-length: %zu\r\n", olen );
printf( "Content-type: image/webp\r\n" );
printf( "\r\n" );
if( fwrite( obuf, sizeof( char ), olen, stdout ) != olen ) {
vips_error( "VipsWebp", "%s", _( "error writing output" ) );
save->strip ) ) {
VIPS_UNREF( output );
return( -1 );
}
g_object_get( output, "blob", &blob, NULL );
data = VIPS_AREA( blob )->data;
len = VIPS_AREA( blob )->length;
vips_area_unref( VIPS_AREA( blob ) );
printf( "Content-length: %zu\r\n", len );
printf( "Content-type: image/webp\r\n" );
printf( "\r\n" );
(void) fwrite( data, sizeof( char ), len, stdout );
fflush( stdout );
g_free( obuf );
VIPS_UNREF( output );
return( 0 );
}
@ -585,3 +667,42 @@ vips_webpsave_mime( VipsImage *in, ... )
return( result );
}
/**
* vips_webpsave_stream: (method)
* @in: image to save
* @output: save image to this stream
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @Q: %gint, quality factor
* * @lossless: %gboolean, enables lossless compression
* * @preset: #VipsForeignWebpPreset, choose lossy compression preset
* * @smart_subsample: %gboolean, enables high quality chroma subsampling
* * @near_lossless: %gboolean, preprocess in lossless mode (controlled by Q)
* * @alpha_q: %gint, set alpha quality in lossless mode
* * @reduction_effort: %gint, level of CPU effort to reduce file size
* * @min_size: %gboolean, minimise size
* * @kmin: %gint, minimum number of frames between keyframes
* * @kmax: %gint, maximum number of frames between keyframes
* * @strip: %gboolean, remove all metadata from image
*
* As vips_webpsave(), but save to a stream.
*
* See also: vips_webpsave().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_webpsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
{
va_list ap;
int result;
va_start( ap, output );
result = vips_call_split( "webpsave_stream", ap, in, output );
va_end( ap );
return( result );
}

View File

@ -406,6 +406,8 @@ int vips_webpload( const char *filename, VipsImage **out, ... )
int vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_webpsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
__attribute__((sentinel));
int vips_webpsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_webpsave_buffer( VipsImage *in, void **buf, size_t *len, ... )