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