libvips/libvips/foreign/foreign.c

2290 lines
61 KiB
C
Raw Normal View History

2014-11-10 13:56:28 +01:00
/* foreign file formats base class
*
* 7/2/12
* - add support for sequential reads
* 18/6/12
* - flatten alpha with vips_flatten()
2013-05-28 11:32:37 +02:00
* 28/5/13
* - auto rshift down to 8 bits during save
* 19/1/14
* - pack and unpack rad to scrgb
* 18/8/14
* - fix conversion to 16-bit RGB, thanks John
2015-06-19 16:00:48 +02:00
* 18/6/15
* - forward progress signals from load
* 23/5/16
* - remove max-alpha stuff, this is now automatic
* 12/6/17
* - transform cmyk->rgb if there's an embedded profile
2017-06-19 10:31:49 +02:00
* 16/6/17
* - add page_height
* 1/1/18
* - META_SEQ support moved here
* 5/3/18
* - block _start if one start fails, see #893
* 1/4/18
* - drop incompatible ICC profiles before save
2011-11-23 18:38:19 +01:00
*/
/*
This file is part of VIPS.
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
2011-11-23 18:38:19 +01:00
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
2017-01-26 19:29:43 +01:00
#define DEBUG
2017-01-27 17:43:37 +01:00
*/
2011-11-23 18:38:19 +01:00
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
2012-10-30 18:16:55 +01:00
#include <stdlib.h>
2011-11-23 18:38:19 +01:00
#include <vips/vips.h>
#include <vips/internal.h>
2011-11-24 22:53:40 +01:00
#include <vips/debug.h>
2011-11-23 18:38:19 +01:00
#include "pforeign.h"
2011-11-23 18:38:19 +01:00
/**
2011-12-22 09:48:34 +01:00
* SECTION: foreign
* @short_description: load and save images in a variety of formats
2011-11-23 18:38:19 +01:00
* @stability: Stable
* @see_also: <link linkend="libvips-image">image</link>
* @include: vips/vips.h
2019-12-30 17:28:39 +01:00
* @title: VipsForeign
2011-11-23 18:38:19 +01:00
*
2011-12-22 09:48:34 +01:00
* This set of operations load and save images in a variety of formats.
2011-11-23 18:38:19 +01:00
*
2011-12-22 09:48:34 +01:00
* The operations share a base class that offers a simple way to search for a
* subclass of #VipsForeign which can load a certain file (see
2014-11-17 11:32:40 +01:00
* vips_foreign_find_load()) or buffer (see vips_foreign_find_load_buffer()),
* or which could be used to save an image to a
* certain file type (see vips_foreign_find_save() and
* vips_foreign_find_save_buffer()). You can then run these
2011-12-22 09:48:34 +01:00
* operations using vips_call() and friends to perform the load or save.
2011-11-23 18:38:19 +01:00
*
2014-11-17 11:32:40 +01:00
* vips_image_write_to_file() and vips_image_new_from_file() and friends use
* these functions to automate file load and save.
*
2011-12-22 09:48:34 +01:00
* You can also invoke the operations directly, for example:
*
* |[
* vips_tiffsave (my_image, "frank.anything",
* "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG,
* NULL);
* ]|
*
* To add support for a new file format to vips, simply define a new subclass
* of #VipsForeignLoad or #VipsForeignSave.
*
* If you define a new operation which is a subclass of #VipsForeign, support
* for it automatically appears in all VIPS user-interfaces. It will also be
* transparently supported by vips_image_new_from_file() and friends.
2011-11-23 18:38:19 +01:00
*
2011-11-29 12:43:08 +01:00
* VIPS comes with VipsForeign for TIFF, JPEG, PNG, Analyze, PPM, OpenEXR, CSV,
* Matlab, Radiance, RAW, FITS, WebP, SVG, PDF, GIF and VIPS. It also includes
* import filters which can load with libMagick and with OpenSlide.
2011-11-23 18:38:19 +01:00
*
2016-09-12 13:23:53 +02:00
* ## Writing a new loader
*
2016-09-12 13:23:53 +02:00
* Add a new loader to VIPS by subclassing #VipsForeignLoad. Subclasses need to
* implement at least @header().
*
2016-09-12 13:23:53 +02:00
* @header() must set at least the header fields of @out. @load(), if defined,
* must load the pixels to @real.
2011-11-23 18:38:19 +01:00
*
2011-12-22 13:12:27 +01:00
* The suffix list is used to select a format to save a file in, and to pick a
* loader if you don't define is_a().
2011-11-23 18:38:19 +01:00
*
2011-12-22 13:12:27 +01:00
* You should also define @nickname and @description in #VipsObject.
2011-11-23 18:38:19 +01:00
*
2014-04-22 20:20:24 +02:00
* As a complete example, here's code for a PNG loader, minus the actual
2011-12-22 13:12:27 +01:00
* calls to libpng.
2011-11-23 18:38:19 +01:00
*
* |[
* typedef struct _VipsForeignLoadPng {
* VipsForeignLoad parent_object;
*
* char *filename;
* } VipsForeignLoadPng;
*
* typedef VipsForeignLoadClass VipsForeignLoadPngClass;
*
* G_DEFINE_TYPE( VipsForeignLoadPng, vips_foreign_load_png,
* VIPS_TYPE_FOREIGN_LOAD );
*
* static VipsForeignFlags
* vips_foreign_load_png_get_flags_filename( const char *filename )
* {
* VipsForeignFlags flags;
*
* flags = 0;
* if( vips__png_isinterlaced( filename ) )
* flags = VIPS_FOREIGN_PARTIAL;
* else
* flags = VIPS_FOREIGN_SEQUENTIAL;
*
* return( flags );
* }
*
* static VipsForeignFlags
* vips_foreign_load_png_get_flags( VipsForeignLoad *load )
* {
* VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
*
* return( vips_foreign_load_png_get_flags_filename( png->filename ) );
* }
*
* static int
* vips_foreign_load_png_header( VipsForeignLoad *load )
* {
* VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
*
* if( vips__png_header( png->filename, load->out ) )
* return( -1 );
*
* return( 0 );
* }
*
* static int
* vips_foreign_load_png_load( VipsForeignLoad *load )
* {
* VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
*
* if( vips__png_read( png->filename, load->real ) )
* return( -1 );
*
* return( 0 );
* }
*
* static void
* vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
* {
* GObjectClass *gobject_class = G_OBJECT_CLASS( class );
* VipsObjectClass *object_class = (VipsObjectClass *) class;
* VipsForeignClass *foreign_class = (VipsForeignClass *) class;
* VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
*
* gobject_class->set_property = vips_object_set_property;
* gobject_class->get_property = vips_object_get_property;
*
* object_class->nickname = "pngload";
* object_class->description = _( "load png from file" );
*
* foreign_class->suffs = vips__png_suffs;
*
* load_class->is_a = vips__png_ispng;
* load_class->get_flags_filename =
* vips_foreign_load_png_get_flags_filename;
* load_class->get_flags = vips_foreign_load_png_get_flags;
* load_class->header = vips_foreign_load_png_header;
* load_class->load = vips_foreign_load_png_load;
*
* VIPS_ARG_STRING( class, "filename", 1,
* _( "Filename" ),
* _( "Filename to load from" ),
* VIPS_ARGUMENT_REQUIRED_INPUT,
* G_STRUCT_OFFSET( VipsForeignLoadPng, filename ),
* NULL );
* }
*
* static void
* vips_foreign_load_png_init( VipsForeignLoadPng *png )
* {
* }
2011-11-23 18:38:19 +01:00
* ]|
2016-09-12 13:23:53 +02:00
*
* ## Writing a new saver
2011-11-23 18:38:19 +01:00
*
2011-12-22 13:12:27 +01:00
* Call your saver in the class' @build() method after chaining up. The
* prepared image should be ready for you to save in @ready.
2011-11-23 18:38:19 +01:00
*
2011-12-22 13:12:27 +01:00
* As a complete example, here's the code for the CSV saver, minus the calls
* to the actual save routines.
2011-11-23 18:38:19 +01:00
*
* |[
* typedef struct _VipsForeignSaveCsv {
* VipsForeignSave parent_object;
*
* char *filename;
* const char *separator;
* } VipsForeignSaveCsv;
*
* typedef VipsForeignSaveClass VipsForeignSaveCsvClass;
*
* G_DEFINE_TYPE( VipsForeignSaveCsv, vips_foreign_save_csv,
* VIPS_TYPE_FOREIGN_SAVE );
*
* static int
* vips_foreign_save_csv_build( VipsObject *object )
* {
* VipsForeignSave *save = (VipsForeignSave *) object;
* VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object;
*
* if( VIPS_OBJECT_CLASS( vips_foreign_save_csv_parent_class )->
* build( object ) )
* return( -1 );
*
* if( vips__csv_write( save->ready, csv->filename, csv->separator ) )
* return( -1 );
*
* return( 0 );
* }
*
* static void
* vips_foreign_save_csv_class_init( VipsForeignSaveCsvClass *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->set_property = vips_object_set_property;
* gobject_class->get_property = vips_object_get_property;
*
* object_class->nickname = "csvsave";
* object_class->description = _( "save image to csv file" );
* object_class->build = vips_foreign_save_csv_build;
*
* foreign_class->suffs = vips__foreign_csv_suffs;
*
* save_class->saveable = VIPS_SAVEABLE_MONO;
* // no need to define ->format_table, we don't want the input
* // cast for us
*
* VIPS_ARG_STRING( class, "filename", 1,
* _( "Filename" ),
* _( "Filename to save to" ),
* VIPS_ARGUMENT_REQUIRED_INPUT,
* G_STRUCT_OFFSET( VipsForeignSaveCsv, filename ),
* NULL );
*
* VIPS_ARG_STRING( class, "separator", 13,
* _( "Separator" ),
* _( "Separator characters" ),
* VIPS_ARGUMENT_OPTIONAL_INPUT,
* G_STRUCT_OFFSET( VipsForeignSaveCsv, separator ),
* "\t" );
* }
*
* static void
* vips_foreign_save_csv_init( VipsForeignSaveCsv *csv )
* {
* csv->separator = g_strdup( "\t" );
* }
2011-12-22 13:12:27 +01:00
* ]|
2011-11-24 15:53:30 +01:00
*/
/* Use this to link images to the load operation that made them.
*/
static GQuark vips__foreign_load_operation = 0;
2016-09-12 13:23:53 +02:00
/**
* VipsForeignFlags:
* @VIPS_FOREIGN_NONE: no flags set
* @VIPS_FOREIGN_PARTIAL: the image may be read lazilly
* @VIPS_FOREIGN_BIGENDIAN: image pixels are most-significant byte first
* @VIPS_FOREIGN_SEQUENTIAL: top-to-bottom lazy reading
*
* Some hints about the image loader.
*
* #VIPS_FOREIGN_PARTIAL means that the image can be read directly from the
* file without needing to be unpacked to a temporary image first.
*
* #VIPS_FOREIGN_SEQUENTIAL means that the loader supports lazy reading, but
* only top-to-bottom (sequential) access. Formats like PNG can read sets of
* scanlines, for example, but only in order.
*
* If neither PARTIAL or SEQUENTIAL is set, the loader only supports whole
* image read. Setting both PARTIAL and SEQUENTIAL is an error.
*
* #VIPS_FOREIGN_BIGENDIAN means that image pixels are most-significant byte
* first. Depending on the native byte order of the host machine, you may
* need to swap bytes. See vips_copy().
*/
2011-11-29 12:43:08 +01:00
G_DEFINE_ABSTRACT_TYPE( VipsForeign, vips_foreign, VIPS_TYPE_OPERATION );
2011-11-24 15:53:30 +01:00
static void
2012-01-16 15:54:29 +01:00
vips_foreign_summary_class( VipsObjectClass *object_class, VipsBuf *buf )
2011-11-24 15:53:30 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignClass *class = VIPS_FOREIGN_CLASS( object_class );
2011-11-24 15:53:30 +01:00
2011-11-29 12:43:08 +01:00
VIPS_OBJECT_CLASS( vips_foreign_parent_class )->
2012-01-16 15:54:29 +01:00
summary_class( object_class, buf );
2011-11-24 15:53:30 +01:00
if( class->suffs ) {
2013-05-01 19:46:15 +02:00
const char **p;
2016-03-25 17:35:28 +01:00
vips_buf_appends( buf, " (" );
2011-11-24 15:53:30 +01:00
for( p = class->suffs; *p; p++ ) {
vips_buf_appendf( buf, "%s", *p );
if( p[1] )
vips_buf_appends( buf, ", " );
}
2016-03-25 17:35:28 +01:00
vips_buf_appends( buf, ")" );
2011-11-24 15:53:30 +01:00
}
2016-03-25 17:35:28 +01:00
vips_buf_appendf( buf, ", priority=%d", class->priority );
2011-11-24 15:53:30 +01:00
}
static void
2011-11-29 12:43:08 +01:00
vips_foreign_class_init( VipsForeignClass *class )
2011-11-24 15:53:30 +01:00
{
2011-11-24 22:53:40 +01:00
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
2011-11-24 15:53:30 +01:00
VipsObjectClass *object_class = (VipsObjectClass *) class;
2011-11-24 22:53:40 +01:00
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "foreign";
2011-11-24 15:53:30 +01:00
object_class->description = _( "load and save image files" );
2012-01-16 15:54:29 +01:00
object_class->summary_class = vips_foreign_summary_class;
2011-11-24 15:53:30 +01:00
}
static void
2011-11-29 12:43:08 +01:00
vips_foreign_init( VipsForeign *object )
2011-11-24 15:53:30 +01:00
{
}
/* To iterate over supported files we build a temp list of subclasses of
2011-11-29 12:43:08 +01:00
* VipsForeign, sort by priority, iterate, and free.
2011-11-23 18:38:19 +01:00
*/
static void *
file_add_class( VipsForeignClass *class, GSList **files )
2011-11-23 18:38:19 +01:00
{
/* Append so we don't reverse the list of files. Sort will not reorder
* items of equal priority.
2011-11-23 18:38:19 +01:00
*/
*files = g_slist_append( *files, class );
2011-11-23 18:38:19 +01:00
return( NULL );
}
static gint
2011-11-29 12:43:08 +01:00
file_compare( VipsForeignClass *a, VipsForeignClass *b )
2011-11-23 18:38:19 +01:00
{
return( b->priority - a->priority );
}
/**
2011-11-29 12:43:08 +01:00
* vips_foreign_map:
* @base: base class to search below (eg. "VipsForeignLoad")
* @fn: (scope call): function to apply to each #VipsForeignClass
2011-11-23 18:38:19 +01:00
* @a: user data
* @b: user data
*
2011-11-29 12:43:08 +01:00
* Apply a function to every #VipsForeignClass that VIPS knows about. Foreigns
2011-11-23 18:38:19 +01:00
* are presented to the function in priority order.
*
* Like all VIPS map functions, if @fn returns %NULL, iteration continues. If
* it returns non-%NULL, iteration terminates and that value is returned. The
* map function returns %NULL if all calls return %NULL.
*
* See also: vips_slist_map().
*
* Returns: (transfer none): the result of iteration
2011-11-23 18:38:19 +01:00
*/
void *
2011-11-29 12:43:08 +01:00
vips_foreign_map( const char *base, VipsSListMap2Fn fn, void *a, void *b )
2011-11-23 18:38:19 +01:00
{
2011-11-24 10:57:01 +01:00
GSList *files;
2011-11-23 18:38:19 +01:00
void *result;
2011-11-24 10:57:01 +01:00
files = NULL;
2011-11-23 18:38:19 +01:00
(void) vips_class_map_all( g_type_from_name( base ),
2011-11-24 10:57:01 +01:00
(VipsClassMapFn) file_add_class, (void *) &files );
2011-11-23 18:38:19 +01:00
2011-11-24 10:57:01 +01:00
files = g_slist_sort( files, (GCompareFunc) file_compare );
result = vips_slist_map2( files, fn, a, b );
g_slist_free( files );
2011-11-23 18:38:19 +01:00
return( result );
}
2011-11-24 15:53:30 +01:00
/* Abstract base class for image load.
2011-11-23 18:38:19 +01:00
*/
2011-11-29 12:43:08 +01:00
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoad, vips_foreign_load, VIPS_TYPE_FOREIGN );
2011-11-23 18:38:19 +01:00
2011-11-24 22:53:40 +01:00
static void
2011-11-29 12:43:08 +01:00
vips_foreign_load_dispose( GObject *gobject )
2011-11-24 22:53:40 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( gobject );
2011-11-24 22:53:40 +01:00
VIPS_UNREF( load->real );
2011-11-29 12:43:08 +01:00
G_OBJECT_CLASS( vips_foreign_load_parent_class )->dispose( gobject );
2011-11-24 22:53:40 +01:00
}
2011-11-23 18:38:19 +01:00
static void
2012-01-16 15:54:29 +01:00
vips_foreign_load_summary_class( VipsObjectClass *object_class, VipsBuf *buf )
2011-11-23 18:38:19 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignLoadClass *class = VIPS_FOREIGN_LOAD_CLASS( object_class );
2011-11-23 18:38:19 +01:00
2011-11-29 12:43:08 +01:00
VIPS_OBJECT_CLASS( vips_foreign_load_parent_class )->
2012-01-16 15:54:29 +01:00
summary_class( object_class, buf );
2011-11-23 18:38:19 +01:00
2011-12-20 15:57:05 +01:00
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) ) {
if( class->is_a )
vips_buf_appends( buf, ", is_a" );
if( class->is_a_buffer )
vips_buf_appends( buf, ", is_a_buffer" );
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
if( class->is_a_source )
vips_buf_appends( buf, ", is_a_source" );
2011-12-20 15:57:05 +01:00
if( class->get_flags )
vips_buf_appends( buf, ", get_flags" );
if( class->get_flags_filename )
vips_buf_appends( buf, ", get_flags_filename" );
if( class->header )
vips_buf_appends( buf, ", header" );
if( class->load )
vips_buf_appends( buf, ", load" );
/* You can omit ->load(), you must not omit ->header().
*/
g_assert( class->header );
}
2011-11-23 18:38:19 +01:00
}
2011-11-29 12:43:08 +01:00
/* Can this VipsForeign open this file?
*/
static void *
vips_foreign_find_load_sub( VipsForeignLoadClass *load_class,
const char *filename )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( load_class );
2011-11-29 12:43:08 +01:00
VipsForeignClass *class = VIPS_FOREIGN_CLASS( load_class );
2017-01-26 19:29:43 +01:00
#ifdef DEBUG
printf( "vips_foreign_find_load_sub: %s\n",
VIPS_OBJECT_CLASS( class )->nickname );
#endif /*DEBUG*/
if( load_class->is_a &&
!vips_ispostfix( object_class->nickname, "_buffer" ) &&
!vips_ispostfix( object_class->nickname, "_source" ) ) {
2012-01-17 17:38:36 +01:00
if( load_class->is_a( filename ) )
return( load_class );
2017-01-26 19:29:43 +01:00
#ifdef DEBUG
printf( "vips_foreign_find_load_sub: is_a failed\n" );
#endif /*DEBUG*/
2012-01-17 17:38:36 +01:00
}
2011-11-29 19:13:14 +01:00
else if( class->suffs &&
vips_filename_suffix_match( filename, class->suffs ) )
return( load_class );
2017-01-26 19:29:43 +01:00
else {
#ifdef DEBUG
printf( "vips_foreign_find_load_sub: suffix match failed\n" );
#endif /*DEBUG*/
}
return( NULL );
}
/**
2011-11-29 12:43:08 +01:00
* vips_foreign_find_load:
* @filename: file to find a loader for
*
* Searches for an operation you could use to load @filename. Any trailing
* options on @filename are stripped and ignored.
*
2014-11-17 11:32:40 +01:00
* See also: vips_foreign_find_load_buffer(), vips_image_new_from_file().
*
* Returns: the name of an operation on success, %NULL on error
*/
const char *
vips_foreign_find_load( const char *name )
{
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
2011-11-29 12:43:08 +01:00
VipsForeignLoadClass *load_class;
vips__filename_split8( name, filename, option_string );
/* Very common, so make a better error message for this case.
*/
if( !vips_existsf( "%s", filename ) ) {
2011-11-29 12:43:08 +01:00
vips_error( "VipsForeignLoad",
_( "file \"%s\" does not exist" ), name );
return( NULL );
}
if( vips_isdirf( "%s", filename ) ) {
vips_error( "VipsForeignLoad",
_( "\"%s\" is a directory" ), name );
return( NULL );
}
2011-11-29 12:43:08 +01:00
if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map(
"VipsForeignLoad",
(VipsSListMap2Fn) vips_foreign_find_load_sub,
(void *) filename, NULL )) ) {
2011-11-29 12:43:08 +01:00
vips_error( "VipsForeignLoad",
_( "\"%s\" is not a known file format" ), name );
return( NULL );
}
2017-01-26 19:29:43 +01:00
#ifdef DEBUG
printf( "vips_foreign_find_load: selected %s\n",
VIPS_OBJECT_CLASS( load_class )->nickname );
#endif /*DEBUG*/
return( G_OBJECT_CLASS_NAME( load_class ) );
}
/* Kept for compat with earlier version of the vip8 API. Use
* vips_image_new_from_file() now.
*/
int
vips_foreign_load( const char *name, VipsImage **out, ... )
{
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
const char *operation_name;
va_list ap;
int result;
vips__filename_split8( name, filename, option_string );
if( !(operation_name = vips_foreign_find_load( filename )) )
return( -1 );
va_start( ap, out );
result = vips_call_split_option_string( operation_name, option_string,
ap, filename, out );
va_end( ap );
return( result );
}
2014-04-22 17:27:43 +02:00
/* Can this VipsForeign open this buffer?
*/
static void *
vips_foreign_find_load_buffer_sub( VipsForeignLoadClass *load_class,
const void **buf, size_t *len )
2014-04-22 17:27:43 +02:00
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( load_class );
2014-04-22 17:27:43 +02:00
if( load_class->is_a_buffer &&
vips_ispostfix( object_class->nickname, "_buffer" ) &&
2014-04-22 17:27:43 +02:00
load_class->is_a_buffer( *buf, *len ) )
return( load_class );
return( NULL );
}
/**
* vips_foreign_find_load_buffer:
2014-09-03 22:34:26 +02:00
* @data: (array length=size) (element-type guint8) (transfer none): start of
* memory buffer
* @size: (type gsize): number of bytes in @data
2014-04-22 17:27:43 +02:00
*
2016-03-24 18:47:24 +01:00
* Searches for an operation you could use to load a memory buffer. To see the
* range of buffer loaders supported by your vips, try something like:
*
* vips -l | grep load_buffer
2014-04-22 17:27:43 +02:00
*
* See also: vips_image_new_from_buffer().
2014-04-22 17:27:43 +02:00
*
2014-09-03 22:34:26 +02:00
* Returns: (transfer none): the name of an operation on success, %NULL on
* error.
2014-04-22 17:27:43 +02:00
*/
const char *
vips_foreign_find_load_buffer( const void *data, size_t size )
2014-04-22 17:27:43 +02:00
{
VipsForeignLoadClass *load_class;
if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map(
"VipsForeignLoad",
(VipsSListMap2Fn) vips_foreign_find_load_buffer_sub,
2014-09-03 22:34:26 +02:00
&data, &size )) ) {
2014-04-22 17:27:43 +02:00
vips_error( "VipsForeignLoad",
"%s", _( "buffer is not in a known format" ) );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( load_class ) );
}
/* Can this VipsForeign open this source?
*/
static void *
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_find_load_source_sub( void *item, void *a, void *b )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( item );
VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS( item );
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
VipsSource *source = VIPS_SOURCE( a );
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
if( load_class->is_a_source &&
vips_ispostfix( object_class->nickname, "_source" ) ) {
2019-11-08 18:39:25 +01:00
/* We may have done a read() rather than a sniff() in one of
* the is_a testers. Always rewind.
*/
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
(void) vips_source_rewind( source );
2019-11-08 18:39:25 +01:00
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
if( load_class->is_a_source( source ) )
2019-11-08 18:39:25 +01:00
return( load_class );
}
return( NULL );
}
/**
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
* vips_foreign_find_load_source:
* @source: source to load from
*
* Searches for an operation you could use to load a source. To see the
* range of source loaders supported by your vips, try something like:
*
* vips -l | grep load_source
*
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
* See also: vips_image_new_from_source().
*
* Returns: (transfer none): the name of an operation on success, %NULL on
* error.
*/
const char *
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_find_load_source( VipsSource *source )
{
VipsForeignLoadClass *load_class;
if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map(
"VipsForeignLoad",
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_find_load_source_sub,
source, NULL )) ) {
vips_error( "VipsForeignLoad",
"%s", _( "source is not in a known format" ) );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( load_class ) );
}
2011-12-13 14:19:20 +01:00
/**
* vips_foreign_is_a:
* @loader: name of loader to use for test
* @filename: file to test
*
* Return %TRUE if @filename can be loaded by @loader. @loader is something
* like "tiffload" or "VipsForeignLoadTiff".
*
* Returns: %TRUE if @filename can be loaded by @loader.
*/
gboolean
vips_foreign_is_a( const char *loader, const char *filename )
{
const VipsObjectClass *class;
2011-12-13 14:19:20 +01:00
VipsForeignLoadClass *load_class;
if( !(class = vips_class_find( "VipsForeignLoad", loader )) )
return( FALSE );
load_class = VIPS_FOREIGN_LOAD_CLASS( class );
if( load_class->is_a &&
load_class->is_a( filename ) )
return( TRUE );
return( FALSE );
}
/**
* vips_foreign_is_a_buffer:
* @loader: name of loader to use for test
* @data: (array length=size) (element-type guint8): pointer to the buffer to test
* @size: (type gsize): size of the buffer to test
*
* Return %TRUE if @data can be loaded by @loader. @loader is something
* like "tiffload_buffer" or "VipsForeignLoadTiffBuffer".
*
* Returns: %TRUE if @data can be loaded by @loader.
*/
gboolean
vips_foreign_is_a_buffer( const char *loader, const void *data, size_t size )
{
const VipsObjectClass *class;
VipsForeignLoadClass *load_class;
if( !(class = vips_class_find( "VipsForeignLoad", loader )) )
return( FALSE );
load_class = VIPS_FOREIGN_LOAD_CLASS( class );
if( load_class->is_a_buffer &&
load_class->is_a_buffer( data, size ) )
return( TRUE );
return( FALSE );
}
2019-10-10 21:42:39 +02:00
/**
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
* vips_foreign_is_a_source:
2019-10-10 21:42:39 +02:00
* @loader: name of loader to use for test
* @source: source to test
2019-10-10 21:42:39 +02:00
*
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
* Return %TRUE if @source can be loaded by @loader. @loader is something
* like "tiffload_source" or "VipsForeignLoadTiffSource".
2019-10-10 21:42:39 +02:00
*
* Returns: %TRUE if @data can be loaded by @source.
2019-10-10 21:42:39 +02:00
*/
gboolean
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_is_a_source( const char *loader, VipsSource *source )
2019-10-10 21:42:39 +02:00
{
const VipsObjectClass *class;
VipsForeignLoadClass *load_class;
if( !(class = vips_class_find( "VipsForeignLoad", loader )) )
return( FALSE );
load_class = VIPS_FOREIGN_LOAD_CLASS( class );
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
if( load_class->is_a_source &&
load_class->is_a_source( source ) )
2019-10-10 21:42:39 +02:00
return( TRUE );
return( FALSE );
}
2011-12-13 14:19:20 +01:00
/**
* vips_foreign_flags:
* @loader: name of loader to use for test
* @filename: file to test
*
* Return the flags for @filename using @loader.
* @loader is something like "tiffload" or "VipsForeignLoadTiff".
*
* Returns: the flags for @filename.
*/
VipsForeignFlags
vips_foreign_flags( const char *loader, const char *filename )
{
const VipsObjectClass *class;
2011-12-13 14:19:20 +01:00
if( (class = vips_class_find( "VipsForeignLoad", loader )) ) {
VipsForeignLoadClass *load_class =
VIPS_FOREIGN_LOAD_CLASS( class );
if( load_class->get_flags_filename )
return( load_class->get_flags_filename( filename ) );
}
return( 0 );
}
static VipsObject *
2011-11-29 12:43:08 +01:00
vips_foreign_load_new_from_string( const char *string )
{
const char *file_op;
GType type;
2011-11-29 12:43:08 +01:00
VipsForeignLoad *load;
2011-11-29 12:43:08 +01:00
if( !(file_op = vips_foreign_find_load( string )) )
return( NULL );
type = g_type_from_name( file_op );
g_assert( type );
2011-11-29 12:43:08 +01:00
load = VIPS_FOREIGN_LOAD( g_object_new( type, NULL ) );
g_object_set( load,
"filename", string,
NULL );
return( VIPS_OBJECT( load ) );
}
2012-02-15 16:47:43 +01:00
static VipsImage *
vips_foreign_load_temp( VipsForeignLoad *load )
{
const guint64 disc_threshold = vips_get_disc_threshold();
const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE( load->out );
/* ->memory used to be called ->disc and default TRUE. If it's been
* forced FALSE, set memory TRUE.
*/
if( !load->disc )
load->memory = TRUE;
if( load->memory ) {
#ifdef DEBUG
printf( "vips_foreign_load_temp: forced memory temp\n" );
#endif /*DEBUG*/
return( vips_image_new_memory() );
}
/* If this is a partial operation, we can open directly.
*/
if( load->flags & VIPS_FOREIGN_PARTIAL ) {
#ifdef DEBUG
printf( "vips_foreign_load_temp: partial temp\n" );
#endif /*DEBUG*/
return( vips_image_new() );
}
/* If it can do sequential access and it's been requested, we can open
* directly.
*/
if( (load->flags & VIPS_FOREIGN_SEQUENTIAL) &&
load->access != VIPS_ACCESS_RANDOM ) {
#ifdef DEBUG
printf( "vips_foreign_load_temp: partial sequential temp\n" );
#endif /*DEBUG*/
return( vips_image_new() );
}
2012-02-15 16:47:43 +01:00
/* We open via disc if the uncompressed image will be larger than
* vips_get_disc_threshold()
*/
if( image_size > disc_threshold ) {
2012-02-15 16:47:43 +01:00
#ifdef DEBUG
printf( "vips_foreign_load_temp: disc temp\n" );
2012-02-15 16:47:43 +01:00
#endif /*DEBUG*/
return( vips_image_new_temp_file( "%s.v" ) );
2012-02-15 16:47:43 +01:00
}
2012-02-15 16:47:43 +01:00
#ifdef DEBUG
printf( "vips_foreign_load_temp: fallback memory temp\n" );
2012-02-15 16:47:43 +01:00
#endif /*DEBUG*/
/* Otherwise, fall back to a memory buffer.
*/
return( vips_image_new_memory() );
2012-02-15 16:47:43 +01:00
}
/* Check two images for compatibility: their geometries need to match.
*/
static gboolean
vips_foreign_load_iscompat( VipsImage *a, VipsImage *b )
{
if( a->Xsize != b->Xsize ||
a->Ysize != b->Ysize ||
a->Bands != b->Bands ||
a->Coding != b->Coding ||
a->BandFmt != b->BandFmt ) {
vips_error( "VipsForeignLoad",
"%s", _( "images do not match" ) );
return( FALSE );
}
return( TRUE );
}
2011-11-24 15:53:30 +01:00
/* Our start function ... do the lazy open, if necessary, and return a region
* on the new image.
2011-11-23 18:38:19 +01:00
*/
2011-11-24 15:53:30 +01:00
static void *
2012-02-15 16:47:43 +01:00
vips_foreign_load_start( VipsImage *out, void *a, void *b )
2011-11-24 15:53:30 +01:00
{
2012-02-15 16:47:43 +01:00
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( b );
VipsForeignLoadClass *class = VIPS_FOREIGN_LOAD_GET_CLASS( load );
2011-11-24 15:53:30 +01:00
/* If this start has failed before in another thread, we can fail now.
*/
if( load->error )
return( NULL );
2011-11-24 15:53:30 +01:00
if( !load->real ) {
2012-02-15 16:47:43 +01:00
if( !(load->real = vips_foreign_load_temp( load )) )
return( NULL );
#ifdef DEBUG
printf( "vips_foreign_load_start: triggering ->load()\n" );
#endif /*DEBUG*/
2011-11-24 22:53:40 +01:00
2015-06-19 16:00:48 +02:00
/* Read the image in. This may involve a long computation and
* will finish with load->real holding the decompressed image.
*
* We want our caller to be able to see this computation on
* @out, so eval signals on ->real need to appear on ->out.
2011-11-24 22:53:40 +01:00
*/
load->real->progress_signal = load->out;
2015-06-19 16:00:48 +02:00
/* Note the load object on the image. Loaders can use
* this to signal invalidate if they hit a load error. See
* vips_foreign_load_invalidate() below.
*/
g_object_set_qdata( G_OBJECT( load->real ),
vips__foreign_load_operation, load );
/* Load the image and check the result.
*
2019-07-28 18:15:54 +02:00
* ->header() read the header into @out, load will read the
* image into @real. They must match exactly in size, bands,
* format and coding for the copy to work.
*
2012-01-18 18:39:01 +01:00
* Some versions of ImageMagick give different results between
* Ping and Load for some formats, for example.
*
* If the load fails, we need to stop
*/
if( class->load( load ) ||
vips_image_pio_input( load->real ) ||
2018-03-05 16:03:49 +01:00
!vips_foreign_load_iscompat( load->real, out ) ) {
vips_operation_invalidate( VIPS_OPERATION( load ) );
load->error = TRUE;
return( NULL );
}
/* We have to tell vips that out depends on real. We've set
* the demand hint below, but not given an input there.
*/
vips_image_pipelinev( load->out, load->out->dhint,
load->real, NULL );
2011-11-24 15:53:30 +01:00
}
2011-11-23 18:38:19 +01:00
2011-11-24 15:53:30 +01:00
return( vips_region_new( load->real ) );
}
2011-11-23 18:38:19 +01:00
2011-11-24 15:53:30 +01:00
/* Just pointer-copy.
*/
static int
2011-12-11 23:01:39 +01:00
vips_foreign_load_generate( VipsRegion *or,
2011-11-24 15:53:30 +01:00
void *seq, void *a, void *b, gboolean *stop )
2011-11-23 18:38:19 +01:00
{
2011-11-24 15:53:30 +01:00
VipsRegion *ir = (VipsRegion *) seq;
2011-11-23 18:38:19 +01:00
2011-11-24 15:53:30 +01:00
VipsRect *r = &or->valid;
2011-11-23 18:38:19 +01:00
2011-11-24 15:53:30 +01:00
/* Ask for input we need.
*/
if( vips_region_prepare( ir, r ) )
return( -1 );
/* Attach output region to that.
*/
if( vips_region_region( or, ir, r, r->left, r->top ) )
return( -1 );
return( 0 );
2011-11-23 18:38:19 +01:00
}
static int
2011-11-29 12:43:08 +01:00
vips_foreign_load_build( VipsObject *object )
2011-11-23 18:38:19 +01:00
{
2012-11-02 15:41:47 +01:00
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
2011-11-29 12:43:08 +01:00
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( object );
2012-11-02 15:41:47 +01:00
VipsForeignLoadClass *fclass = VIPS_FOREIGN_LOAD_GET_CLASS( object );
2011-11-23 18:38:19 +01:00
2011-12-01 22:59:21 +01:00
VipsForeignFlags flags;
gboolean sequential;
2011-12-01 22:59:21 +01:00
#ifdef DEBUG
printf( "vips_foreign_load_build:\n" );
#endif /*DEBUG*/
2011-12-01 22:59:21 +01:00
flags = 0;
2012-11-02 15:41:47 +01:00
if( fclass->get_flags )
flags |= fclass->get_flags( load );
if( (flags & VIPS_FOREIGN_PARTIAL) &&
(flags & VIPS_FOREIGN_SEQUENTIAL) ) {
g_warning( "%s",
_( "VIPS_FOREIGN_PARTIAL and VIPS_FOREIGN_SEQUENTIAL "
"both set -- using SEQUENTIAL" ) );
flags ^= VIPS_FOREIGN_PARTIAL;
}
2011-12-01 22:59:21 +01:00
g_object_set( load, "flags", flags, NULL );
2011-11-24 15:53:30 +01:00
/* Seq access has been requested and the loader supports seq.
*/
sequential = (load->flags & VIPS_FOREIGN_SEQUENTIAL) &&
load->access != VIPS_ACCESS_RANDOM;
/* We must block caching of seq loads.
*/
if( sequential )
load->nocache = TRUE;
2011-11-29 12:43:08 +01:00
if( VIPS_OBJECT_CLASS( vips_foreign_load_parent_class )->
2011-11-23 18:38:19 +01:00
build( object ) )
return( -1 );
if( load->sequential )
g_warning( "%s",
_( "ignoring deprecated \"sequential\" mode -- "
"please use \"access\" instead" ) );
2011-11-30 23:06:52 +01:00
g_object_set( object, "out", vips_image_new(), NULL );
vips_image_set_string( load->out,
VIPS_META_LOADER, class->nickname );
#ifdef DEBUG
printf( "vips_foreign_load_build: triggering ->header()\n" );
#endif /*DEBUG*/
2011-11-27 22:31:21 +01:00
/* Read the header into @out.
2011-11-24 15:53:30 +01:00
*/
2012-11-02 15:41:47 +01:00
if( fclass->header &&
fclass->header( load ) )
2011-11-24 15:53:30 +01:00
return( -1 );
2011-11-27 22:31:21 +01:00
/* If there's no ->load() method then the header read has done
* everything. Otherwise, it's just set fields and we must also
* load pixels.
*
* Delay the load until the first pixel is requested by doing the work
* in the start function of the copy.
2011-11-24 15:53:30 +01:00
*/
2012-11-02 15:41:47 +01:00
if( fclass->load ) {
#ifdef DEBUG
printf( "vips_foreign_load_build: delaying read ...\n" );
#endif /*DEBUG*/
2011-12-11 23:01:39 +01:00
/* ->header() should set the dhint. It'll default to the safe
* SMALLTILE if header() did not set it.
2011-11-27 22:31:21 +01:00
*/
vips_image_pipelinev( load->out, load->out->dhint, NULL );
2011-11-27 22:31:21 +01:00
/* Then 'start' creates the real image and 'gen' fetches
* pixels for @out from @real on demand.
*/
if( vips_image_generate( load->out,
2011-12-11 23:01:39 +01:00
vips_foreign_load_start,
vips_foreign_load_generate,
2011-11-27 22:31:21 +01:00
vips_stop_one,
NULL, load ) )
2011-11-27 22:31:21 +01:00
return( -1 );
}
/* Tell downstream if we are reading sequentially.
*/
if( sequential )
vips_image_set_area( load->out,
VIPS_META_SEQUENTIAL, NULL, NULL );
2011-11-24 15:53:30 +01:00
2011-11-23 18:38:19 +01:00
return( 0 );
}
static VipsOperationFlags
vips_foreign_load_operation_get_flags( VipsOperation *operation )
{
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( operation );
VipsOperationFlags flags;
flags = VIPS_OPERATION_CLASS( vips_foreign_load_parent_class )->
get_flags( operation );
if( load->nocache )
flags |= VIPS_OPERATION_NOCACHE;
return( flags );
}
2011-11-23 18:38:19 +01:00
static void
2011-11-29 12:43:08 +01:00
vips_foreign_load_class_init( VipsForeignLoadClass *class )
2011-11-23 18:38:19 +01:00
{
2011-11-24 22:53:40 +01:00
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
2011-11-23 18:38:19 +01:00
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = (VipsOperationClass *) class;
2011-11-23 18:38:19 +01:00
2011-11-29 12:43:08 +01:00
gobject_class->dispose = vips_foreign_load_dispose;
2011-11-24 22:53:40 +01:00
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
2011-11-29 12:43:08 +01:00
object_class->build = vips_foreign_load_build;
2012-01-16 15:54:29 +01:00
object_class->summary_class = vips_foreign_load_summary_class;
2011-11-29 12:43:08 +01:00
object_class->new_from_string = vips_foreign_load_new_from_string;
2011-11-24 10:57:01 +01:00
object_class->nickname = "fileload";
object_class->description = _( "file loaders" );
2011-11-23 18:38:19 +01:00
operation_class->get_flags = vips_foreign_load_operation_get_flags;
2011-11-24 22:53:40 +01:00
VIPS_ARG_IMAGE( class, "out", 2,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
2011-11-29 12:43:08 +01:00
G_STRUCT_OFFSET( VipsForeignLoad, out ) );
2011-11-24 22:53:40 +01:00
VIPS_ARG_FLAGS( class, "flags", 106,
2011-11-23 18:38:19 +01:00
_( "Flags" ),
2011-11-24 10:57:01 +01:00
_( "Flags for this file" ),
2011-11-23 18:38:19 +01:00
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
2011-11-29 12:43:08 +01:00
G_STRUCT_OFFSET( VipsForeignLoad, flags ),
VIPS_TYPE_FOREIGN_FLAGS, VIPS_FOREIGN_NONE );
2011-11-23 18:38:19 +01:00
VIPS_ARG_BOOL( class, "memory", 107,
_( "Memory" ),
_( "Force open via memory" ),
2011-11-24 15:53:30 +01:00
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoad, memory ),
FALSE );
VIPS_ARG_ENUM( class, "access", 108,
_( "Access" ),
_( "Required access pattern for this file" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoad, access ),
VIPS_TYPE_ACCESS, VIPS_ACCESS_RANDOM );
VIPS_ARG_BOOL( class, "sequential", 109,
_( "Sequential" ),
_( "Sequential read only" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignLoad, sequential ),
FALSE );
VIPS_ARG_BOOL( class, "fail", 110,
_( "Fail" ),
_( "Fail on first error" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoad, fail ),
FALSE );
VIPS_ARG_BOOL( class, "disc", 111,
_( "Disc" ),
_( "Open to disc" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsForeignLoad, disc ),
TRUE );
2011-11-23 18:38:19 +01:00
}
static void
2011-11-29 12:43:08 +01:00
vips_foreign_load_init( VipsForeignLoad *load )
2011-11-23 18:38:19 +01:00
{
2011-11-24 22:53:40 +01:00
load->disc = TRUE;
load->access = VIPS_ACCESS_RANDOM;
2011-11-23 18:38:19 +01:00
}
/*
* Loaders can call this
*/
/**
* vips_foreign_load_invalidate: (method)
* @image: image to invalidate
*
* Loaders can call this on the image they are making if they see a read error
* from the load library. It signals "invalidate" on the load operation and
2017-01-18 15:39:27 +01:00
* will cause it to be dropped from cache.
*
2017-01-17 15:53:40 +01:00
* If we know a file will cause a read error, we don't want to cache the
* failing operation, we want to make sure the image will really be opened
* again if our caller tries again. For example, a broken file might be
* replaced by a working one.
*/
void
vips_foreign_load_invalidate( VipsImage *image )
{
VipsOperation *operation;
#ifdef DEBUG
printf( "vips_foreign_load_invalidate: %p\n", image );
#endif /*DEBUG*/
if( (operation = g_object_get_qdata( G_OBJECT( image ),
vips__foreign_load_operation )) ) {
vips_operation_invalidate( operation );
}
}
2011-11-23 18:38:19 +01:00
/* Abstract base class for image savers.
*/
2011-11-29 12:43:08 +01:00
G_DEFINE_ABSTRACT_TYPE( VipsForeignSave, vips_foreign_save, VIPS_TYPE_FOREIGN );
2011-11-23 18:38:19 +01:00
2011-11-25 15:34:17 +01:00
static void
2011-11-29 12:43:08 +01:00
vips_foreign_save_dispose( GObject *gobject )
2011-11-25 15:34:17 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignSave *save = VIPS_FOREIGN_SAVE( gobject );
2011-11-25 15:34:17 +01:00
VIPS_UNREF( save->ready );
2011-11-29 12:43:08 +01:00
G_OBJECT_CLASS( vips_foreign_save_parent_class )->dispose( gobject );
2011-11-25 15:34:17 +01:00
}
2011-11-23 18:38:19 +01:00
static void
2012-01-16 15:54:29 +01:00
vips_foreign_save_summary_class( VipsObjectClass *object_class, VipsBuf *buf )
2011-11-23 18:38:19 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_CLASS( object_class );
2011-11-25 15:34:17 +01:00
2011-11-29 12:43:08 +01:00
VIPS_OBJECT_CLASS( vips_foreign_save_parent_class )->
2012-01-16 15:54:29 +01:00
summary_class( object_class, buf );
2011-11-23 18:38:19 +01:00
2011-11-25 15:34:17 +01:00
vips_buf_appendf( buf, ", %s",
2012-01-27 18:14:59 +01:00
vips_enum_nick( VIPS_TYPE_SAVEABLE, class->saveable ) );
2011-11-23 18:38:19 +01:00
}
2011-11-27 22:31:21 +01:00
static VipsObject *
2011-11-29 12:43:08 +01:00
vips_foreign_save_new_from_string( const char *string )
2011-11-27 22:31:21 +01:00
{
const char *file_op;
GType type;
2011-11-29 12:43:08 +01:00
VipsForeignSave *save;
2011-11-27 22:31:21 +01:00
2011-11-29 12:43:08 +01:00
if( !(file_op = vips_foreign_find_save( string )) )
2011-11-27 22:31:21 +01:00
return( NULL );
type = g_type_from_name( file_op );
g_assert( type );
2011-11-29 12:43:08 +01:00
save = VIPS_FOREIGN_SAVE( g_object_new( type, NULL ) );
2011-11-27 22:31:21 +01:00
g_object_set( save,
"filename", string,
NULL );
return( VIPS_OBJECT( save ) );
}
/* Convert an image for saving.
2011-11-25 10:15:45 +01:00
*/
int
vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready,
VipsSaveable saveable, VipsBandFormat *format, VipsCoding *coding,
VipsArrayDouble *background )
2011-11-25 10:15:45 +01:00
{
2011-11-25 15:34:17 +01:00
/* in holds a reference to the output of our chain as we build it.
*/
g_object_ref( in );
2012-09-26 15:53:14 +02:00
/* For coded images, can this class save the coding we are in now?
* Nothing to do.
2011-12-20 15:57:05 +01:00
*/
if( in->Coding != VIPS_CODING_NONE &&
coding[in->Coding] ) {
*ready = in;
2011-12-20 15:57:05 +01:00
return( 0 );
}
2012-09-26 15:53:14 +02:00
/* For uncoded images, if this saver supports ANY bands and this
* format we have nothing to do.
*/
if( in->Coding == VIPS_CODING_NONE &&
saveable == VIPS_SAVEABLE_ANY &&
format[in->BandFmt] == in->BandFmt ) {
*ready = in;
2012-09-26 15:53:14 +02:00
return( 0 );
}
2011-12-20 15:57:05 +01:00
/* Otherwise ... we need to decode and then (possibly) recode at the
* end.
*/
2011-11-25 10:15:45 +01:00
/* If this is an VIPS_CODING_LABQ, we can go straight to RGB.
*/
if( in->Coding == VIPS_CODING_LABQ ) {
2011-11-25 15:34:17 +01:00
VipsImage *out;
2011-11-25 10:15:45 +01:00
if( vips_LabQ2sRGB( in, &out, NULL ) ) {
2011-11-25 15:34:17 +01:00
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
/* If this is an VIPS_CODING_RAD, we unpack to float. This could be
* scRGB or XYZ.
2011-11-25 10:15:45 +01:00
*/
2011-11-25 15:34:17 +01:00
if( in->Coding == VIPS_CODING_RAD ) {
VipsImage *out;
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
if( vips_rad2float( in, &out, NULL ) ) {
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
2014-11-10 13:56:28 +01:00
/* If the saver supports RAD, we need to go to scRGB or XYZ.
*/
if( coding[VIPS_CODING_RAD] ) {
2014-11-10 13:56:28 +01:00
if( in->Type != VIPS_INTERPRETATION_scRGB &&
in->Type != VIPS_INTERPRETATION_XYZ ) {
VipsImage *out;
if( vips_colourspace( in, &out,
VIPS_INTERPRETATION_scRGB, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
}
/* If this image is CMYK and the saver is RGB-only, use lcms to try to
* import to XYZ. This will only work if the image has an embedded
* profile.
*/
if( in->Type == VIPS_INTERPRETATION_CMYK &&
in->Bands >= 4 &&
(saveable == VIPS_SAVEABLE_RGB ||
saveable == VIPS_SAVEABLE_RGBA ||
saveable == VIPS_SAVEABLE_RGBA_ONLY) ) {
VipsImage *out;
if( vips_icc_import( in, &out,
"pcs", VIPS_PCS_XYZ,
NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
2014-11-10 13:56:28 +01:00
/* If this is something other than CMYK or RAD, eg. maybe a LAB image,
* we need to transform to RGB.
*/
if( !coding[VIPS_CODING_RAD] &&
2014-11-10 13:56:28 +01:00
in->Bands >= 3 &&
in->Type != VIPS_INTERPRETATION_CMYK &&
vips_colourspace_issupported( in ) &&
(saveable == VIPS_SAVEABLE_RGB ||
saveable == VIPS_SAVEABLE_RGBA ||
saveable == VIPS_SAVEABLE_RGBA_ONLY ||
saveable == VIPS_SAVEABLE_RGB_CMYK) ) {
2014-11-10 13:56:28 +01:00
VipsImage *out;
VipsInterpretation interpretation;
/* Do we make RGB or RGB16? We don't want to squash a 16-bit
* RGB down to 8 bits if the saver supports 16.
*/
if( vips_band_format_is8bit( format[in->BandFmt] ) )
2014-11-10 13:56:28 +01:00
interpretation = VIPS_INTERPRETATION_sRGB;
else
interpretation = VIPS_INTERPRETATION_RGB16;
if( vips_colourspace( in, &out, interpretation, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
/* VIPS_SAVEABLE_RGBA_ONLY does not support 1 or 2 bands ... convert
* to sRGB.
*/
if( !coding[VIPS_CODING_RAD] &&
in->Bands < 3 &&
vips_colourspace_issupported( in ) &&
saveable == VIPS_SAVEABLE_RGBA_ONLY ) {
VipsImage *out;
VipsInterpretation interpretation;
/* Do we make RGB or RGB16? We don't want to squash a 16-bit
* RGB down to 8 bits if the saver supports 16.
*/
if( vips_band_format_is8bit( format[in->BandFmt] ) )
interpretation = VIPS_INTERPRETATION_sRGB;
else
interpretation = VIPS_INTERPRETATION_RGB16;
if( vips_colourspace( in, &out, interpretation, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
2014-11-10 13:56:28 +01:00
/* Get the bands right. We must do this after all colourspace
* transforms, since they can change the number of bands.
2011-11-25 10:15:45 +01:00
*/
2011-11-25 15:34:17 +01:00
if( in->Coding == VIPS_CODING_NONE ) {
/* Do we need to flatten out an alpha channel? There needs to
* be an alpha there now, and this writer needs to not support
* alpha.
*/
if( (in->Bands == 2 ||
(in->Bands == 4 &&
in->Type != VIPS_INTERPRETATION_CMYK)) &&
(saveable == VIPS_SAVEABLE_MONO ||
saveable == VIPS_SAVEABLE_RGB ||
saveable == VIPS_SAVEABLE_RGB_CMYK) ) {
2011-11-25 15:34:17 +01:00
VipsImage *out;
if( vips_flatten( in, &out,
"background", background,
NULL ) ) {
2011-11-25 15:34:17 +01:00
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
/* Other alpha removal strategies ... just drop the extra
* bands.
*/
2011-11-25 15:34:17 +01:00
else if( in->Bands > 3 &&
(saveable == VIPS_SAVEABLE_RGB ||
(saveable == VIPS_SAVEABLE_RGB_CMYK &&
in->Type != VIPS_INTERPRETATION_CMYK)) ) {
2011-11-25 15:34:17 +01:00
VipsImage *out;
/* Don't let 4 bands though unless the image really is
* a CMYK.
*
* Consider a RGBA png being saved as JPG. We can
* write CMYK jpg, but we mustn't do that for RGBA
* images.
*/
2011-11-25 15:34:17 +01:00
if( vips_extract_band( in, &out, 0,
"n", 3,
NULL ) ) {
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
else if( in->Bands > 4 &&
((saveable == VIPS_SAVEABLE_RGB_CMYK &&
in->Type == VIPS_INTERPRETATION_CMYK) ||
saveable == VIPS_SAVEABLE_RGBA ||
saveable == VIPS_SAVEABLE_RGBA_ONLY) ) {
2011-11-25 15:34:17 +01:00
VipsImage *out;
if( vips_extract_band( in, &out, 0,
"n", 4,
NULL ) ) {
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
2011-12-16 16:24:35 +01:00
else if( in->Bands > 1 &&
saveable == VIPS_SAVEABLE_MONO ) {
2011-12-16 16:24:35 +01:00
VipsImage *out;
if( vips_extract_band( in, &out, 0, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
/* Else we have VIPS_SAVEABLE_ANY and we don't chop bands down.
2011-11-25 10:15:45 +01:00
*/
}
/* Handle the ushort interpretations.
2013-05-28 11:32:37 +02:00
*
* RGB16 and GREY16 use 0-65535 for black-white. If we have an image
* tagged like this, and it has more than 8 bits (we leave crazy uchar
* images tagged as RGB16 alone), we'll need to get it ready for the
* saver.
2013-05-28 11:32:37 +02:00
*/
if( (in->Type == VIPS_INTERPRETATION_RGB16 ||
in->Type == VIPS_INTERPRETATION_GREY16) &&
!vips_band_format_is8bit( in->BandFmt ) ) {
/* If the saver supports ushort, cast to ushort. It may be
* float at the moment, for example.
*
* If the saver does not support ushort, automatically shift
* it down. This is the behaviour we want for saving an RGB16
* image as JPG, for example.
*/
if( format[VIPS_FORMAT_USHORT] == VIPS_FORMAT_USHORT ) {
VipsImage *out;
2013-05-28 11:32:37 +02:00
if( vips_cast( in, &out, VIPS_FORMAT_USHORT, NULL ) ) {
g_object_unref( in );
return( -1 );
}
2013-05-28 11:32:37 +02:00
g_object_unref( in );
in = out;
2013-05-28 11:32:37 +02:00
}
else {
VipsImage *out;
2013-05-28 11:32:37 +02:00
if( vips_rshift_const1( in, &out, 8, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
/* That could have produced an int image ... make sure
* we are now uchar.
*/
if( vips_cast( in, &out, VIPS_FORMAT_UCHAR, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
}
2013-05-28 11:32:37 +02:00
}
2011-11-25 10:15:45 +01:00
/* Cast to the output format.
*/
{
2011-11-25 15:34:17 +01:00
VipsImage *out;
2011-11-25 10:15:45 +01:00
if( vips_cast( in, &out, format[in->BandFmt], NULL ) ) {
2011-11-25 15:34:17 +01:00
g_object_unref( in );
return( -1 );
2011-11-25 10:15:45 +01:00
}
2011-11-25 15:34:17 +01:00
g_object_unref( in );
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
in = out;
2011-11-25 10:15:45 +01:00
}
2012-01-12 14:39:58 +01:00
/* Does this class want a coded image? Search the coding table for the
* first one.
2011-12-20 15:57:05 +01:00
*/
if( coding[VIPS_CODING_NONE] ) {
2012-01-12 14:39:58 +01:00
/* Already NONE, nothing to do.
*/
}
else if( coding[VIPS_CODING_LABQ] ) {
2012-01-12 14:39:58 +01:00
VipsImage *out;
2011-12-20 15:57:05 +01:00
if( vips_Lab2LabQ( in, &out, NULL ) ) {
2011-12-20 15:57:05 +01:00
g_object_unref( in );
2012-01-12 14:39:58 +01:00
return( -1 );
2011-12-20 15:57:05 +01:00
}
2012-01-12 14:39:58 +01:00
g_object_unref( in );
2011-12-20 15:57:05 +01:00
2012-01-12 14:39:58 +01:00
in = out;
}
else if( coding[VIPS_CODING_RAD] ) {
2012-01-12 14:39:58 +01:00
VipsImage *out;
2011-12-20 15:57:05 +01:00
if( vips_float2rad( in, &out, NULL ) ) {
2012-01-12 14:39:58 +01:00
g_object_unref( in );
return( -1 );
2011-12-20 15:57:05 +01:00
}
2012-01-12 14:39:58 +01:00
g_object_unref( in );
in = out;
2011-12-20 15:57:05 +01:00
}
/* Some format libraries, like libpng, will throw a hard error if the
* profile is inappropriate for this image type. With profiles inherited
* from a source image, this can happen all the time, so we
* want to silently drop the profile in this case.
*/
if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) {
const void *data;
size_t length;
if( !vips_image_get_blob( in, VIPS_META_ICC_NAME,
&data, &length ) &&
!vips_icc_is_compatible_profile( in, data, length ) ) {
VipsImage *out;
if( vips_copy( in, &out, NULL ) ) {
g_object_unref( in );
return( -1 );
}
g_object_unref( in );
in = out;
vips_image_remove( in, VIPS_META_ICC_NAME );
}
}
*ready = in;
2011-11-25 10:15:45 +01:00
2011-11-25 15:34:17 +01:00
return( 0 );
2011-11-25 10:15:45 +01:00
}
2011-11-23 18:38:19 +01:00
static int
2011-11-29 12:43:08 +01:00
vips_foreign_save_build( VipsObject *object )
2011-11-23 18:38:19 +01:00
{
2011-11-29 12:43:08 +01:00
VipsForeignSave *save = VIPS_FOREIGN_SAVE( object );
2011-11-23 18:38:19 +01:00
if( save->in ) {
VipsForeignSaveClass *class =
VIPS_FOREIGN_SAVE_GET_CLASS( save );
VipsImage *ready;
if( vips__foreign_convert_saveable( save->in, &ready,
class->saveable, class->format_table, class->coding,
save->background ) )
return( -1 );
if( save->page_height ) {
VipsImage *x;
if( vips_copy( ready, &x, NULL ) ) {
VIPS_UNREF( ready );
return( -1 );
}
VIPS_UNREF( ready );
ready = x;
2017-06-19 10:31:49 +02:00
vips_image_set_int( ready,
VIPS_META_PAGE_HEIGHT, save->page_height );
}
2017-06-19 10:31:49 +02:00
VIPS_UNREF( save->ready );
save->ready = ready;
}
2011-11-25 10:15:45 +01:00
2011-11-29 12:43:08 +01:00
if( VIPS_OBJECT_CLASS( vips_foreign_save_parent_class )->
2011-11-23 18:38:19 +01:00
build( object ) )
return( -1 );
return( 0 );
}
#define UC VIPS_FORMAT_UCHAR
#define C VIPS_FORMAT_CHAR
#define US VIPS_FORMAT_USHORT
#define S VIPS_FORMAT_SHORT
#define UI VIPS_FORMAT_UINT
#define I VIPS_FORMAT_INT
#define F VIPS_FORMAT_FLOAT
#define X VIPS_FORMAT_COMPLEX
#define D VIPS_FORMAT_DOUBLE
#define DX VIPS_FORMAT_DPCOMPLEX
static int vips_foreign_save_format_table[10] = {
// UC C US S UI I F X D DX
UC, C, US, S, UI, I, F, X, D, DX
};
2011-11-23 18:38:19 +01:00
static void
2011-11-29 12:43:08 +01:00
vips_foreign_save_class_init( VipsForeignSaveClass *class )
2011-11-23 18:38:19 +01:00
{
2011-11-24 22:53:40 +01:00
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
2011-11-23 18:38:19 +01:00
VipsObjectClass *object_class = (VipsObjectClass *) class;
2012-07-10 12:45:19 +02:00
VipsOperationClass *operation_class = (VipsOperationClass *) class;
int i;
2011-11-23 18:38:19 +01:00
2011-11-29 12:43:08 +01:00
gobject_class->dispose = vips_foreign_save_dispose;
2011-11-24 22:53:40 +01:00
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
2011-11-29 12:43:08 +01:00
object_class->build = vips_foreign_save_build;
2012-01-16 15:54:29 +01:00
object_class->summary_class = vips_foreign_save_summary_class;
2011-11-29 12:43:08 +01:00
object_class->new_from_string = vips_foreign_save_new_from_string;
2011-11-24 10:57:01 +01:00
object_class->nickname = "filesave";
object_class->description = _( "file savers" );
2011-11-23 18:38:19 +01:00
/* All savers are sequential by definition. Things like tiled tiff
* write and interlaced png write, which are not, add extra caches
* on their input.
2012-07-10 12:45:19 +02:00
*/
2017-03-06 12:55:38 +01:00
operation_class->flags |= VIPS_OPERATION_SEQUENTIAL;
2012-07-10 12:45:19 +02:00
/* Must not cache savers.
*/
operation_class->flags |= VIPS_OPERATION_NOCACHE;
2012-01-12 14:39:58 +01:00
/* Default to no coding allowed.
*/
for( i = 0; i < VIPS_CODING_LAST; i++ )
class->coding[i] = FALSE;
class->coding[VIPS_CODING_NONE] = TRUE;
2011-12-20 15:57:05 +01:00
/* Default to no cast on save.
*/
class->format_table = vips_foreign_save_format_table;
2011-11-24 22:53:40 +01:00
VIPS_ARG_IMAGE( class, "in", 0,
2011-11-23 18:38:19 +01:00
_( "Input" ),
_( "Image to save" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
2011-11-29 12:43:08 +01:00
G_STRUCT_OFFSET( VipsForeignSave, in ) );
VIPS_ARG_BOOL( class, "strip", 100,
_( "Strip" ),
_( "Strip all metadata from image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSave, strip ),
FALSE );
VIPS_ARG_BOXED( class, "background", 101,
_( "Background" ),
_( "Background value" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSave, background ),
VIPS_TYPE_ARRAY_DOUBLE );
2017-06-19 10:31:49 +02:00
VIPS_ARG_INT( class, "page_height", 102,
2017-06-19 10:31:49 +02:00
_( "Page height" ),
_( "Set page height for multipage save" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSave, page_height ),
0, VIPS_MAX_COORD, 0 );
2011-11-23 18:38:19 +01:00
}
static void
vips_foreign_save_init( VipsForeignSave *save )
2011-11-23 18:38:19 +01:00
{
save->background = vips_array_double_newv( 1, 0.0 );
2011-11-23 18:38:19 +01:00
}
2019-10-14 19:03:45 +02:00
/* Can we write this filename with this class?
2011-11-23 18:38:19 +01:00
*/
static void *
vips_foreign_find_save_sub( VipsForeignSaveClass *save_class,
const char *filename )
2011-11-23 18:38:19 +01:00
{
2019-10-14 19:03:45 +02:00
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
2011-11-23 18:38:19 +01:00
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
2019-10-14 19:03:45 +02:00
!vips_ispostfix( object_class->nickname, "_buffer" ) &&
!vips_ispostfix( object_class->nickname, "_target" ) &&
vips_filename_suffix_match( filename, class->suffs ) )
return( save_class );
2011-11-24 15:53:30 +01:00
return( NULL );
2011-11-23 18:38:19 +01:00
}
2014-04-22 17:27:43 +02:00
/**
* vips_foreign_find_save:
* @filename: name to find a saver for
2014-04-22 17:27:43 +02:00
*
* Searches for an operation you could use to write to @filename.
* Any trailing options on @filename are stripped and ignored.
2014-04-22 17:27:43 +02:00
*
2014-11-17 11:32:40 +01:00
* See also: vips_foreign_find_save_buffer(), vips_image_write_to_file().
2014-04-22 17:27:43 +02:00
*
* Returns: the name of an operation on success, %NULL on error
2014-04-22 17:27:43 +02:00
*/
const char *
vips_foreign_find_save( const char *name )
2014-04-22 17:27:43 +02:00
{
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
VipsForeignSaveClass *save_class;
2014-04-22 17:27:43 +02:00
vips__filename_split8( name, filename, option_string );
2014-04-22 17:27:43 +02:00
if( !(save_class = (VipsForeignSaveClass *) vips_foreign_map(
"VipsForeignSave",
(VipsSListMap2Fn) vips_foreign_find_save_sub,
(void *) filename, NULL )) ) {
vips_error( "VipsForeignSave",
_( "\"%s\" is not a known file format" ), name );
2014-04-22 17:27:43 +02:00
return( NULL );
}
2014-04-22 17:27:43 +02:00
return( G_OBJECT_CLASS_NAME( save_class ) );
2014-04-22 17:27:43 +02:00
}
static void *
vips_foreign_get_suffixes_count_cb( VipsForeignSaveClass *save_class,
void *a, void *b )
{
VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS( save_class );
int *n_fields = (int *) a;
int i;
if( foreign_class->suffs )
for( i = 0; foreign_class->suffs[i]; i++ )
*n_fields += 1;
return( NULL );
}
static void *
vips_foreign_get_suffixes_add_cb( VipsForeignSaveClass *save_class,
void *a, void *b )
{
VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS( save_class );
gchar ***p = (gchar ***) a;
int i;
if( foreign_class->suffs )
for( i = 0; foreign_class->suffs[i]; i++ ) {
**p = g_strdup( foreign_class->suffs[i] );
*p += 1;
}
return( NULL );
}
/**
* vips_foreign_get_suffixes: (method)
*
* Get a %NULL-terminated array listing all the supported suffixes.
*
* This is not the same as all the supported file types, since libvips
* detects image format for load by testing the first few bytes.
*
* Use vips_foreign_find_load() to detect type for a specific file.
*
* Free the return result with g_strfreev().
*
* Returns: (transfer full): all supported file extensions, as a
* %NULL-terminated array.
*/
gchar **
vips_foreign_get_suffixes( void )
{
int n_suffs;
gchar **suffs;
gchar **p;
n_suffs = 0;
(void) vips_foreign_map(
"VipsForeignSave",
(VipsSListMap2Fn) vips_foreign_get_suffixes_count_cb,
&n_suffs, NULL );
suffs = g_new0( gchar *, n_suffs + 1 );
p = suffs;
(void) vips_foreign_map(
"VipsForeignSave",
(VipsSListMap2Fn) vips_foreign_get_suffixes_add_cb,
&p, NULL );
return( suffs );
}
/* Kept for early vips8 API compat.
2011-11-23 18:38:19 +01:00
*/
2011-11-23 18:38:19 +01:00
int
vips_foreign_save( VipsImage *in, const char *name, ... )
2011-11-23 18:38:19 +01:00
{
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
const char *operation_name;
2011-11-24 15:53:30 +01:00
va_list ap;
int result;
2011-11-23 18:38:19 +01:00
vips__filename_split8( name, filename, option_string );
if( !(operation_name = vips_foreign_find_save( filename )) )
2011-11-23 18:38:19 +01:00
return( -1 );
va_start( ap, name );
result = vips_call_split_option_string( operation_name, option_string,
ap, in, filename );
2011-11-24 15:53:30 +01:00
va_end( ap );
return( result );
2011-11-23 18:38:19 +01:00
}
/* Can this class write this filetype to a target?
*/
static void *
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_find_save_target_sub( VipsForeignSaveClass *save_class,
const char *suffix )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
vips_ispostfix( object_class->nickname, "_target" ) &&
vips_filename_suffix_match( suffix, class->suffs ) )
return( save_class );
return( NULL );
}
/**
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
* vips_foreign_find_save_target:
* @suffix: format to find a saver for
*
* Searches for an operation you could use to write to a target in @suffix
* format.
*
* See also: vips_image_write_to_buffer().
*
* Returns: the name of an operation on success, %NULL on error
*/
const char *
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
vips_foreign_find_save_target( const char *name )
{
char suffix[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
VipsForeignSaveClass *save_class;
vips__filename_split8( name, suffix, option_string );
if( !(save_class = (VipsForeignSaveClass *) vips_foreign_map(
"VipsForeignSave",
experiment with renaming stream rename as VipsConnection, VipsSource, VipsTarget etc. see https://github.com/libvips/libvips/issues/1494#issuecomment-569498619 renamed with this script: ``` set -e edit() { sed -i -E "$1" rename } for i in $*; do cp $i rename edit s/VIPS_STREAMOU/VIPS_TARGET_CUSTOM/g edit s/VIPS_STREAMO/VIPS_TARGET/g edit s/VIPS_STREAMIU/VIPS_SOURCE_CUSTOM/g edit s/VIPS_STREAMI/VIPS_SOURCE/g edit s/VIPS_STREAM/VIPS_CONNECTION/g edit s/vips_streamou/vips_target_custom/g edit s/vips_streamo/vips_target/g edit s/vips_streamiu/vips_source_custom/g edit s/vips_streami/vips_source/g edit s/vips_stream/vips_connection/g edit s/VipsStreamou/VipsTargetCustom/g edit s/VipsStreamo/VipsTarget/g edit s/VipsStreamiu/VipsSourceCustom/g edit s/VipsStreami/VipsSource/g edit s/VipsStream/VipsConnection/g # eg. VIPS_TYPE_STREAM or VIPS_IS_STREAM edit "s/VIPS_([A-Z]+)_STREAMOU/VIPS_\1_TARGET_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMO/VIPS_\1_TARGET/g" edit "s/VIPS_([A-Z]+)_STREAMIU/VIPS_\1_SOURCE_CUSTOM/g" edit "s/VIPS_([A-Z]+)_STREAMI/VIPS_\1_SOURCE/g" edit "s/VIPS_([A-Z]+)_STREAM/VIPS_\1_CONNECTION/g" edit s/streamou/target_custom/g edit s/streamo/target/g edit s/streamiu/source_custom/g edit s/streami/source/g # various identifiers which also change edit s/is_a_stream/is_a_source/g edit s/find_load_stream/find_load_source/g edit s/find_save_stream/find_save_target/g edit s/new_from_stream/new_from_source/g edit s/write_to_stream/write_to_target/g edit s/vips_thumbnail_stream/vips_thumbnail_source/g # eg. vips_webpload_stream edit "s/vips_([a-z]+)load_stream/vips_\1load_source/g" # eg. vips_webpsave_stream edit "s/vips_([a-z]+)save_stream/vips_\1save_target/g" mv rename $i done ```
2019-12-29 22:40:21 +01:00
(VipsSListMap2Fn) vips_foreign_find_save_target_sub,
(void *) suffix, NULL )) ) {
vips_error( "VipsForeignSave",
_( "\"%s\" is not a known target format" ), name );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( save_class ) );
}
/* Can we write this buffer with this file type?
*/
static void *
vips_foreign_find_save_buffer_sub( VipsForeignSaveClass *save_class,
const char *suffix )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
vips_ispostfix( object_class->nickname, "_buffer" ) &&
vips_filename_suffix_match( suffix, class->suffs ) )
return( save_class );
return( NULL );
}
/**
* vips_foreign_find_save_buffer:
* @suffix: name to find a saver for
*
* Searches for an operation you could use to write to a buffer in @suffix
* format.
*
* See also: vips_image_write_to_buffer().
*
* Returns: the name of an operation on success, %NULL on error
*/
const char *
vips_foreign_find_save_buffer( const char *name )
{
char suffix[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
VipsForeignSaveClass *save_class;
vips__filename_split8( name, suffix, option_string );
if( !(save_class = (VipsForeignSaveClass *) vips_foreign_map(
"VipsForeignSave",
(VipsSListMap2Fn) vips_foreign_find_save_buffer_sub,
(void *) suffix, NULL )) ) {
vips_error( "VipsForeignSave",
2015-06-08 10:00:04 +02:00
_( "\"%s\" is not a known buffer format" ), name );
return( NULL );
}
return( G_OBJECT_CLASS_NAME( save_class ) );
}
2011-11-24 22:53:40 +01:00
/* Called from iofuncs to init all operations in this dir. Use a plugin system
* instead?
*/
void
2011-11-29 12:43:08 +01:00
vips_foreign_operation_init( void )
2011-11-24 22:53:40 +01:00
{
extern GType vips_foreign_load_rad_file_get_type( void );
extern GType vips_foreign_load_rad_buffer_get_type( void );
extern GType vips_foreign_load_rad_source_get_type( void );
2016-05-23 16:37:28 +02:00
extern GType vips_foreign_save_rad_file_get_type( void );
extern GType vips_foreign_save_rad_buffer_get_type( void );
extern GType vips_foreign_save_rad_target_get_type( void );
2011-12-20 11:10:53 +01:00
extern GType vips_foreign_load_mat_get_type( void );
extern GType vips_foreign_load_ppm_file_get_type( void );
extern GType vips_foreign_save_ppm_file_get_type( void );
extern GType vips_foreign_load_png_file_get_type( void );
extern GType vips_foreign_load_png_buffer_get_type( void );
extern GType vips_foreign_load_png_source_get_type( void );
2011-12-19 22:40:08 +01:00
extern GType vips_foreign_save_png_file_get_type( void );
extern GType vips_foreign_save_png_buffer_get_type( void );
extern GType vips_foreign_save_png_target_get_type( void );
2020-02-21 17:04:29 +01:00
extern GType vips_foreign_load_csv_file_get_type( void );
2020-02-21 17:39:40 +01:00
extern GType vips_foreign_load_csv_source_get_type( void );
2020-02-21 18:57:28 +01:00
extern GType vips_foreign_save_csv_file_get_type( void );
extern GType vips_foreign_save_csv_target_get_type( void );
2020-02-22 16:02:12 +01:00
extern GType vips_foreign_load_matrix_file_get_type( void );
extern GType vips_foreign_load_matrix_source_get_type( void );
2020-02-22 18:55:04 +01:00
extern GType vips_foreign_save_matrix_file_get_type( void );
extern GType vips_foreign_save_matrix_target_get_type( void );
2013-10-25 13:02:02 +02:00
extern GType vips_foreign_print_matrix_get_type( void );
2011-12-13 18:50:55 +01:00
extern GType vips_foreign_load_fits_get_type( void );
extern GType vips_foreign_save_fits_get_type( void );
2011-12-14 19:02:46 +01:00
extern GType vips_foreign_load_analyze_get_type( void );
2011-12-13 11:20:22 +01:00
extern GType vips_foreign_load_openexr_get_type( void );
2011-12-11 23:01:39 +01:00
extern GType vips_foreign_load_openslide_get_type( void );
2011-11-29 19:13:14 +01:00
extern GType vips_foreign_load_jpeg_file_get_type( void );
extern GType vips_foreign_load_jpeg_buffer_get_type( void );
extern GType vips_foreign_load_jpeg_source_get_type( void );
2011-11-29 19:13:14 +01:00
extern GType vips_foreign_save_jpeg_file_get_type( void );
extern GType vips_foreign_save_jpeg_buffer_get_type( void );
extern GType vips_foreign_save_jpeg_target_get_type( void );
2011-11-29 23:14:06 +01:00
extern GType vips_foreign_save_jpeg_mime_get_type( void );
extern GType vips_foreign_load_tiff_file_get_type( void );
extern GType vips_foreign_load_tiff_buffer_get_type( void );
extern GType vips_foreign_load_tiff_source_get_type( void );
extern GType vips_foreign_save_tiff_file_get_type( void );
extern GType vips_foreign_save_tiff_buffer_get_type( void );
2011-11-29 12:43:08 +01:00
extern GType vips_foreign_load_vips_get_type( void );
extern GType vips_foreign_save_vips_get_type( void );
2011-12-14 23:51:14 +01:00
extern GType vips_foreign_load_raw_get_type( void );
2011-12-15 11:59:05 +01:00
extern GType vips_foreign_save_raw_get_type( void );
2011-12-21 13:08:29 +01:00
extern GType vips_foreign_save_raw_fd_get_type( void );
2015-02-16 14:31:22 +01:00
extern GType vips_foreign_load_magick_file_get_type( void );
extern GType vips_foreign_load_magick_buffer_get_type( 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_buffer_get_type( void );
extern GType vips_foreign_save_dz_file_get_type( void );
extern GType vips_foreign_save_dz_buffer_get_type( void );
2013-08-06 11:01:50 +02:00
extern GType vips_foreign_load_webp_file_get_type( void );
extern GType vips_foreign_load_webp_buffer_get_type( void );
extern GType vips_foreign_load_webp_source_get_type( void );
2013-08-06 17:18:30 +02:00
extern GType vips_foreign_save_webp_file_get_type( void );
extern GType vips_foreign_save_webp_buffer_get_type( void );
extern GType vips_foreign_save_webp_target_get_type( void );
2016-02-08 21:25:03 +01:00
extern GType vips_foreign_load_pdf_file_get_type( void );
extern GType vips_foreign_load_pdf_buffer_get_type( void );
extern GType vips_foreign_load_pdf_source_get_type( void );
extern GType vips_foreign_load_svg_file_get_type( void );
extern GType vips_foreign_load_svg_buffer_get_type( void );
extern GType vips_foreign_load_svg_source_get_type( void );
2019-01-28 23:16:56 +01:00
extern GType vips_foreign_load_heif_file_get_type( void );
2019-01-29 02:48:10 +01:00
extern GType vips_foreign_load_heif_buffer_get_type( void );
2020-03-15 12:45:56 +01:00
extern GType vips_foreign_load_heif_source_get_type( void );
2019-01-29 18:21:13 +01:00
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 );
2018-06-29 18:31:17 +02:00
extern GType vips_foreign_load_nifti_get_type( void );
extern GType vips_foreign_save_nifti_get_type( void );
extern GType vips_foreign_load_gif_file_get_type( void );
extern GType vips_foreign_load_gif_buffer_get_type( void );
2020-01-30 23:15:48 +01:00
extern GType vips_foreign_load_gif_source_get_type( void );
2011-12-15 11:59:05 +01:00
2020-02-21 17:04:29 +01:00
vips_foreign_load_csv_file_get_type();
2020-02-21 17:39:40 +01:00
vips_foreign_load_csv_source_get_type();
2020-02-21 18:57:28 +01:00
vips_foreign_save_csv_file_get_type();
vips_foreign_save_csv_target_get_type();
2020-02-22 16:02:12 +01:00
vips_foreign_load_matrix_file_get_type();
vips_foreign_load_matrix_source_get_type();
2020-02-22 18:55:04 +01:00
vips_foreign_save_matrix_file_get_type();
vips_foreign_save_matrix_target_get_type();
2013-10-25 13:02:02 +02:00
vips_foreign_print_matrix_get_type();
2011-12-15 11:59:05 +01:00
vips_foreign_load_raw_get_type();
vips_foreign_save_raw_get_type();
2011-12-21 13:08:29 +01:00
vips_foreign_save_raw_fd_get_type();
2011-12-15 11:59:05 +01:00
vips_foreign_load_vips_get_type();
vips_foreign_save_vips_get_type();
#ifdef HAVE_ANALYZE
vips_foreign_load_analyze_get_type();
#endif /*HAVE_ANALYZE*/
#ifdef HAVE_PPM
vips_foreign_load_ppm_file_get_type();
vips_foreign_save_ppm_file_get_type();
#endif /*HAVE_PPM*/
#ifdef HAVE_RADIANCE
vips_foreign_load_rad_file_get_type();
vips_foreign_load_rad_buffer_get_type();
vips_foreign_load_rad_source_get_type();
2016-05-23 16:37:28 +02:00
vips_foreign_save_rad_file_get_type();
vips_foreign_save_rad_buffer_get_type();
vips_foreign_save_rad_target_get_type();
#endif /*HAVE_RADIANCE*/
#if defined(HAVE_POPPLER)
2016-02-08 21:25:03 +01:00
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
vips_foreign_load_pdf_source_get_type();
2016-02-08 00:33:43 +01:00
#endif /*HAVE_POPPLER*/
#ifdef HAVE_PDFIUM
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
#endif /*HAVE_PDFIUM*/
#ifdef HAVE_RSVG
vips_foreign_load_svg_file_get_type();
vips_foreign_load_svg_buffer_get_type();
vips_foreign_load_svg_source_get_type();
#endif /*HAVE_RSVG*/
#ifdef HAVE_GIFLIB
vips_foreign_load_gif_file_get_type();
vips_foreign_load_gif_buffer_get_type();
2020-01-30 23:15:48 +01:00
vips_foreign_load_gif_source_get_type();
#endif /*HAVE_GIFLIB*/
#ifdef HAVE_GSF
vips_foreign_save_dz_file_get_type();
vips_foreign_save_dz_buffer_get_type();
#endif /*HAVE_GSF*/
2011-11-24 22:53:40 +01:00
2011-12-19 22:40:08 +01:00
#ifdef HAVE_PNG
vips_foreign_load_png_file_get_type();
vips_foreign_load_png_buffer_get_type();
vips_foreign_load_png_source_get_type();
2011-12-19 22:40:08 +01:00
vips_foreign_save_png_file_get_type();
vips_foreign_save_png_buffer_get_type();
vips_foreign_save_png_target_get_type();
2011-12-19 22:40:08 +01:00
#endif /*HAVE_PNG*/
2011-12-20 11:10:53 +01:00
#ifdef HAVE_MATIO
vips_foreign_load_mat_get_type();
#endif /*HAVE_MATIO*/
2011-11-24 22:53:40 +01:00
#ifdef HAVE_JPEG
2011-11-29 19:13:14 +01:00
vips_foreign_load_jpeg_file_get_type();
vips_foreign_load_jpeg_buffer_get_type();
vips_foreign_load_jpeg_source_get_type();
2011-11-29 19:13:14 +01:00
vips_foreign_save_jpeg_file_get_type();
vips_foreign_save_jpeg_buffer_get_type();
vips_foreign_save_jpeg_target_get_type();
2011-11-29 23:14:06 +01:00
vips_foreign_save_jpeg_mime_get_type();
2011-11-24 22:53:40 +01:00
#endif /*HAVE_JPEG*/
2011-12-03 11:59:25 +01:00
2013-08-06 11:01:50 +02:00
#ifdef HAVE_LIBWEBP
vips_foreign_load_webp_file_get_type();
vips_foreign_load_webp_buffer_get_type();
vips_foreign_load_webp_source_get_type();
2013-08-06 17:18:30 +02:00
vips_foreign_save_webp_file_get_type();
vips_foreign_save_webp_buffer_get_type();
vips_foreign_save_webp_target_get_type();
2013-08-06 11:01:50 +02:00
#endif /*HAVE_LIBWEBP*/
2011-12-03 11:59:25 +01:00
#ifdef HAVE_TIFF
vips_foreign_load_tiff_file_get_type();
vips_foreign_load_tiff_buffer_get_type();
vips_foreign_load_tiff_source_get_type();
vips_foreign_save_tiff_file_get_type();
vips_foreign_save_tiff_buffer_get_type();
2011-12-03 11:59:25 +01:00
#endif /*HAVE_TIFF*/
2011-12-11 23:01:39 +01:00
#ifdef HAVE_OPENSLIDE
vips_foreign_load_openslide_get_type();
#endif /*HAVE_OPENSLIDE*/
#ifdef ENABLE_MAGICKLOAD
#ifdef HAVE_MAGICK6
vips_foreign_load_magick_file_get_type();
vips_foreign_load_magick_buffer_get_type();
#endif /*HAVE_MAGICK6*/
#ifdef HAVE_MAGICK7
vips_foreign_load_magick7_file_get_type();
vips_foreign_load_magick7_buffer_get_type();
#endif /*HAVE_MAGICK7*/
#endif /*ENABLE_MAGICKLOAD*/
#ifdef ENABLE_MAGICKSAVE
vips_foreign_save_magick_file_get_type();
vips_foreign_save_magick_buffer_get_type();
#endif /*ENABLE_MAGICKSAVE*/
2016-07-08 18:56:30 +02:00
2011-12-13 18:50:55 +01:00
#ifdef HAVE_CFITSIO
vips_foreign_load_fits_get_type();
vips_foreign_save_fits_get_type();
#endif /*HAVE_CFITSIO*/
2011-12-13 11:20:22 +01:00
#ifdef HAVE_OPENEXR
vips_foreign_load_openexr_get_type();
#endif /*HAVE_OPENEXR*/
2018-06-29 18:31:17 +02:00
#ifdef HAVE_NIFTI
vips_foreign_load_nifti_get_type();
vips_foreign_save_nifti_get_type();
2018-06-29 18:31:17 +02:00
#endif /*HAVE_NIFTI*/
#ifdef HAVE_HEIF_DECODER
2019-01-28 23:16:56 +01:00
vips_foreign_load_heif_file_get_type();
2019-01-29 02:48:10 +01:00
vips_foreign_load_heif_buffer_get_type();
2020-03-15 12:45:56 +01:00
vips_foreign_load_heif_source_get_type();
#endif /*HAVE_HEIF_DECODER*/
#ifdef HAVE_HEIF_ENCODER
2019-01-29 18:21:13 +01:00
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 =
g_quark_from_static_string( "vips-foreign-load-operation" );
2011-11-24 22:53:40 +01:00
}