move heifsave to new target API

and add heifsave_target
This commit is contained in:
John Cupitt 2020-03-15 18:17:08 +00:00
parent 0badb7c603
commit 3b57e13452
5 changed files with 142 additions and 50 deletions

View File

@ -6,7 +6,7 @@
- tiffsave has a "depth" param to set max pyr depth
- libtiff LOGLUV images load and save as libvips XYZ
- add gifload_source, csvload_source, csvsave_target, matrixload_source,
matrixsave_source, pdfload_source, heifload_source
matrixsave_source, pdfload_source, heifload_source, heifsave_target
- revise vipsthumbnail flags
- add VIPS_LEAK env var
- add vips_pipe_read_limit_set(), --vips-pipe-read-limit,

View File

@ -2127,6 +2127,7 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_load_heif_source_get_type( void );
extern GType vips_foreign_save_heif_file_get_type( void );
extern GType vips_foreign_save_heif_buffer_get_type( void );
extern GType vips_foreign_save_heif_target_get_type( void );
extern GType vips_foreign_load_nifti_get_type( void );
extern GType vips_foreign_save_nifti_get_type( void );
@ -2280,6 +2281,7 @@ vips_foreign_operation_init( void )
#ifdef HAVE_HEIF_ENCODER
vips_foreign_save_heif_file_get_type();
vips_foreign_save_heif_buffer_get_type();
vips_foreign_save_heif_target_get_type();
#endif /*HAVE_HEIF_ENCODER*/
vips__foreign_load_operation =

View File

@ -14,6 +14,8 @@
* were reselecting the image for each scanline
* 3/10/19
* - restart after minimise
* 15/3/20
* - revise for new VipsSource API
*/
/*

View File

@ -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 );
}

View File

@ -635,6 +635,8 @@ int vips_heifsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_heifsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
__attribute__((sentinel));
int vips_heifsave_target( VipsImage *in, VipsTarget *target, ... )
__attribute__((sentinel));
int vips_niftiload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));