diff --git a/ChangeLog b/ChangeLog index 8657826c..2eb8575b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ - added restart_interval option to jpegsave [manthey] - add IIIF3 support to dzsaave [martimpassos] - add atan2 [indus] +- improve buffer and target save file format selection +- added VipsForeignPpmFormat, @format arg to ppm savers 16/8/21 started 8.11.4 - fix off-by-one error in new rank fast path diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 48f22611..07e2199e 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1795,6 +1795,7 @@ vips_foreign_save_class_init( VipsForeignSaveClass *class ) VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsForeignSave, page_height ), 0, VIPS_MAX_COORD, 0 ); + } static void @@ -2782,7 +2783,10 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_ppm_file_get_type( void ); extern GType vips_foreign_load_ppm_source_get_type( void ); extern GType vips_foreign_save_ppm_file_get_type( void ); + extern GType vips_foreign_save_pbm_target_get_type( void ); + extern GType vips_foreign_save_pgm_target_get_type( void ); extern GType vips_foreign_save_ppm_target_get_type( void ); + extern GType vips_foreign_save_pfm_target_get_type( void ); extern GType vips_foreign_load_png_file_get_type( void ); extern GType vips_foreign_load_png_buffer_get_type( void ); @@ -2841,7 +2845,9 @@ vips_foreign_operation_init( void ) extern GType vips_foreign_load_magick7_file_get_type( void ); extern GType vips_foreign_load_magick7_buffer_get_type( void ); extern GType vips_foreign_save_magick_file_get_type( void ); + extern GType vips_foreign_save_magick_bmp_file_get_type( void ); extern GType vips_foreign_save_magick_buffer_get_type( void ); + extern GType vips_foreign_save_magick_bmp_buffer_get_type( void ); extern GType vips_foreign_save_dz_file_get_type( void ); extern GType vips_foreign_save_dz_buffer_get_type( void ); @@ -2881,6 +2887,7 @@ vips_foreign_operation_init( 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_save_avif_target_get_type( void ); extern GType vips_foreign_load_nifti_file_get_type( void ); extern GType vips_foreign_load_nifti_source_get_type( void ); @@ -2922,7 +2929,10 @@ vips_foreign_operation_init( void ) vips_foreign_load_ppm_file_get_type(); vips_foreign_load_ppm_source_get_type(); vips_foreign_save_ppm_file_get_type(); + vips_foreign_save_pbm_target_get_type(); + vips_foreign_save_pgm_target_get_type(); vips_foreign_save_ppm_target_get_type(); + vips_foreign_save_pfm_target_get_type(); #endif /*HAVE_PPM*/ #ifdef HAVE_RADIANCE @@ -3052,7 +3062,9 @@ vips_foreign_operation_init( void ) #if defined(ENABLE_MAGICKSAVE) && !defined(MAGICK_MODULE) vips_foreign_save_magick_file_get_type(); + vips_foreign_save_magick_bmp_file_get_type(); vips_foreign_save_magick_buffer_get_type(); + vips_foreign_save_magick_bmp_buffer_get_type(); #endif /*defined(ENABLE_MAGICKSAVE) && !defined(MAGICK_MODULE)*/ #ifdef HAVE_CFITSIO @@ -3081,6 +3093,7 @@ vips_foreign_operation_init( void ) vips_foreign_save_heif_file_get_type(); vips_foreign_save_heif_buffer_get_type(); vips_foreign_save_heif_target_get_type(); + vips_foreign_save_avif_target_get_type(); #endif /*defined(HAVE_HEIF_ENCODER) && !defined(HEIF_MODULE)*/ vips__foreign_load_operation = diff --git a/libvips/foreign/heifload.c b/libvips/foreign/heifload.c index 34916e3a..cd631bd3 100644 --- a/libvips/foreign/heifload.c +++ b/libvips/foreign/heifload.c @@ -76,6 +76,17 @@ #include "pforeign.h" +const char *vips__heic_suffs[] = { + ".heic", + ".heif", + NULL +}; + +const char *vips__avif_suffs[] = { + ".avif", + NULL +}; + const char *vips__heif_suffs[] = { ".heic", ".heif", diff --git a/libvips/foreign/heifsave.c b/libvips/foreign/heifsave.c index 686c9933..3256a8a3 100644 --- a/libvips/foreign/heifsave.c +++ b/libvips/foreign/heifsave.c @@ -335,7 +335,6 @@ vips_foreign_save_heif_build( VipsObject *object ) VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; - const char *filename; struct heif_error error; struct heif_writer writer; char *chroma; @@ -357,15 +356,6 @@ vips_foreign_save_heif_build( VipsObject *object ) if( vips_copy( save->ready, &heif->image, NULL ) ) 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, (enum heif_compression_format) heif->compression, &heif->encoder ); @@ -489,7 +479,6 @@ vips_foreign_save_heif_class_init( VipsForeignSaveHeifClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_heif_dispose; @@ -500,8 +489,6 @@ vips_foreign_save_heif_class_init( VipsForeignSaveHeifClass *class ) object_class->description = _( "save image in HEIF format" ); object_class->build = vips_foreign_save_heif_build; - foreign_class->suffs = vips__heif_suffs; - save_class->saveable = VIPS_SAVEABLE_RGBA_ONLY; save_class->format_table = vips_heif_bandfmt; @@ -588,6 +575,9 @@ vips_foreign_save_heif_file_build( VipsObject *object ) if( !(heif->target = vips_target_new_to_file( file->filename )) ) return( -1 ); + if( vips_iscasepostfix( file->filename, ".avif" ) ) + heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; + if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_file_parent_class )-> build( object ) ) return( -1 ); @@ -600,6 +590,7 @@ vips_foreign_save_heif_file_class_init( VipsForeignSaveHeifFileClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -607,6 +598,8 @@ vips_foreign_save_heif_file_class_init( VipsForeignSaveHeifFileClass *class ) object_class->nickname = "heifsave"; object_class->build = vips_foreign_save_heif_file_build; + foreign_class->suffs = vips__heif_suffs; + VIPS_ARG_STRING( class, "filename", 1, _( "Filename" ), _( "Filename to save to" ), @@ -664,6 +657,7 @@ vips_foreign_save_heif_buffer_class_init( { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -671,6 +665,8 @@ vips_foreign_save_heif_buffer_class_init( object_class->nickname = "heifsave_buffer"; object_class->build = vips_foreign_save_heif_buffer_build; + foreign_class->suffs = vips__heic_suffs; + VIPS_ARG_BOXED( class, "buffer", 1, _( "Buffer" ), _( "Buffer to save to" ), @@ -721,6 +717,7 @@ vips_foreign_save_heif_target_class_init( { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -728,6 +725,8 @@ vips_foreign_save_heif_target_class_init( object_class->nickname = "heifsave_target"; object_class->build = vips_foreign_save_heif_target_build; + foreign_class->suffs = vips__heic_suffs; + VIPS_ARG_OBJECT( class, "target", 1, _( "Target" ), _( "Target to save to" ), @@ -742,6 +741,38 @@ vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target ) { } +typedef VipsForeignSaveHeifTarget VipsForeignSaveAvifTarget; +typedef VipsForeignSaveHeifTargetClass VipsForeignSaveAvifTargetClass; + +G_DEFINE_TYPE( VipsForeignSaveAvifTarget, vips_foreign_save_avif_target, + vips_foreign_save_heif_target_get_type() ); + +static void +vips_foreign_save_avif_target_class_init( + VipsForeignSaveAvifTargetClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "avifsave_target"; + object_class->description = _( "save image in AVIF format" ); + + foreign_class->suffs = vips__avif_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_avif_target_init( VipsForeignSaveAvifTarget *target ) +{ + VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) target; + + heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; +} + #endif /*HAVE_HEIF_ENCODER*/ /* The C API wrappers are defined in foreign.c. diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index 7017172b..44d955f0 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -158,6 +158,10 @@ int vips__mat_header( const char *filename, VipsImage *out ); int vips__mat_ismat( const char *filename ); extern const char *vips__ppm_suffs[]; +extern const char *vips__save_pbm_suffs[]; +extern const char *vips__save_pgm_suffs[]; +extern const char *vips__save_ppm_suffs[]; +extern const char *vips__save_pfm_suffs[]; int vips__ppm_save_target( VipsImage *in, VipsTarget *target, gboolean ascii, gboolean squash ); @@ -235,6 +239,8 @@ typedef void *(*VipsNiftiMapFn)( const char *name, GValue *value, glong offset, void *a, void *b ); void *vips__foreign_nifti_map( VipsNiftiMapFn fn, void *a, void *b ); +extern const char *vips__heic_suffs[]; +extern const char *vips__avif_suffs[]; extern const char *vips__heif_suffs[]; extern const char *vips__jp2k_suffs[]; diff --git a/libvips/foreign/ppmload.c b/libvips/foreign/ppmload.c index ecdef5cc..130e3cda 100644 --- a/libvips/foreign/ppmload.c +++ b/libvips/foreign/ppmload.c @@ -141,7 +141,11 @@ static char *magic_names[] = { /* Shared with ppmsave. */ -const char *vips__ppm_suffs[] = { ".ppm", ".pgm", ".pbm", ".pfm", NULL }; +const char *vips__ppm_suffs[] = { ".pbm", ".pgm", ".ppm", ".pfm", NULL }; +const char *vips__save_pbm_suffs[] = { ".pbm", NULL }; +const char *vips__save_pgm_suffs[] = { ".pgm", NULL }; +const char *vips__save_ppm_suffs[] = { ".ppm", NULL }; +const char *vips__save_pfm_suffs[] = { ".pfm", NULL }; static gboolean vips_foreign_load_ppm_is_a_source( VipsSource *source ) diff --git a/libvips/foreign/ppmsave.c b/libvips/foreign/ppmsave.c index 8e719c6e..1ac29303 100644 --- a/libvips/foreign/ppmsave.c +++ b/libvips/foreign/ppmsave.c @@ -12,6 +12,8 @@ * - byteswap on save, if necessary [ewelot] * 2/12/20 * - don't add date with @strip [ewelot] + * 28/10/21 + * - add @format, default type by filename */ /* @@ -70,6 +72,7 @@ struct _VipsForeignSavePpm { VipsForeignSave parent_object; VipsTarget *target; + VipsForeignPpmFormat format; gboolean ascii; int bitdepth; @@ -216,16 +219,70 @@ vips_foreign_save_ppm_build( VipsObject *object ) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); VipsImage *image; char *magic; char *date; + VipsBandFormat target_format; + VipsInterpretation target_interpretation; if( VIPS_OBJECT_CLASS( vips_foreign_save_ppm_parent_class )-> build( object ) ) return( -1 ); image = save->ready; + target_format = image->BandFmt; + target_interpretation = image->Type; + + /* ppm types to set the defaults for bitdepth etc. + * + * pbm ... 1 band 1 bit + * pgm ... 1 band many bit + * ppm ... 3 band many bit + * pfm ... 1 or 3 bands, 32 bit + */ + switch( ppm->format ) { + case VIPS_FOREIGN_PPM_FORMAT_PBM: + if( !vips_object_argument_isset( object, "bitdepth" ) ) + ppm->bitdepth = 1; + target_interpretation = VIPS_INTERPRETATION_B_W; + break; + + case VIPS_FOREIGN_PPM_FORMAT_PGM: + if( target_format == VIPS_FORMAT_USHORT ) + target_interpretation = VIPS_INTERPRETATION_GREY16; + else + target_interpretation = VIPS_INTERPRETATION_B_W; + break; + + case VIPS_FOREIGN_PPM_FORMAT_PPM: + if( target_format == VIPS_FORMAT_USHORT ) + target_interpretation = VIPS_INTERPRETATION_RGB16; + else + target_interpretation = VIPS_INTERPRETATION_sRGB; + break; + + case VIPS_FOREIGN_PPM_FORMAT_PFM: + target_format = VIPS_FORMAT_FLOAT; + break; + + default: + /* Harmless. + */ + break; + } + + if( vips_cast( image, &t[0], target_format, NULL ) ) + return( -1 ); + image = t[0]; + + if( image->Type != target_interpretation ) { + if( vips_colourspace( image, &t[1], + target_interpretation, NULL ) ) + return( -1 ); + image = t[1]; + } /* Handle the deprecated squash parameter. */ @@ -318,9 +375,12 @@ vips_foreign_save_ppm_build( VipsObject *object ) double scale; char buf[G_ASCII_DTOSTR_BUF_SIZE]; - if( vips_image_get_double( image, - "pfm-scale", &scale ) ) - scale = 1; + scale = 1; + if( vips_image_get_typeof( image, "pfm-scale" ) && + !vips_image_get_double( image, + "pfm-scale", &scale ) ) + ; + if( !vips_amiMSBfirst() ) scale *= -1; /* Need to be locale independent. @@ -391,7 +451,6 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_ppm_dispose; @@ -402,11 +461,17 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class ) object_class->description = _( "save to ppm" ); object_class->build = vips_foreign_save_ppm_build; - foreign_class->suffs = vips__ppm_suffs; - save_class->saveable = VIPS_SAVEABLE_RGB; save_class->format_table = bandfmt_ppm; + VIPS_ARG_ENUM( class, "format", 2, + _( "Format" ), + _( "Format to save in" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSavePpm, format ), + VIPS_TYPE_FOREIGN_PPM_FORMAT, + VIPS_FOREIGN_PPM_FORMAT_PPM ); + VIPS_ARG_BOOL( class, "ascii", 10, _( "ASCII" ), _( "save as ascii" ), @@ -433,6 +498,7 @@ vips_foreign_save_ppm_class_init( VipsForeignSavePpmClass *class ) static void vips_foreign_save_ppm_init( VipsForeignSavePpm *ppm ) { + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PPM; } typedef struct _VipsForeignSavePpmFile { @@ -456,6 +522,13 @@ vips_foreign_save_ppm_file_build( VipsObject *object ) !(ppm->target = vips_target_new_to_file( file->filename )) ) return( -1 ); + if( vips_iscasepostfix( file->filename, ".pbm" ) ) + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PBM; + else if( vips_iscasepostfix( file->filename, ".pgm" ) ) + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PGM; + else if( vips_iscasepostfix( file->filename, ".pfm" ) ) + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PFM; + return( VIPS_OBJECT_CLASS( vips_foreign_save_ppm_file_parent_class )-> build( object ) ); } @@ -465,6 +538,7 @@ vips_foreign_save_ppm_file_class_init( VipsForeignSavePpmFileClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -473,6 +547,8 @@ vips_foreign_save_ppm_file_class_init( VipsForeignSavePpmFileClass *class ) object_class->description = _( "save image to ppm file" ); object_class->build = vips_foreign_save_ppm_file_build; + foreign_class->suffs = vips__ppm_suffs; + VIPS_ARG_STRING( class, "filename", 1, _( "Filename" ), _( "Filename to save to" ), @@ -521,6 +597,7 @@ vips_foreign_save_ppm_target_class_init( { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -528,6 +605,8 @@ vips_foreign_save_ppm_target_class_init( object_class->nickname = "ppmsave_target"; object_class->build = vips_foreign_save_ppm_target_build; + foreign_class->suffs = vips__save_ppm_suffs; + VIPS_ARG_OBJECT( class, "target", 1, _( "Target" ), _( "Target to save to" ), @@ -542,6 +621,102 @@ vips_foreign_save_ppm_target_init( VipsForeignSavePpmTarget *target ) { } +typedef VipsForeignSavePpmTarget VipsForeignSavePbmTarget; +typedef VipsForeignSavePpmTargetClass VipsForeignSavePbmTargetClass; + +G_DEFINE_TYPE( VipsForeignSavePbmTarget, vips_foreign_save_pbm_target, + vips_foreign_save_ppm_target_get_type() ); + +static void +vips_foreign_save_pbm_target_class_init( + VipsForeignSavePbmTargetClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "pbmsave_target"; + object_class->description = _( "save image in pbm format" ); + + foreign_class->suffs = vips__save_pbm_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_pbm_target_init( VipsForeignSavePbmTarget *target ) +{ + VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; + + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PBM; +} + +typedef VipsForeignSavePpmTarget VipsForeignSavePgmTarget; +typedef VipsForeignSavePpmTargetClass VipsForeignSavePgmTargetClass; + +G_DEFINE_TYPE( VipsForeignSavePgmTarget, vips_foreign_save_pgm_target, + vips_foreign_save_ppm_target_get_type() ); + +static void +vips_foreign_save_pgm_target_class_init( + VipsForeignSavePgmTargetClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "pgmsave_target"; + object_class->description = _( "save image in pgm format" ); + + foreign_class->suffs = vips__save_pgm_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_pgm_target_init( VipsForeignSavePgmTarget *target ) +{ + VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; + + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PGM; +} + +typedef VipsForeignSavePpmTarget VipsForeignSavePfmTarget; +typedef VipsForeignSavePpmTargetClass VipsForeignSavePfmTargetClass; + +G_DEFINE_TYPE( VipsForeignSavePfmTarget, vips_foreign_save_pfm_target, + vips_foreign_save_ppm_target_get_type() ); + +static void +vips_foreign_save_pfm_target_class_init( + VipsForeignSavePfmTargetClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "pfmsave_target"; + object_class->description = _( "save image in pfm format" ); + + foreign_class->suffs = vips__save_pfm_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_pfm_target_init( VipsForeignSavePfmTarget *target ) +{ + VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; + + ppm->format = VIPS_FOREIGN_PPM_FORMAT_PFM; +} + #endif /*HAVE_PPM*/ /** @@ -552,8 +727,9 @@ vips_foreign_save_ppm_target_init( VipsForeignSavePpmTarget *target ) * * Optional arguments: * - * * @ascii: save as ASCII rather than binary - * * @squash: squash 8-bit images down to one bit + * * @format: #VipsForeignPpmFormat, format to save in + * * @ascii: %gboolean, save as ASCII rather than binary + * * @bitdepth: %gint, bitdepth to save at * * Write a VIPS image to a file as PPM. It can write 1, 8, 16 or * 32 bit unsigned integer images, float images, colour or monochrome, @@ -566,8 +742,9 @@ vips_foreign_save_ppm_target_init( VipsForeignSavePpmTarget *target ) * Set @ascii to %TRUE to write as human-readable ASCII. Normally data is * written in binary. * - * Set @squash to %TRUE to squash 8-bit images down to one bit. The saver does - * no dithering, that's up to you. + * Set @bitdepth to 1 to write a one-bit image. + * + * @format defaults to the sub-type for this filename suffix. * * See also: vips_image_write_to_file(). * @@ -592,6 +769,12 @@ vips_ppmsave( VipsImage *in, const char *filename, ... ) * @target: save image to this target * @...: %NULL-terminated list of optional named arguments * + * Optional arguments: + * + * * @format: #VipsForeignPpmFormat, format to save in + * * @ascii: %gboolean, save as ASCII rather than binary + * * @bitdepth: %gint, bitdepth to save at + * * As vips_ppmsave(), but save to a target. * * See also: vips_ppmsave(). diff --git a/libvips/foreign/vips2magick.c b/libvips/foreign/vips2magick.c index 21eedc82..c2b3c305 100644 --- a/libvips/foreign/vips2magick.c +++ b/libvips/foreign/vips2magick.c @@ -102,6 +102,7 @@ vips_foreign_save_magick_dispose( GObject *gobject ) printf( "vips_foreign_save_magick_dispose: %p\n", gobject ); #endif /*DEBUG*/ + VIPS_FREE( magick->filename ); VIPS_FREE( magick->map ); VIPS_FREEF( DestroyImageList, magick->images ); VIPS_FREEF( DestroyImageInfo, magick->image_info ); @@ -414,7 +415,8 @@ vips_foreign_save_magick_build( VipsObject *object ) * Instead, just list the commonly-used formats that all libMagicks support and * that libvips does not. */ -static const char *vips__save_magick_suffs[] = { ".gif", ".bmp", NULL }; +static const char *vips__save_magick_suffs[] = { NULL }; +static const char *vips__save_magick_bmp_suffs[] = { ".bmp", NULL }; /* Save a bit of typing. */ @@ -512,7 +514,7 @@ vips_foreign_save_magick_file_build( VipsObject *object ) VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) object; VipsForeignSaveMagickFile *file = (VipsForeignSaveMagickFile *) object; - magick->filename = file->filename; + magick->filename = g_strdup( file->filename ); if( VIPS_OBJECT_CLASS( vips_foreign_save_magick_file_parent_class )-> build( object ) ) @@ -557,6 +559,38 @@ vips_foreign_save_magick_file_init( VipsForeignSaveMagickFile *file ) { } +typedef VipsForeignSaveMagickFile VipsForeignSaveMagickBmpFile; +typedef VipsForeignSaveMagickFileClass VipsForeignSaveMagickBmpFileClass; + +G_DEFINE_TYPE( VipsForeignSaveMagickBmpFile, vips_foreign_save_magick_bmp_file, + vips_foreign_save_magick_file_get_type() ); + +static void +vips_foreign_save_magick_bmp_file_class_init( + VipsForeignSaveMagickBmpFileClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "magicksave_bmp"; + object_class->description = _( "save bmp image with ImageMagick" ); + + foreign_class->suffs = vips__save_magick_bmp_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_magick_bmp_file_init( VipsForeignSaveMagickBmpFile *file ) +{ + VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) file; + + VIPS_SETSTR( magick->format, "bmp" ); +} + typedef struct _VipsForeignSaveMagickBuffer { VipsForeignSaveMagick parent_object; @@ -630,4 +664,38 @@ vips_foreign_save_magick_buffer_init( VipsForeignSaveMagickBuffer *buffer ) { } +typedef VipsForeignSaveMagickBuffer VipsForeignSaveMagickBmpBuffer; +typedef VipsForeignSaveMagickBufferClass VipsForeignSaveMagickBmpBufferClass; + +G_DEFINE_TYPE( VipsForeignSaveMagickBmpBuffer, + vips_foreign_save_magick_bmp_buffer, + vips_foreign_save_magick_buffer_get_type() ); + +static void +vips_foreign_save_magick_bmp_buffer_class_init( + VipsForeignSaveMagickBmpBufferClass *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsForeignClass *foreign_class = (VipsForeignClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; + + object_class->nickname = "magicksave_bmp_buffer"; + object_class->description = _( "save bmp image to magick buffer" ); + + foreign_class->suffs = vips__save_magick_bmp_suffs; + + /* Hide from UI. + */ + operation_class->flags = VIPS_OPERATION_DEPRECATED; +} + +static void +vips_foreign_save_magick_bmp_buffer_init( + VipsForeignSaveMagickBmpBuffer *buffer ) +{ + VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) buffer; + + VIPS_SETSTR( magick->format, "bmp" ); +} + #endif /*ENABLE_MAGICKSAVE*/ diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 8cb85a9e..772e14a1 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -72,6 +72,8 @@ GType vips_foreign_tiff_resunit_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_TIFF_RESUNIT (vips_foreign_tiff_resunit_get_type()) GType vips_foreign_png_filter_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_PNG_FILTER (vips_foreign_png_filter_get_type()) +GType vips_foreign_ppm_format_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_FOREIGN_PPM_FORMAT (vips_foreign_ppm_format_get_type()) GType vips_foreign_dz_layout_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_DZ_LAYOUT (vips_foreign_dz_layout_get_type()) GType vips_foreign_dz_depth_get_type (void) G_GNUC_CONST; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index e8d0d1ac..ac58f946 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -612,6 +612,31 @@ int vips_pngsave( VipsImage *in, const char *filename, ... ) int vips_pngsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) __attribute__((sentinel)); +/** + * VipsForeignPpmFormat: + * @VIPS_FOREIGN_PPM_PBM: portable bitmap + * @VIPS_FOREIGN_PPM_PGM: portable greymap + * @VIPS_FOREIGN_PPM_PPM: portable pixmap + * @VIPS_FOREIGN_PPM_PFM: portable float map + * + * The netpbm file format to save as. + * + * #VIPS_FOREIGN_PPM_PBM images are single bit. + * + * #VIPS_FOREIGN_PPM_PGB images are 8, 16, or 32-bits, one band. + * + * #VIPS_FOREIGN_PPM_PPM images are 8, 16, or 32-bits, three bands. + * + * #VIPS_FOREIGN_PPM_PFM images are 32-bit float pixels. + */ +typedef enum { + VIPS_FOREIGN_PPM_FORMAT_PBM, + VIPS_FOREIGN_PPM_FORMAT_PGM, + VIPS_FOREIGN_PPM_FORMAT_PPM, + VIPS_FOREIGN_PPM_FORMAT_PFM, + VIPS_FOREIGN_PPM_FORMAT_LAST +} VipsForeignPpmFormat; + int vips_ppmload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); int vips_ppmload_source( VipsSource *source, VipsImage **out, ... ) diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index a752ae41..0109ed30 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -644,6 +644,26 @@ vips_foreign_png_filter_get_type( void ) return( etype ); } GType +vips_foreign_ppm_format_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GEnumValue values[] = { + {VIPS_FOREIGN_PPM_FORMAT_PBM, "VIPS_FOREIGN_PPM_FORMAT_PBM", "pbm"}, + {VIPS_FOREIGN_PPM_FORMAT_PGM, "VIPS_FOREIGN_PPM_FORMAT_PGM", "pgm"}, + {VIPS_FOREIGN_PPM_FORMAT_PPM, "VIPS_FOREIGN_PPM_FORMAT_PPM", "ppm"}, + {VIPS_FOREIGN_PPM_FORMAT_PFM, "VIPS_FOREIGN_PPM_FORMAT_PFM", "pfm"}, + {VIPS_FOREIGN_PPM_FORMAT_LAST, "VIPS_FOREIGN_PPM_FORMAT_LAST", "last"}, + {0, NULL, NULL} + }; + + etype = g_enum_register_static( "VipsForeignPpmFormat", values ); + } + + return( etype ); +} +GType vips_foreign_dz_layout_get_type( void ) { static GType etype = 0; diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index c59f28a7..6f93cb8d 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -2750,7 +2750,11 @@ vips_image_write_to_buffer( VipsImage *in, vips__filename_split8( suffix, filename, option_string ); - if( (operation_name = vips_foreign_find_save_target( filename )) ) { + vips_error_freeze(); + operation_name = vips_foreign_find_save_target( filename ); + vips_error_thaw(); + + if( operation_name ) { VipsTarget *target; if( !(target = vips_target_new_to_memory()) ) diff --git a/libvips/module/heif.c b/libvips/module/heif.c index 7d43949f..4eeb722b 100644 --- a/libvips/module/heif.c +++ b/libvips/module/heif.c @@ -64,6 +64,7 @@ g_module_check_init( GModule *module ) 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_save_avif_target_get_type( void ); #ifdef HAVE_HEIF_DECODER vips_foreign_load_heif_file_get_type(); @@ -75,6 +76,7 @@ g_module_check_init( GModule *module ) vips_foreign_save_heif_file_get_type(); vips_foreign_save_heif_buffer_get_type(); vips_foreign_save_heif_target_get_type(); + vips_foreign_save_avif_target_get_type(); #endif /*HAVE_HEIF_ENCODER*/ return( NULL ); diff --git a/libvips/module/magick.c b/libvips/module/magick.c index afd63588..e601fb8b 100644 --- a/libvips/module/magick.c +++ b/libvips/module/magick.c @@ -63,7 +63,9 @@ g_module_check_init( GModule *module ) extern GType vips_foreign_load_magick7_file_get_type( void ); extern GType vips_foreign_load_magick7_buffer_get_type( void ); extern GType vips_foreign_save_magick_file_get_type( void ); + extern GType vips_foreign_save_magick_bmp_file_get_type( void ); extern GType vips_foreign_save_magick_buffer_get_type( void ); + extern GType vips_foreign_save_magick_bmp_buffer_get_type( void ); #ifdef ENABLE_MAGICKLOAD #ifdef HAVE_MAGICK6 @@ -79,7 +81,9 @@ g_module_check_init( GModule *module ) #ifdef ENABLE_MAGICKSAVE vips_foreign_save_magick_file_get_type(); + vips_foreign_save_magick_bmp_file_get_type(); vips_foreign_save_magick_buffer_get_type(); + vips_foreign_save_magick_bmp_buffer_get_type(); #endif /*ENABLE_MAGICKSAVE*/ return( NULL );