|
|
|
@ -6,6 +6,8 @@
|
|
|
|
|
* - add "compression" option
|
|
|
|
|
* 1/9/19 [meyermarcel]
|
|
|
|
|
* - save alpha when necessary
|
|
|
|
|
* 15/3/20
|
|
|
|
|
* - revise for new VipsTarget API
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -61,6 +63,10 @@
|
|
|
|
|
typedef struct _VipsForeignSaveHeif {
|
|
|
|
|
VipsForeignSave parent_object;
|
|
|
|
|
|
|
|
|
|
/* Where to write (set by subclasses).
|
|
|
|
|
*/
|
|
|
|
|
VipsTarget *target;
|
|
|
|
|
|
|
|
|
|
/* Coding quality factor (1-100).
|
|
|
|
|
*/
|
|
|
|
|
int Q;
|
|
|
|
@ -112,6 +118,7 @@ vips_foreign_save_heif_dispose( GObject *gobject )
|
|
|
|
|
{
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) gobject;
|
|
|
|
|
|
|
|
|
|
VIPS_UNREF( heif->target );
|
|
|
|
|
VIPS_UNREF( heif->image );
|
|
|
|
|
VIPS_FREEF( heif_image_release, heif->img );
|
|
|
|
|
VIPS_FREEF( heif_image_handle_release, heif->handle );
|
|
|
|
@ -292,6 +299,21 @@ vips_foreign_save_heif_write_block( VipsRegion *region, VipsRect *area,
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct heif_error
|
|
|
|
|
vips_foreign_save_heif_write( struct heif_context *ctx,
|
|
|
|
|
const void *data, size_t length, void *userdata )
|
|
|
|
|
{
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) userdata;
|
|
|
|
|
|
|
|
|
|
struct heif_error error;
|
|
|
|
|
|
|
|
|
|
error.code = 0;
|
|
|
|
|
if( vips_target_write( heif->target, data, length ) )
|
|
|
|
|
error.code = -1;
|
|
|
|
|
|
|
|
|
|
return( error );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
vips_foreign_save_heif_build( VipsObject *object )
|
|
|
|
|
{
|
|
|
|
@ -299,6 +321,7 @@ vips_foreign_save_heif_build( VipsObject *object )
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
|
|
|
|
|
|
|
|
|
|
struct heif_error error;
|
|
|
|
|
struct heif_writer writer;
|
|
|
|
|
|
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_parent_class )->
|
|
|
|
|
build( object ) )
|
|
|
|
@ -377,6 +400,19 @@ vips_foreign_save_heif_build( VipsObject *object )
|
|
|
|
|
vips_foreign_save_heif_write_block, heif ) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
/* This has to come right at the end :-( so there's no support for
|
|
|
|
|
* incremental writes.
|
|
|
|
|
*/
|
|
|
|
|
writer.writer_api_version = 1;
|
|
|
|
|
writer.write = vips_foreign_save_heif_write;
|
|
|
|
|
error = heif_context_write( heif->ctx, &writer, heif );
|
|
|
|
|
if( error.code ) {
|
|
|
|
|
vips__heif_error( &error );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vips_target_finish( heif->target );
|
|
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -462,21 +498,13 @@ vips_foreign_save_heif_file_build( VipsObject *object )
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
|
|
|
|
|
VipsForeignSaveHeifFile *file = (VipsForeignSaveHeifFile *) object;
|
|
|
|
|
|
|
|
|
|
struct heif_error error;
|
|
|
|
|
if( !(heif->target = vips_target_new_to_file( file->filename )) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_file_parent_class )->
|
|
|
|
|
build( object ) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
/* This has to come right at the end :-( so there's no support for
|
|
|
|
|
* incremental writes.
|
|
|
|
|
*/
|
|
|
|
|
error = heif_context_write_to_file( heif->ctx, file->filename );
|
|
|
|
|
if( error.code ) {
|
|
|
|
|
vips__heif_error( &error );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -520,55 +548,25 @@ typedef VipsForeignSaveHeifClass VipsForeignSaveHeifBufferClass;
|
|
|
|
|
G_DEFINE_TYPE( VipsForeignSaveHeifBuffer, vips_foreign_save_heif_buffer,
|
|
|
|
|
vips_foreign_save_heif_get_type() );
|
|
|
|
|
|
|
|
|
|
struct heif_error
|
|
|
|
|
vips_foreign_save_heif_buffer_write( struct heif_context *ctx,
|
|
|
|
|
const void *data, size_t length, void *userdata )
|
|
|
|
|
{
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) userdata;
|
|
|
|
|
|
|
|
|
|
VipsBlob *blob;
|
|
|
|
|
struct heif_error error;
|
|
|
|
|
void *data_copy;
|
|
|
|
|
|
|
|
|
|
/* FIXME .. we have to memcpy()!
|
|
|
|
|
*/
|
|
|
|
|
data_copy = vips_malloc( NULL, length );
|
|
|
|
|
memcpy( data_copy, data, length );
|
|
|
|
|
|
|
|
|
|
blob = vips_blob_new( (VipsCallbackFn) vips_free, data_copy, length );
|
|
|
|
|
g_object_set( heif, "buffer", blob, NULL );
|
|
|
|
|
vips_area_unref( VIPS_AREA( blob ) );
|
|
|
|
|
|
|
|
|
|
error.code = 0;
|
|
|
|
|
|
|
|
|
|
return( error );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
vips_foreign_save_heif_buffer_build( VipsObject *object )
|
|
|
|
|
{
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
|
|
|
|
|
VipsForeignSaveHeifBuffer *buffer =
|
|
|
|
|
(VipsForeignSaveHeifBuffer *) object;
|
|
|
|
|
|
|
|
|
|
/* FIXME ... argh, allocating on the stack! But the example code does
|
|
|
|
|
* this too.
|
|
|
|
|
*/
|
|
|
|
|
struct heif_writer writer;
|
|
|
|
|
struct heif_error error;
|
|
|
|
|
VipsBlob *blob;
|
|
|
|
|
|
|
|
|
|
if( !(heif->target = vips_target_new_to_memory()) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_buffer_parent_class )->
|
|
|
|
|
build( object ) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
/* This has to come right at the end :-( so there's no support for
|
|
|
|
|
* incremental writes.
|
|
|
|
|
*/
|
|
|
|
|
writer.writer_api_version = 1;
|
|
|
|
|
writer.write = vips_foreign_save_heif_buffer_write;
|
|
|
|
|
error = heif_context_write( heif->ctx, &writer, heif );
|
|
|
|
|
if( error.code ) {
|
|
|
|
|
vips__heif_error( &error );
|
|
|
|
|
return( -1 );
|
|
|
|
|
}
|
|
|
|
|
g_object_get( heif->target, "blob", &blob, NULL );
|
|
|
|
|
g_object_set( buffer, "buffer", blob, NULL );
|
|
|
|
|
vips_area_unref( VIPS_AREA( blob ) );
|
|
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
@ -600,6 +598,63 @@ vips_foreign_save_heif_buffer_init( VipsForeignSaveHeifBuffer *buffer )
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct _VipsForeignSaveHeifTarget {
|
|
|
|
|
VipsForeignSaveHeif parent_object;
|
|
|
|
|
|
|
|
|
|
VipsTarget *target;
|
|
|
|
|
} VipsForeignSaveHeifTarget;
|
|
|
|
|
|
|
|
|
|
typedef VipsForeignSaveHeifClass VipsForeignSaveHeifTargetClass;
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE( VipsForeignSaveHeifTarget, vips_foreign_save_heif_target,
|
|
|
|
|
vips_foreign_save_heif_get_type() );
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
vips_foreign_save_heif_target_build( VipsObject *object )
|
|
|
|
|
{
|
|
|
|
|
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
|
|
|
|
|
VipsForeignSaveHeifTarget *target =
|
|
|
|
|
(VipsForeignSaveHeifTarget *) object;
|
|
|
|
|
|
|
|
|
|
if( target->target ) {
|
|
|
|
|
heif->target = target->target;
|
|
|
|
|
g_object_ref( heif->target );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_target_parent_class )->
|
|
|
|
|
build( object ) )
|
|
|
|
|
return( -1 );
|
|
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
vips_foreign_save_heif_target_class_init(
|
|
|
|
|
VipsForeignSaveHeifTargetClass *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 = "heifsave_target";
|
|
|
|
|
object_class->build = vips_foreign_save_heif_target_build;
|
|
|
|
|
|
|
|
|
|
VIPS_ARG_OBJECT( class, "target", 1,
|
|
|
|
|
_( "Target" ),
|
|
|
|
|
_( "Target to save to" ),
|
|
|
|
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
|
|
|
|
G_STRUCT_OFFSET( VipsForeignSaveHeifTarget, target ),
|
|
|
|
|
VIPS_TYPE_TARGET );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /*HAVE_HEIF_ENCODER*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -690,3 +745,34 @@ vips_heifsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*
|
|
|
|
|
* 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 );
|
|
|
|
|
}
|
|
|
|
|