diff --git a/libvips/foreign/heifload.c b/libvips/foreign/heifload.c index 73bceab2..624b73dc 100644 --- a/libvips/foreign/heifload.c +++ b/libvips/foreign/heifload.c @@ -146,7 +146,8 @@ void vips__heif_error( struct heif_error *error ) { if( error->code ) - vips_error( "heifload", "%s", error->message ); + vips_error( "heif", "%s (%d.%d)", error->message, error->code, + error->subcode ); } static const char *heif_magic[] = { @@ -814,6 +815,8 @@ vips_foreign_load_heif_file_header( VipsForeignLoad *load ) const char *vips__heif_suffs[] = { ".heic", + ".heif", + ".avif", NULL }; diff --git a/libvips/foreign/heifsave.c b/libvips/foreign/heifsave.c index f8fea788..b6d22c1e 100644 --- a/libvips/foreign/heifsave.c +++ b/libvips/foreign/heifsave.c @@ -65,6 +65,10 @@ typedef struct _VipsForeignSaveHeif { */ gboolean lossless; + /* Compression format + */ + VipsForeignHeifCompression compression; + int page_width; int page_height; int n_pages; @@ -293,12 +297,15 @@ vips_foreign_save_heif_build( VipsObject *object ) build( object ) ) return( -1 ); - /* TODO ... should be a param? the other useful one is AVC. - */ error = heif_context_get_encoder_for_format( heif->ctx, - heif_compression_HEVC, &heif->encoder ); + heif->compression, &heif->encoder ); if( error.code ) { - vips__heif_error( &error ); + if ( error.code == heif_error_Unsupported_filetype ) { + vips_error( "heifsave", "%s", _( "Unsupported compression" ) ); + } + else { + vips__heif_error( &error ); + } return( -1 ); } @@ -401,6 +408,14 @@ vips_foreign_save_heif_class_init( VipsForeignSaveHeifClass *class ) G_STRUCT_OFFSET( VipsForeignSaveHeif, lossless ), FALSE ); + VIPS_ARG_ENUM( class, "compression", 14, + _( "compression" ), + _( "Compression format" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveHeif, compression ), + VIPS_TYPE_FOREIGN_HEIF_COMPRESSION, + VIPS_FOREIGN_HEIF_COMPRESSION_HEVC ); + } static void @@ -408,6 +423,7 @@ vips_foreign_save_heif_init( VipsForeignSaveHeif *heif ) { heif->ctx = heif_context_alloc(); heif->Q = 50; + heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC; } typedef struct _VipsForeignSaveHeifFile { @@ -580,6 +596,7 @@ vips_foreign_save_heif_buffer_init( VipsForeignSaveHeifBuffer *buffer ) * * * @Q: %gint, quality factor * * @lossless: %gboolean, enable lossless encoding + * * @compression: use this #VipsForeignHeifCompression * * Write a VIPS image to a file in HEIF format. * @@ -588,6 +605,8 @@ vips_foreign_save_heif_buffer_init( VipsForeignSaveHeifBuffer *buffer ) * * Set @lossless %TRUE to switch to lossless compression. * + * Use @compression to set the encoder e.g. HEVC, AVC, AV1 + * * See also: vips_image_write_to_file(), vips_heifload(). * * Returns: 0 on success, -1 on error. @@ -616,6 +635,7 @@ vips_heifsave( VipsImage *in, const char *filename, ... ) * * * @Q: %gint, quality factor * * @lossless: %gboolean, enable lossless encoding + * * @compression: use this #VipsForeignHeifCompression * * As vips_heifsave(), but save to a memory buffer. * diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 87cea5fd..2de73711 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -74,6 +74,8 @@ GType vips_foreign_dz_depth_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_DZ_DEPTH (vips_foreign_dz_depth_get_type()) GType vips_foreign_dz_container_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_DZ_CONTAINER (vips_foreign_dz_container_get_type()) +GType vips_foreign_heif_compression_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_FOREIGN_HEIF_COMPRESSION (vips_foreign_heif_compression_get_type()) /* enumerations from "../../../libvips/include/vips/image.h" */ GType vips_demand_style_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_DEMAND_STYLE (vips_demand_style_get_type()) diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 6b3ea0a6..eb8a425d 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -623,6 +623,23 @@ typedef enum { int vips_dzsave( VipsImage *in, const char *name, ... ) __attribute__((sentinel)); +/** + * VipsForeignHeifCompression: + * @VIPS_FOREIGN_HEIF_COMPRESSION_HEVC: x265 + * @VIPS_FOREIGN_HEIF_COMPRESSION_AVC: x264 + * @VIPS_FOREIGN_HEIF_COMPRESSION_JPEG: jpeg + * @VIPS_FOREIGN_HEIF_COMPRESSION_AV1: aom + * + * The compression format to use inside a HEIF container. + */ +typedef enum { + VIPS_FOREIGN_HEIF_COMPRESSION_HEVC = 1, + VIPS_FOREIGN_HEIF_COMPRESSION_AVC = 2, + VIPS_FOREIGN_HEIF_COMPRESSION_JPEG = 3, + VIPS_FOREIGN_HEIF_COMPRESSION_AV1 = 4, + VIPS_FOREIGN_HEIF_COMPRESSION_LAST +} VipsForeignHeifCompression; + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index d5ba3f3d..6628e3c2 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -657,6 +657,26 @@ vips_foreign_dz_container_get_type( void ) return( etype ); } +GType +vips_foreign_heif_compression_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GEnumValue values[] = { + {VIPS_FOREIGN_HEIF_COMPRESSION_HEVC, "VIPS_FOREIGN_HEIF_COMPRESSION_HEVC", "hevc"}, + {VIPS_FOREIGN_HEIF_COMPRESSION_AVC, "VIPS_FOREIGN_HEIF_COMPRESSION_AVC", "avc"}, + {VIPS_FOREIGN_HEIF_COMPRESSION_JPEG, "VIPS_FOREIGN_HEIF_COMPRESSION_JPEG", "jpeg"}, + {VIPS_FOREIGN_HEIF_COMPRESSION_AV1, "VIPS_FOREIGN_HEIF_COMPRESSION_AV1", "av1"}, + {VIPS_FOREIGN_HEIF_COMPRESSION_LAST, "VIPS_FOREIGN_HEIF_COMPRESSION_LAST", "last"}, + {0, NULL, NULL} + }; + + etype = g_enum_register_static( "VipsForeignHeifCompression", values ); + } + + return( etype ); +} /* enumerations from "../../libvips/include/vips/image.h" */ GType vips_demand_style_get_type( void )