1 /* save to webp
2  *
3  * 24/11/11
4  * 	- wrap a class around the webp writer
5  * 29/10/18
6  * 	- add animated webp support
7  * 15/1/19 lovell
8  * 	- add @effort
9  * 18/7/20
10  * 	- add @profile param to match tiff, jpg, etc.
11  * 30/7/21
12  * 	- rename "reduction-effort" as "effort"
13  */
14 
15 /*
16 
17     This file is part of VIPS.
18 
19     VIPS is free software; you can redistribute it and/or modify
20     it under the terms of the GNU Lesser General Public License as published by
21     the Free Software Foundation; either version 2 of the License, or
22     (at your option) any later version.
23 
24     This program is distributed in the hope that it will be useful,
25     but WITHOUT ANY WARRANTY; without even the implied warranty of
26     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27     GNU Lesser General Public License for more details.
28 
29     You should have received a copy of the GNU Lesser General Public License
30     along with this program; if not, write to the Free Software
31     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32     02110-1301  USA
33 
34  */
35 
36 /*
37 
38     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
39 
40  */
41 
42 /*
43 #define DEBUG_VERBOSE
44 #define DEBUG
45  */
46 
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif /*HAVE_CONFIG_H*/
50 #include <vips/intl.h>
51 
52 #include <stdlib.h>
53 
54 #include <vips/vips.h>
55 
56 #include "pforeign.h"
57 
58 #ifdef HAVE_LIBWEBP
59 
60 typedef struct _VipsForeignSaveWebp {
61 	VipsForeignSave parent_object;
62 
63 	/* Quality factor.
64 	 */
65 	int Q;
66 
67 	/* Turn on lossless encode.
68 	 */
69 	gboolean lossless;
70 
71 	/* Lossy compression preset.
72 	 */
73 	VipsForeignWebpPreset preset;
74 
75 	/* Enable smart chroma subsampling.
76 	 */
77 	gboolean smart_subsample;
78 
79 	/* Use preprocessing in lossless mode.
80 	 */
81 	gboolean near_lossless;
82 
83 	/* Alpha quality.
84 	 */
85 	int alpha_q;
86 
87 	/* Level of CPU effort to reduce file size.
88 	 */
89 	int effort;
90 
91 	/* Animated webp options.
92 	 */
93 
94 	/* Attempt to minimise size
95 	 */
96 	gboolean min_size;
97 
98 	/* Min between key frames.
99 	 */
100 	int kmin;
101 
102 	/* Max between keyframes.
103 	 */
104 	int kmax;
105 
106 	/* Profile to embed.
107 	 */
108 	char *profile;
109 
110 } VipsForeignSaveWebp;
111 
112 typedef VipsForeignSaveClass VipsForeignSaveWebpClass;
113 
114 G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveWebp, vips_foreign_save_webp,
115 	VIPS_TYPE_FOREIGN_SAVE );
116 
117 #define UC VIPS_FORMAT_UCHAR
118 
119 /* Type promotion for save ... just always go to uchar.
120  */
121 static int bandfmt_webp[10] = {
122 /* UC  C   US  S   UI  I   F   X   D   DX */
123    UC, UC, UC, UC, UC, UC, UC, UC, UC, UC
124 };
125 
126 static void
vips_foreign_save_webp_class_init(VipsForeignSaveWebpClass * class)127 vips_foreign_save_webp_class_init( VipsForeignSaveWebpClass *class )
128 {
129 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
130 	VipsObjectClass *object_class = (VipsObjectClass *) class;
131 	VipsForeignClass *foreign_class = (VipsForeignClass *) class;
132 	VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
133 
134 	gobject_class->set_property = vips_object_set_property;
135 	gobject_class->get_property = vips_object_get_property;
136 
137 	object_class->nickname = "webpsave_base";
138 	object_class->description = _( "save webp" );
139 
140 	foreign_class->suffs = vips__webp_suffs;
141 
142 	save_class->saveable = VIPS_SAVEABLE_RGBA_ONLY;
143 	save_class->format_table = bandfmt_webp;
144 
145 	VIPS_ARG_INT( class, "Q", 10,
146 		_( "Q" ),
147 		_( "Q factor" ),
148 		VIPS_ARGUMENT_OPTIONAL_INPUT,
149 		G_STRUCT_OFFSET( VipsForeignSaveWebp, Q ),
150 		0, 100, 75 );
151 
152 	VIPS_ARG_BOOL( class, "lossless", 11,
153 		_( "lossless" ),
154 		_( "enable lossless compression" ),
155 		VIPS_ARGUMENT_OPTIONAL_INPUT,
156 		G_STRUCT_OFFSET( VipsForeignSaveWebp, lossless ),
157 		FALSE );
158 
159 	VIPS_ARG_ENUM( class, "preset", 12,
160 		_( "preset" ),
161 		_( "Preset for lossy compression" ),
162 		VIPS_ARGUMENT_OPTIONAL_INPUT,
163 		G_STRUCT_OFFSET( VipsForeignSaveWebp, preset ),
164 		VIPS_TYPE_FOREIGN_WEBP_PRESET,
165 		VIPS_FOREIGN_WEBP_PRESET_DEFAULT );
166 
167 	VIPS_ARG_BOOL( class, "smart_subsample", 13,
168 		_( "Smart subsampling" ),
169 		_( "Enable high quality chroma subsampling" ),
170 		VIPS_ARGUMENT_OPTIONAL_INPUT,
171 		G_STRUCT_OFFSET( VipsForeignSaveWebp, smart_subsample ),
172 		FALSE );
173 
174 	VIPS_ARG_BOOL( class, "near_lossless", 14,
175 		_( "Near lossless" ),
176 		_( "Enable preprocessing in lossless mode (uses Q)" ),
177 		VIPS_ARGUMENT_OPTIONAL_INPUT,
178 		G_STRUCT_OFFSET( VipsForeignSaveWebp, near_lossless ),
179 		FALSE );
180 
181 	VIPS_ARG_INT( class, "alpha_q", 15,
182 		_( "Alpha quality" ),
183 		_( "Change alpha plane fidelity for lossy compression" ),
184 		VIPS_ARGUMENT_OPTIONAL_INPUT,
185 		G_STRUCT_OFFSET( VipsForeignSaveWebp, alpha_q ),
186 		0, 100, 100 );
187 
188 	VIPS_ARG_BOOL( class, "min_size", 16,
189 		_( "Minimise size" ),
190 		_( "Optimise for minium size" ),
191 		VIPS_ARGUMENT_OPTIONAL_INPUT,
192 		G_STRUCT_OFFSET( VipsForeignSaveWebp, min_size ),
193 		FALSE );
194 
195 	VIPS_ARG_INT( class, "kmin", 17,
196 		_( "Minimum keyframe spacing" ),
197 		_( "Minimum number of frames between key frames" ),
198 		VIPS_ARGUMENT_OPTIONAL_INPUT,
199 		G_STRUCT_OFFSET( VipsForeignSaveWebp, kmin ),
200 		0, INT_MAX, INT_MAX - 1 );
201 
202 	VIPS_ARG_INT( class, "kmax", 18,
203 		_( "Maximum keyframe spacing" ),
204 		_( "Maximum number of frames between key frames" ),
205 		VIPS_ARGUMENT_OPTIONAL_INPUT,
206 		G_STRUCT_OFFSET( VipsForeignSaveWebp, kmax ),
207 		0, INT_MAX, INT_MAX );
208 
209 	VIPS_ARG_INT( class, "effort", 19,
210 		_( "Effort" ),
211 		_( "Level of CPU effort to reduce file size" ),
212 		VIPS_ARGUMENT_OPTIONAL_INPUT,
213 		G_STRUCT_OFFSET( VipsForeignSaveWebp, effort ),
214 		0, 6, 4 );
215 
216 	VIPS_ARG_STRING( class, "profile", 20,
217 		_( "Profile" ),
218 		_( "ICC profile to embed" ),
219 		VIPS_ARGUMENT_OPTIONAL_INPUT,
220 		G_STRUCT_OFFSET( VipsForeignSaveWebp, profile ),
221 		NULL );
222 
223 	VIPS_ARG_INT( class, "reduction-effort", 21,
224 		_( "Reduction effort" ),
225 		_( "Level of CPU effort to reduce file size" ),
226 		VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
227 		G_STRUCT_OFFSET( VipsForeignSaveWebp, effort ),
228 		0, 6, 4 );
229 }
230 
231 static void
vips_foreign_save_webp_init(VipsForeignSaveWebp * webp)232 vips_foreign_save_webp_init( VipsForeignSaveWebp *webp )
233 {
234 	webp->Q = 75;
235 	webp->alpha_q = 100;
236 	webp->effort = 4;
237 
238 	/* ie. keyframes disabled by default.
239 	 */
240 	webp->kmin = INT_MAX - 1;
241 	webp->kmax = INT_MAX;
242 }
243 
244 typedef struct _VipsForeignSaveWebpTarget {
245 	VipsForeignSaveWebp parent_object;
246 
247 	VipsTarget *target;
248 
249 } VipsForeignSaveWebpTarget;
250 
251 typedef VipsForeignSaveWebpClass VipsForeignSaveWebpTargetClass;
252 
253 G_DEFINE_TYPE( VipsForeignSaveWebpTarget, vips_foreign_save_webp_target,
254 	vips_foreign_save_webp_get_type() );
255 
256 static int
vips_foreign_save_webp_target_build(VipsObject * object)257 vips_foreign_save_webp_target_build( VipsObject *object )
258 {
259 	VipsForeignSave *save = (VipsForeignSave *) object;
260 	VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
261 	VipsForeignSaveWebpTarget *target =
262 		(VipsForeignSaveWebpTarget *) object;
263 
264 	if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_target_parent_class )->
265 		build( object ) )
266 		return( -1 );
267 
268 	if( vips__webp_write_target( save->ready, target->target,
269 		webp->Q, webp->lossless, webp->preset,
270 		webp->smart_subsample, webp->near_lossless,
271 		webp->alpha_q, webp->effort,
272 		webp->min_size, webp->kmin, webp->kmax,
273 		save->strip, webp->profile ) )
274 		return( -1 );
275 
276 	return( 0 );
277 }
278 
279 static void
vips_foreign_save_webp_target_class_init(VipsForeignSaveWebpTargetClass * class)280 vips_foreign_save_webp_target_class_init(
281 	VipsForeignSaveWebpTargetClass *class )
282 {
283 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
284 	VipsObjectClass *object_class = (VipsObjectClass *) class;
285 
286 	gobject_class->set_property = vips_object_set_property;
287 	gobject_class->get_property = vips_object_get_property;
288 
289 	object_class->nickname = "webpsave_target";
290 	object_class->description = _( "save image to webp target" );
291 	object_class->build = vips_foreign_save_webp_target_build;
292 
293 	VIPS_ARG_OBJECT( class, "target", 1,
294 		_( "Target" ),
295 		_( "Target to save to" ),
296 		VIPS_ARGUMENT_REQUIRED_INPUT,
297 		G_STRUCT_OFFSET( VipsForeignSaveWebpTarget, target ),
298 		VIPS_TYPE_TARGET );
299 }
300 
301 static void
vips_foreign_save_webp_target_init(VipsForeignSaveWebpTarget * target)302 vips_foreign_save_webp_target_init( VipsForeignSaveWebpTarget *target )
303 {
304 }
305 
306 
307 typedef struct _VipsForeignSaveWebpFile {
308 	VipsForeignSaveWebp parent_object;
309 
310 	/* Filename for save.
311 	 */
312 	char *filename;
313 
314 } VipsForeignSaveWebpFile;
315 
316 typedef VipsForeignSaveWebpClass VipsForeignSaveWebpFileClass;
317 
318 G_DEFINE_TYPE( VipsForeignSaveWebpFile, vips_foreign_save_webp_file,
319 	vips_foreign_save_webp_get_type() );
320 
321 static int
vips_foreign_save_webp_file_build(VipsObject * object)322 vips_foreign_save_webp_file_build( VipsObject *object )
323 {
324 	VipsForeignSave *save = (VipsForeignSave *) object;
325 	VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
326 	VipsForeignSaveWebpFile *file = (VipsForeignSaveWebpFile *) object;
327 
328 	VipsTarget *target;
329 
330 	if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_file_parent_class )->
331 		build( object ) )
332 		return( -1 );
333 
334 	if( !(target = vips_target_new_to_file( file->filename )) )
335 		return( -1 );
336 	if( vips__webp_write_target( save->ready, target,
337 		webp->Q, webp->lossless, webp->preset,
338 		webp->smart_subsample, webp->near_lossless,
339 		webp->alpha_q, webp->effort,
340 		webp->min_size, webp->kmin, webp->kmax,
341 		save->strip, webp->profile ) ) {
342 		VIPS_UNREF( target );
343 		return( -1 );
344 	}
345 	VIPS_UNREF( target );
346 
347 	return( 0 );
348 }
349 
350 static void
vips_foreign_save_webp_file_class_init(VipsForeignSaveWebpFileClass * class)351 vips_foreign_save_webp_file_class_init( VipsForeignSaveWebpFileClass *class )
352 {
353 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
354 	VipsObjectClass *object_class = (VipsObjectClass *) class;
355 
356 	gobject_class->set_property = vips_object_set_property;
357 	gobject_class->get_property = vips_object_get_property;
358 
359 	object_class->nickname = "webpsave";
360 	object_class->description = _( "save image to webp file" );
361 	object_class->build = vips_foreign_save_webp_file_build;
362 
363 	VIPS_ARG_STRING( class, "filename", 1,
364 		_( "Filename" ),
365 		_( "Filename to save to" ),
366 		VIPS_ARGUMENT_REQUIRED_INPUT,
367 		G_STRUCT_OFFSET( VipsForeignSaveWebpFile, filename ),
368 		NULL );
369 }
370 
371 static void
vips_foreign_save_webp_file_init(VipsForeignSaveWebpFile * file)372 vips_foreign_save_webp_file_init( VipsForeignSaveWebpFile *file )
373 {
374 }
375 
376 typedef struct _VipsForeignSaveWebpBuffer {
377 	VipsForeignSaveWebp parent_object;
378 
379 	/* Save to a buffer.
380 	 */
381 	VipsArea *buf;
382 
383 } VipsForeignSaveWebpBuffer;
384 
385 typedef VipsForeignSaveWebpClass VipsForeignSaveWebpBufferClass;
386 
387 G_DEFINE_TYPE( VipsForeignSaveWebpBuffer, vips_foreign_save_webp_buffer,
388 	vips_foreign_save_webp_get_type() );
389 
390 static int
vips_foreign_save_webp_buffer_build(VipsObject * object)391 vips_foreign_save_webp_buffer_build( VipsObject *object )
392 {
393 	VipsForeignSave *save = (VipsForeignSave *) object;
394 	VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
395 	VipsForeignSaveWebpBuffer *buffer =
396 		(VipsForeignSaveWebpBuffer *) object;
397 
398 	VipsTarget *target;
399 	VipsBlob *blob;
400 
401 	if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_buffer_parent_class )->
402 		build( object ) )
403 		return( -1 );
404 
405 	if( !(target = vips_target_new_to_memory()) )
406 		return( -1 );
407 
408 	if( vips__webp_write_target( save->ready, target,
409 		webp->Q, webp->lossless, webp->preset,
410 		webp->smart_subsample, webp->near_lossless,
411 		webp->alpha_q, webp->effort,
412 		webp->min_size, webp->kmin, webp->kmax,
413 		save->strip, webp->profile ) ) {
414 		VIPS_UNREF( target );
415 		return( -1 );
416 	}
417 
418 	g_object_get( target, "blob", &blob, NULL );
419 	g_object_set( buffer, "buffer", blob, NULL );
420 	vips_area_unref( VIPS_AREA( blob ) );
421 
422 	VIPS_UNREF( target );
423 
424 	return( 0 );
425 }
426 
427 static void
vips_foreign_save_webp_buffer_class_init(VipsForeignSaveWebpBufferClass * class)428 vips_foreign_save_webp_buffer_class_init(
429 	VipsForeignSaveWebpBufferClass *class )
430 {
431 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
432 	VipsObjectClass *object_class = (VipsObjectClass *) class;
433 
434 	gobject_class->set_property = vips_object_set_property;
435 	gobject_class->get_property = vips_object_get_property;
436 
437 	object_class->nickname = "webpsave_buffer";
438 	object_class->description = _( "save image to webp buffer" );
439 	object_class->build = vips_foreign_save_webp_buffer_build;
440 
441 	VIPS_ARG_BOXED( class, "buffer", 1,
442 		_( "Buffer" ),
443 		_( "Buffer to save to" ),
444 		VIPS_ARGUMENT_REQUIRED_OUTPUT,
445 		G_STRUCT_OFFSET( VipsForeignSaveWebpBuffer, buf ),
446 		VIPS_TYPE_BLOB );
447 }
448 
449 static void
vips_foreign_save_webp_buffer_init(VipsForeignSaveWebpBuffer * file)450 vips_foreign_save_webp_buffer_init( VipsForeignSaveWebpBuffer *file )
451 {
452 }
453 
454 typedef struct _VipsForeignSaveWebpMime {
455 	VipsForeignSaveWebp parent_object;
456 
457 } VipsForeignSaveWebpMime;
458 
459 typedef VipsForeignSaveWebpClass VipsForeignSaveWebpMimeClass;
460 
461 G_DEFINE_TYPE( VipsForeignSaveWebpMime, vips_foreign_save_webp_mime,
462 	vips_foreign_save_webp_get_type() );
463 
464 static int
vips_foreign_save_webp_mime_build(VipsObject * object)465 vips_foreign_save_webp_mime_build( VipsObject *object )
466 {
467 	VipsForeignSave *save = (VipsForeignSave *) object;
468 	VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object;
469 
470 	VipsTarget *target;
471 	VipsBlob *blob;
472 	void *data;
473 	size_t len;
474 
475 	if( VIPS_OBJECT_CLASS( vips_foreign_save_webp_mime_parent_class )->
476 		build( object ) )
477 		return( -1 );
478 
479 	if( !(target = vips_target_new_to_memory()) )
480 		return( -1 );
481 
482 	if( vips__webp_write_target( save->ready, target,
483 		webp->Q, webp->lossless, webp->preset,
484 		webp->smart_subsample, webp->near_lossless,
485 		webp->alpha_q, webp->effort,
486 		webp->min_size, webp->kmin, webp->kmax,
487 		save->strip, webp->profile ) ) {
488 		VIPS_UNREF( target );
489 		return( -1 );
490 	}
491 
492 	g_object_get( target, "blob", &blob, NULL );
493 	data = VIPS_AREA( blob )->data;
494 	len = VIPS_AREA( blob )->length;
495 	vips_area_unref( VIPS_AREA( blob ) );
496 
497 	printf( "Content-length: %zu\r\n", len );
498 	printf( "Content-type: image/webp\r\n" );
499 	printf( "\r\n" );
500 	(void) fwrite( data, sizeof( char ), len, stdout );
501 	fflush( stdout );
502 
503 	VIPS_UNREF( target );
504 
505 	return( 0 );
506 }
507 
508 static void
vips_foreign_save_webp_mime_class_init(VipsForeignSaveWebpMimeClass * class)509 vips_foreign_save_webp_mime_class_init( VipsForeignSaveWebpMimeClass *class )
510 {
511 	VipsObjectClass *object_class = (VipsObjectClass *) class;
512 
513 	object_class->nickname = "webpsave_mime";
514 	object_class->description = _( "save image to webp mime" );
515 	object_class->build = vips_foreign_save_webp_mime_build;
516 
517 }
518 
519 static void
vips_foreign_save_webp_mime_init(VipsForeignSaveWebpMime * mime)520 vips_foreign_save_webp_mime_init( VipsForeignSaveWebpMime *mime )
521 {
522 }
523 
524 #endif /*HAVE_LIBWEBP*/
525 
526 /**
527  * vips_webpsave: (method)
528  * @in: image to save
529  * @filename: file to write to
530  * @...: %NULL-terminated list of optional named arguments
531  *
532  * Optional arguments:
533  *
534  * * @Q: %gint, quality factor
535  * * @lossless: %gboolean, enables lossless compression
536  * * @preset: #VipsForeignWebpPreset, choose lossy compression preset
537  * * @smart_subsample: %gboolean, enables high quality chroma subsampling
538  * * @near_lossless: %gboolean, preprocess in lossless mode (controlled by Q)
539  * * @alpha_q: %gint, set alpha quality in lossless mode
540  * * @effort: %gint, level of CPU effort to reduce file size
541  * * @min_size: %gboolean, minimise size
542  * * @kmin: %gint, minimum number of frames between keyframes
543  * * @kmax: %gint, maximum number of frames between keyframes
544  * * @strip: %gboolean, remove all metadata from image
545  * * @profile: %gchararray, filename of ICC profile to attach
546  *
547  * Write an image to a file in WebP format.
548  *
549  * By default, images are saved in lossy format, with
550  * @Q giving the WebP quality factor. It has the range 0 - 100, with the
551  * default 75.
552  *
553  * Use @preset to hint the image type to the lossy compressor. The default is
554  * #VIPS_FOREIGN_WEBP_PRESET_DEFAULT.
555  *
556  * Set @smart_subsample to enable high quality chroma subsampling.
557  *
558  * Use @alpha_q to set the quality for the alpha channel in lossy mode. It has
559  * the range 1 - 100, with the default 100.
560  *
561  * Use @effort to control how much CPU time to spend attempting to
562  * reduce file size. A higher value means more effort and therefore CPU time
563  * should be spent. It has the range 0-6 and a default value of 4.
564  *
565  * Set @lossless to use lossless compression, or combine @near_lossless
566  * with @Q 80, 60, 40 or 20 to apply increasing amounts of preprocessing
567  * which improves the near-lossless compression ratio by up to 50%.
568  *
569  * For animated webp output, @min_size will try to optimize for minimum size.
570  *
571  * For animated webp output, @kmax sets the maximum number of frames between
572  * keyframes. Setting 0 means only keyframes. @kmin sets the minimum number of
573  * frames between frames. Setting 0 means no keyframes. By default, keyframes
574  * are disabled.
575  *
576  * Use @profile to give the name of a profile to be embedded in the file.
577  * This does not affect the pixels which are written, just the way
578  * they are tagged. See vips_profile_load() for details on profile naming.
579  *
580  * Use the metadata items `loop` and `delay` to set the number of
581  * loops for the animation and the frame delays.
582  *
583  * The writer will attach ICC, EXIF and XMP metadata, unless @strip is set to
584  * %TRUE.
585  *
586  * See also: vips_webpload(), vips_image_write_to_file().
587  *
588  * Returns: 0 on success, -1 on error.
589  */
590 int
vips_webpsave(VipsImage * in,const char * filename,...)591 vips_webpsave( VipsImage *in, const char *filename, ... )
592 {
593 	va_list ap;
594 	int result;
595 
596 	va_start( ap, filename );
597 	result = vips_call_split( "webpsave", ap, in, filename );
598 	va_end( ap );
599 
600 	return( result );
601 }
602 
603 /**
604  * vips_webpsave_buffer: (method)
605  * @in: image to save
606  * @buf: (out) (array length=len) (element-type guint8): return output buffer here
607  * @len: return output length here
608  * @...: %NULL-terminated list of optional named arguments
609  *
610  * Optional arguments:
611  *
612  * * @Q: %gint, quality factor
613  * * @lossless: %gboolean, enables lossless compression
614  * * @preset: #VipsForeignWebpPreset, choose lossy compression preset
615  * * @smart_subsample: %gboolean, enables high quality chroma subsampling
616  * * @near_lossless: %gboolean, preprocess in lossless mode (controlled by Q)
617  * * @alpha_q: %gint, set alpha quality in lossless mode
618  * * @effort: %gint, level of CPU effort to reduce file size
619  * * @min_size: %gboolean, minimise size
620  * * @kmin: %gint, minimum number of frames between keyframes
621  * * @kmax: %gint, maximum number of frames between keyframes
622  * * @strip: %gboolean, remove all metadata from image
623  * * @profile: %gchararray, filename of ICC profile to attach
624  *
625  * As vips_webpsave(), but save to a memory buffer.
626  *
627  * The address of the buffer is returned in @buf, the length of the buffer in
628  * @len. You are responsible for freeing the buffer with g_free() when you
629  * are done with it.
630  *
631  * See also: vips_webpsave().
632  *
633  * Returns: 0 on success, -1 on error.
634  */
635 int
vips_webpsave_buffer(VipsImage * in,void ** buf,size_t * len,...)636 vips_webpsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
637 {
638 	va_list ap;
639 	VipsArea *area;
640 	int result;
641 
642 	area = NULL;
643 
644 	va_start( ap, len );
645 	result = vips_call_split( "webpsave_buffer", ap, in, &area );
646 	va_end( ap );
647 
648 	if( !result &&
649 		area ) {
650 		if( buf ) {
651 			*buf = area->data;
652 			area->free_fn = NULL;
653 		}
654 		if( len )
655 			*len = area->length;
656 
657 		vips_area_unref( area );
658 	}
659 
660 	return( result );
661 }
662 
663 /**
664  * vips_webpsave_mime: (method)
665  * @in: image to save
666  * @...: %NULL-terminated list of optional named arguments
667  *
668  * Optional arguments:
669  *
670  * * @Q: %gint, quality factor
671  * * @lossless: %gboolean, enables lossless compression
672  * * @preset: #VipsForeignWebpPreset, choose lossy compression preset
673  * * @smart_subsample: %gboolean, enables high quality chroma subsampling
674  * * @near_lossless: %gboolean, preprocess in lossless mode (controlled by Q)
675  * * @alpha_q: %gint, set alpha quality in lossless mode
676  * * @effort: %gint, level of CPU effort to reduce file size
677  * * @min_size: %gboolean, minimise size
678  * * @kmin: %gint, minimum number of frames between keyframes
679  * * @kmax: %gint, maximum number of frames between keyframes
680  * * @strip: %gboolean, remove all metadata from image
681  * * @profile: %gchararray, filename of ICC profile to attach
682  *
683  * As vips_webpsave(), but save as a mime webp on stdout.
684  *
685  * See also: vips_webpsave(), vips_image_write_to_file().
686  *
687  * Returns: 0 on success, -1 on error.
688  */
689 int
vips_webpsave_mime(VipsImage * in,...)690 vips_webpsave_mime( VipsImage *in, ... )
691 {
692 	va_list ap;
693 	int result;
694 
695 	va_start( ap, in );
696 	result = vips_call_split( "webpsave_mime", ap, in );
697 	va_end( ap );
698 
699 	return( result );
700 }
701 
702 /**
703  * vips_webpsave_target: (method)
704  * @in: image to save
705  * @target: save image to this target
706  * @...: %NULL-terminated list of optional named arguments
707  *
708  * Optional arguments:
709  *
710  * * @Q: %gint, quality factor
711  * * @lossless: %gboolean, enables lossless compression
712  * * @preset: #VipsForeignWebpPreset, choose lossy compression preset
713  * * @smart_subsample: %gboolean, enables high quality chroma subsampling
714  * * @near_lossless: %gboolean, preprocess in lossless mode (controlled by Q)
715  * * @alpha_q: %gint, set alpha quality in lossless mode
716  * * @effort: %gint, level of CPU effort to reduce file size
717  * * @min_size: %gboolean, minimise size
718  * * @kmin: %gint, minimum number of frames between keyframes
719  * * @kmax: %gint, maximum number of frames between keyframes
720  * * @strip: %gboolean, remove all metadata from image
721  * * @profile: %gchararray, filename of ICC profile to attach
722  *
723  * As vips_webpsave(), but save to a target.
724  *
725  * See also: vips_webpsave().
726  *
727  * Returns: 0 on success, -1 on error.
728  */
729 int
vips_webpsave_target(VipsImage * in,VipsTarget * target,...)730 vips_webpsave_target( VipsImage *in, VipsTarget *target, ... )
731 {
732 	va_list ap;
733 	int result;
734 
735 	va_start( ap, target );
736 	result = vips_call_split( "webpsave_target", ap, in, target );
737 	va_end( ap );
738 
739 	return( result );
740 }
741