"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "libvips/foreign/heifsave.c" between
vips-8.10.6.tar.gz and vips-8.11.0.tar.gz

About: VIPS is a free image processing system (see also the GUI nip2).

heifsave.c  (vips-8.10.6):heifsave.c  (vips-8.11.0)
/* save to heif /* save to heif
* *
* 5/7/18 * 5/7/18
* - from niftisave.c * - from niftisave.c
* 3/7/19 [lovell] * 3/7/19 [lovell]
* - add "compression" option * - add "compression" option
* 1/9/19 [meyermarcel] * 1/9/19 [meyermarcel]
* - save alpha when necessary * - save alpha when necessary
* 15/3/20 * 15/3/20
* - revise for new VipsTarget API * - revise for new VipsTarget API
* 14/2/21 kleisauke
* - move GObject part to vips2heif.c
*/ */
/* /*
This file is part of VIPS. This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
skipping to change at line 50 skipping to change at line 52
/* /*
#define DEBUG_VERBOSE #define DEBUG_VERBOSE
#define DEBUG #define DEBUG
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h> #include <vips/intl.h>
#ifdef HAVE_HEIF_ENCODER
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <vips/vips.h> #include <vips/vips.h>
#include <vips/internal.h> #include <vips/internal.h>
#ifdef HAVE_HEIF_ENCODER #include "pforeign.h"
#include <libheif/heif.h> #include <libheif/heif.h>
#include "pforeign.h"
typedef struct _VipsForeignSaveHeif { typedef struct _VipsForeignSaveHeif {
VipsForeignSave parent_object; VipsForeignSave parent_object;
/* Where to write (set by subclasses). /* Where to write (set by subclasses).
*/ */
VipsTarget *target; VipsTarget *target;
/* Coding quality factor (1-100). /* Coding quality factor (1-100).
*/ */
int Q; int Q;
skipping to change at line 86 skipping to change at line 88
gboolean lossless; gboolean lossless;
/* Compression format /* Compression format
*/ */
VipsForeignHeifCompression compression; VipsForeignHeifCompression compression;
/* CPU effort (0-8). /* CPU effort (0-8).
*/ */
int speed; int speed;
/* Chroma subsampling.
*/
VipsForeignSubsample subsample_mode;
/* The image we save. This is a copy of save->ready since we need to /* The image we save. This is a copy of save->ready since we need to
* be able to update the metadata. * be able to update the metadata.
*/ */
VipsImage *image; VipsImage *image;
int page_width; int page_width;
int page_height; int page_height;
int n_pages; int n_pages;
struct heif_context *ctx; struct heif_context *ctx;
skipping to change at line 117 skipping to change at line 123
/* The libheif memory area we fill with pixels from the libvips /* The libheif memory area we fill with pixels from the libvips
* pipe. * pipe.
*/ */
uint8_t *data; uint8_t *data;
int stride; int stride;
} VipsForeignSaveHeif; } VipsForeignSaveHeif;
typedef VipsForeignSaveClass VipsForeignSaveHeifClass; typedef VipsForeignSaveClass VipsForeignSaveHeifClass;
/* Defined in heif2vips.c
*/
void vips__heif_error( struct heif_error *error );
void vips__heif_image_print( struct heif_image *img );
G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveHeif, vips_foreign_save_heif, G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveHeif, vips_foreign_save_heif,
VIPS_TYPE_FOREIGN_SAVE ); VIPS_TYPE_FOREIGN_SAVE );
static void static void
vips_foreign_save_heif_dispose( GObject *gobject ) vips_foreign_save_heif_dispose( GObject *gobject )
{ {
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) gobject; VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) gobject;
VIPS_UNREF( heif->target ); VIPS_UNREF( heif->target );
VIPS_UNREF( heif->image ); VIPS_UNREF( heif->image );
skipping to change at line 320 skipping to change at line 331
return( error ); return( error );
} }
static int static int
vips_foreign_save_heif_build( VipsObject *object ) vips_foreign_save_heif_build( VipsObject *object )
{ {
VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
const char *filename;
struct heif_error error; struct heif_error error;
struct heif_writer writer; struct heif_writer writer;
char *chroma;
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_parent_class )-> if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_parent_class )->
build( object ) ) build( object ) )
return( -1 ); return( -1 );
/* Make a copy of the image in case we modify the metadata eg. for /* Make a copy of the image in case we modify the metadata eg. for
* exif_update. * exif_update.
*/ */
if( vips_copy( save->ready, &heif->image, NULL ) ) if( vips_copy( save->ready, &heif->image, NULL ) )
return( -1 ); return( -1 );
/* Compression defaults to VIPS_FOREIGN_HEIF_COMPRESSION_AV1 for .avif
* suffix.
*/
filename = vips_connection_filename( VIPS_CONNECTION( heif->target ) );
if( !vips_object_argument_isset( object, "compression" ) &&
filename &&
vips_iscasepostfix( filename, ".avif" ) )
heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
error = heif_context_get_encoder_for_format( heif->ctx, error = heif_context_get_encoder_for_format( heif->ctx,
(enum heif_compression_format) heif->compression, (enum heif_compression_format) heif->compression,
&heif->encoder ); &heif->encoder );
if( error.code ) { if( error.code ) {
if( error.code == heif_error_Unsupported_filetype ) if( error.code == heif_error_Unsupported_filetype )
vips_error( "heifsave", vips_error( "heifsave",
"%s", _( "Unsupported compression" ) ); "%s", _( "Unsupported compression" ) );
else else
vips__heif_error( &error ); vips__heif_error( &error );
skipping to change at line 366 skipping to change at line 388
} }
error = heif_encoder_set_parameter_integer( heif->encoder, error = heif_encoder_set_parameter_integer( heif->encoder,
"speed", heif->speed ); "speed", heif->speed );
if( error.code && if( error.code &&
error.subcode != heif_suberror_Unsupported_parameter ) { error.subcode != heif_suberror_Unsupported_parameter ) {
vips__heif_error( &error ); vips__heif_error( &error );
return( -1 ); return( -1 );
} }
chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF ||
( heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO &&
heif->Q >= 90 ) ? "444" : "420";
error = heif_encoder_set_parameter_string( heif->encoder,
"chroma", chroma );
if( error.code &&
error.subcode != heif_suberror_Unsupported_parameter ) {
vips__heif_error( &error );
return( -1 );
}
/* TODO .. support extra per-encoder params with /* TODO .. support extra per-encoder params with
* heif_encoder_list_parameters(). * heif_encoder_list_parameters().
*/ */
heif->page_width = heif->image->Xsize; heif->page_width = heif->image->Xsize;
heif->page_height = vips_image_get_page_height( heif->image ); heif->page_height = vips_image_get_page_height( heif->image );
heif->n_pages = heif->image->Ysize / heif->page_height; heif->n_pages = heif->image->Ysize / heif->page_height;
/* Make a heif image the size of a page. We send sink_disc() output /* Make a heif image the size of a page. We send sink_disc() output
* here and write a frame each time it fills. * here and write a frame each time it fills.
*/ */
#ifdef DEBUG
printf( "vips_foreign_save_heif_build:\n" );
printf( "\twidth = %d\n", heif->page_width );
printf( "\theight = %d\n", heif->page_height );
printf( "\talpha = %d\n", vips_image_hasalpha( heif->image ) );
#endif /*DEBUG*/
error = heif_image_create( heif->page_width, heif->page_height, error = heif_image_create( heif->page_width, heif->page_height,
heif_colorspace_RGB, heif_colorspace_RGB,
vips_image_hasalpha( heif->image ) ? vips_image_hasalpha( heif->image ) ?
heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGBA :
heif_chroma_interleaved_RGB, heif_chroma_interleaved_RGB,
&heif->img ); &heif->img );
if( error.code ) { if( error.code ) {
vips__heif_error( &error ); vips__heif_error( &error );
return( -1 ); return( -1 );
} }
error = heif_image_add_plane( heif->img, heif_channel_interleaved, error = heif_image_add_plane( heif->img, heif_channel_interleaved,
heif->page_width, heif->page_height, heif->page_width, heif->page_height,
vips_image_hasalpha( heif->image ) ? 32 : 24 ); vips_image_hasalpha( heif->image ) ? 32 : 24 );
if( error.code ) { if( error.code ) {
vips__heif_error( &error ); vips__heif_error( &error );
return( -1 ); return( -1 );
} }
#ifdef DEBUG
vips__heif_image_print( heif->img );
#endif /*DEBUG*/
heif->data = heif_image_get_plane( heif->img, heif->data = heif_image_get_plane( heif->img,
heif_channel_interleaved, &heif->stride ); heif_channel_interleaved, &heif->stride );
/* Write data. /* Write data.
*/ */
if( vips_sink_disc( heif->image, if( vips_sink_disc( heif->image,
vips_foreign_save_heif_write_block, heif ) ) vips_foreign_save_heif_write_block, heif ) )
return( -1 ); return( -1 );
/* This has to come right at the end :-( so there's no support for /* This has to come right at the end :-( so there's no support for
skipping to change at line 478 skipping to change at line 521
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveHeif, compression ), G_STRUCT_OFFSET( VipsForeignSaveHeif, compression ),
VIPS_TYPE_FOREIGN_HEIF_COMPRESSION, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
VIPS_FOREIGN_HEIF_COMPRESSION_HEVC ); VIPS_FOREIGN_HEIF_COMPRESSION_HEVC );
VIPS_ARG_INT( class, "speed", 15, VIPS_ARG_INT( class, "speed", 15,
_( "speed" ), _( "speed" ),
_( "CPU effort" ), _( "CPU effort" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveHeif, speed ), G_STRUCT_OFFSET( VipsForeignSaveHeif, speed ),
0, 8, 5 ); 0, 9, 5 );
VIPS_ARG_ENUM( class, "subsample_mode", 16,
_( "Subsample mode" ),
_( "Select chroma subsample operation mode" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveHeif, subsample_mode ),
VIPS_TYPE_FOREIGN_SUBSAMPLE,
VIPS_FOREIGN_SUBSAMPLE_AUTO );
} }
static void static void
vips_foreign_save_heif_init( VipsForeignSaveHeif *heif ) vips_foreign_save_heif_init( VipsForeignSaveHeif *heif )
{ {
heif->ctx = heif_context_alloc(); heif->ctx = heif_context_alloc();
heif->Q = 50; heif->Q = 50;
heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC; heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC;
heif->speed = 5; heif->speed = 5;
heif->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO;
} }
typedef struct _VipsForeignSaveHeifFile { typedef struct _VipsForeignSaveHeifFile {
VipsForeignSaveHeif parent_object; VipsForeignSaveHeif parent_object;
/* Filename for save. /* Filename for save.
*/ */
char *filename; char *filename;
} VipsForeignSaveHeifFile; } VipsForeignSaveHeifFile;
skipping to change at line 535 skipping to change at line 586
VipsObjectClass *object_class = (VipsObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property; gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property; gobject_class->get_property = vips_object_get_property;
object_class->nickname = "heifsave"; object_class->nickname = "heifsave";
object_class->build = vips_foreign_save_heif_file_build; object_class->build = vips_foreign_save_heif_file_build;
VIPS_ARG_STRING( class, "filename", 1, VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ), _( "Filename" ),
_( "Filename to load from" ), _( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT, VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveHeifFile, filename ), G_STRUCT_OFFSET( VipsForeignSaveHeifFile, filename ),
NULL ); NULL );
} }
static void static void
vips_foreign_save_heif_file_init( VipsForeignSaveHeifFile *file ) vips_foreign_save_heif_file_init( VipsForeignSaveHeifFile *file )
{ {
} }
skipping to change at line 670 skipping to change at line 721
} }
static void static void
vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target ) vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
{ {
} }
#endif /*HAVE_HEIF_ENCODER*/ #endif /*HAVE_HEIF_ENCODER*/
/** /* The C API wrappers are defined in foreign.c.
* vips_heifsave: (method)
* @in: image to save
* @filename: file to write to
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @Q: %gint, quality factor
* * @lossless: %gboolean, enable lossless encoding
* * @compression: #VipsForeignHeifCompression, write with this compression
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
*
* Write a VIPS image to a file in HEIF format.
*
* Use @Q to set the compression factor. Default 50, which seems to be roughly
* what the iphone uses. Q 30 gives about the same quality as JPEG Q 75.
*
* Set @lossless %TRUE to switch to lossless compression.
*
* Use @compression to set the encoder e.g. HEVC, AVC, AV1
*
* Use @speed to control the CPU effort spent improving compression.
* This is currently only applicable to AV1 encoders, defaults to 5.
*
* See also: vips_image_write_to_file(), vips_heifload().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_heifsave( VipsImage *in, const char *filename, ... )
{
va_list ap;
int result;
va_start( ap, filename );
result = vips_call_split( "heifsave", ap, in, filename );
va_end( ap );
return( result );
}
/**
* vips_heifsave_buffer: (method)
* @in: image to save
* @buf: (array length=len) (element-type guint8): return output buffer here
* @len: (type gsize): return output length here
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @Q: %gint, quality factor
* * @lossless: %gboolean, enable lossless encoding
* * @compression: #VipsForeignHeifCompression, write with this compression
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
*
* As vips_heifsave(), but save to a memory buffer.
*
* The address of the buffer is returned in @obuf, the length of the buffer in
* @olen. You are responsible for freeing the buffer with g_free() when you
* are done with it.
*
* See also: vips_heifsave(), vips_image_write_to_file().
*
* Returns: 0 on success, -1 on error.
*/ */
int
vips_heifsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
{
va_list ap;
VipsArea *area;
int result;
area = NULL;
va_start( ap, len );
result = vips_call_split( "heifsave_buffer", ap, in, &area );
va_end( ap );
if( !result &&
area ) {
if( buf ) {
*buf = area->data;
area->free_fn = NULL;
}
if( len )
*len = area->length;
vips_area_unref( area );
}
return( result );
}
/**
* vips_heifsave_target: (method)
* @in: image to save
* @target: save image to this target
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @Q: %gint, quality factor
* * @lossless: %gboolean, enable lossless encoding
* * @compression: #VipsForeignHeifCompression, write with this compression
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
*
* As vips_heifsave(), but save to a target.
*
* See also: vips_heifsave(), vips_image_write_to_target().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_heifsave_target( VipsImage *in, VipsTarget *target, ... )
{
va_list ap;
int result;
va_start( ap, target );
result = vips_call_split( "heifsave_target", ap, in, target );
va_end( ap );
return( result );
}
 End of changes. 18 change blocks. 
70 lines changed or deleted 57 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)