diff --git a/ChangeLog b/ChangeLog index f1abc4b5..a3ef67c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +25/5/08 fork for loadable image format branch +- image load/save in non-vips format code moved to own dir +- simple format searching added +- some cleanups for vips load +- im_open() simplified +- add im_format_flags +- only consider formats with a save method in im_format_for_name() +- oops, format sort order was reversed +- im_filename_suffix() includes "." in suffix +- merge back into trunk for 7.15.1 + 7/3/08 started 7.15.0 - MAGIC constants should be tagged as unsigned - write MAGIC correctly on sparc/powerpc machines (thanks Joe) diff --git a/TODO b/TODO index 27bbcf83..668b3844 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,37 @@ -- merge loadable format stuff, postpone new object parameter API to next - version +- is_a.c should be broken out into the respective loaders? that's how it + wouldbe for plugns + +- something in vips.c to list the available formats, like + + vips --list packages + + perhaps + + vips --list formats + +- add API to add operations and formats, can be used by plugins in module init + to register stuff + +- deprecate the current plugin init system + +- more cleanups to the handling of vips format images, esp. we have vips write + spread across many files atm + +- could remove a lot of crappy old API + +- it'd be nice to handle vips format images in the same im_format system, but + it's not clear if this is possible + +- we sometimes name types with a trailing _t, but only sometimes, argh + + should im_format become im_format_t? what's the current naming convention? + should be add _t variants for all types? + + + +- when we open with a mmap window and later do im_incheck(), do we remap the + whole file? + - try diff --git a/configure.in b/configure.in index 5db83d78..21d18d38 100644 --- a/configure.in +++ b/configure.in @@ -5,7 +5,7 @@ AM_CONFIG_HEADER(config.h) # user-visible library versioning IM_MAJOR_VERSION=7 IM_MINOR_VERSION=15 -IM_MICRO_VERSION=0 +IM_MICRO_VERSION=1 IM_VERSION=$IM_MAJOR_VERSION.$IM_MINOR_VERSION.$IM_MICRO_VERSION IM_VERSION_STRING=$IM_VERSION-`date` @@ -458,6 +458,7 @@ AC_OUTPUT([ libsrc/colour/Makefile libsrc/conversion/Makefile libsrc/convolution/Makefile + libsrc/format/Makefile libsrc/freq_filt/Makefile libsrc/histograms_lut/Makefile libsrc/inplace/Makefile @@ -495,10 +496,12 @@ AC_OUTPUT([ ]) AC_MSG_RESULT([ +* general build options native win32: $vips_os_win32 open files in binary mode: $vips_binary_open - evaluate with threads: $enable_threads + +* optional packages and modules use fftw3 for FFT: $with_fftw3 Magick package: $with_magickpackage file import with libMagick: $with_magick diff --git a/include/vips/dispatch.h b/include/vips/dispatch.h index 98971595..08fac6cf 100644 --- a/include/vips/dispatch.h +++ b/include/vips/dispatch.h @@ -36,6 +36,7 @@ extern "C" { #endif /*__cplusplus*/ +#include #include #include @@ -76,8 +77,9 @@ typedef enum { IM_TYPE_ARG = 0x2 /* Uses a str arg in construction */ } im_type_flags; -/* Initialise and destroy objects. The "str" argument to the init function - * will not be supplied if this is not an ARG type. +/* Initialise, destroy and write objects. The "str" argument to the + * init function will not be supplied if this is not an ARG type. The + * write function writes to the GString. */ typedef int (*im_init_obj_fn)( im_object *obj, char *str ); typedef int (*im_dest_obj_fn)( im_object obj ); @@ -89,7 +91,7 @@ typedef struct { int size; /* sizeof( im_object repres. ) */ im_type_flags flags; /* Flags */ im_init_obj_fn init; /* Operation functions */ - im_dest_obj_fn dest; + im_dest_obj_fn dest; /* Destroy object */ } im_type_desc; /* Success on an argument. This is called if the image processing function @@ -143,6 +145,44 @@ typedef struct { im_function **table; /* Array of function descriptors */ } im_package; +/* Image file properties. OR these together to get the result of + * im_format_flags_fn(). 0 is default. + */ +typedef enum { + IM_FORMAT_FLAG_NONE = 0,/* No flags set */ + IM_FORMAT_FLAG_PARTIAL = 1/* Lazy read OK (eg. tiled tiff) */ +} im_format_flags; + +/* Function protos for formats. + */ +typedef gboolean (*im_format_is_a_fn)( const char * ); +typedef int (*im_format_header_fn)( const char *, IMAGE * ); +typedef int (*im_format_load_fn)( const char *, IMAGE * ); +typedef int (*im_format_save_fn)( IMAGE *, const char * ); +typedef im_format_flags (*im_format_flags_fn)( const char * ); + +/* A VIPS image format. + */ +typedef struct { + const char *name; /* Format name, same as mime */ + const char *name_user; /* I18n'd name for users */ + int priority; /* Keep formats sorted by this, default 0 */ + const char **suffs; /* Allowed suffixes */ + im_format_is_a_fn is_a; /* Filename is in format */ + im_format_header_fn header;/* Load header only from filename */ + im_format_load_fn load; /* Load image from filename */ + im_format_save_fn save; /* Save image to filename */ + im_format_flags_fn flags;/* Get flags for filename */ +} im_format; + +/* A set of VIPS formats forming a format package. + */ +typedef struct { + char *name; /* Package name (eg "magick") */ + int nfuncs; /* Number of formats in package */ + im_format **table; /* Array of formats */ +} im_format_package; + /* Externs for dispatch. */ @@ -272,6 +312,12 @@ im_function *im_find_function( const char *name ); im_package *im_find_package( const char *name ); im_package *im_package_of_function( const char *name ); +/* Map over and find formats. + */ +void *im_map_formats( VSListMap2Fn fn, void *a, void *b ); +im_format *im_format_for_file( const char *filename ); +im_format *im_format_for_name( const char *filename ); + /* Allocate space for, and free im_object argument lists. */ int im_free_vargv( im_function *fn, im_object *vargv ); diff --git a/include/vips/internal.h b/include/vips/internal.h index b3229c82..d2cc40a5 100644 --- a/include/vips/internal.h +++ b/include/vips/internal.h @@ -61,11 +61,16 @@ void im__read_2byte( int msb_first, unsigned char *to, unsigned char **from ); void im__write_4byte( unsigned char **to, unsigned char *from ); void im__write_2byte( unsigned char **to, unsigned char *from ); +int im__ftruncate( int fd, gint64 pos ); +int im__seek( int fd, gint64 pos ); + +int im__open_image_file( const char * ); +void im__format_init( void ); +void im__type_init( void ); int im__read_header_bytes( IMAGE *im, unsigned char *from ); int im__write_header_bytes( IMAGE *im, unsigned char *to ); int im__has_extension_block( IMAGE *im ); void *im__read_extension_block( IMAGE *im, int *size ); -int im__readhist( IMAGE *image ); int im__write_extension_block( IMAGE *im, void *buf, int size ); int im__writehist( IMAGE *image ); int im__start_eval( IMAGE *im ); @@ -98,13 +103,10 @@ char *im__gslist_gvalue_get( const GSList *list ); void im__buffer_init( void ); int im__cast_and_call(); -int im__read_header( IMAGE *image ); int im__test_kill( IMAGE *im ); void *im__mmap( int fd, int writeable, size_t length, gint64 offset ); int im__munmap( void *start, size_t length ); int im__write( int, const void *, size_t ); -int im__open_image_file( const char *filename ); -gint64 im__image_pixel_length( IMAGE *im ); void im__change_suffix( const char *name, char *out, int mx, const char *new_suff, const char **olds, int nolds ); void im__print_all( void ); diff --git a/include/vips/proto.h b/include/vips/proto.h index fcaf40cf..6c57d8d9 100644 --- a/include/vips/proto.h +++ b/include/vips/proto.h @@ -95,8 +95,10 @@ const char *im_guess_prefix( const char *, const char * ); const char *im_guess_libdir( const char *, const char * ); IMAGE *im_init( const char * ); IMAGE *im_openout( const char * ); +IMAGE *im_open_vips( const char * ); int im_openin( IMAGE *image ); int im_openinrw( IMAGE *image ); +IMAGE *im_vips_open( const char * ); IMAGE *im_setbuf( const char * ); IMAGE *im_partial( const char * ); IMAGE *im_binfile( const char *, int, int, int, int ); @@ -148,7 +150,9 @@ int im_istiffpyramid( const char * ); int im_isjpeg( const char * ); int im_isvips( const char * ); int im_isexr( const char * ); +int im_isexrtiled( const char *name ); int im_isppm( const char * ); +int im_isppmmmap( const char *filename ); int im_ispng( const char * ); int im_ismagick( const char * ); int im_isanalyze( const char *filename ); @@ -509,6 +513,7 @@ int im_grid( IMAGE *in, IMAGE *out, int tile_height, int across, int down ); int im_msb ( IMAGE * in, IMAGE * out ); int im_msb_band ( IMAGE * in, IMAGE * out, int band ); int im_wrap( IMAGE *in, IMAGE *out, int x, int y ); +int im_vips2raw( IMAGE *in, int fd ); /* colour */ diff --git a/include/vips/util.h b/include/vips/util.h index ab18a8bb..f6c9bfa5 100644 --- a/include/vips/util.h +++ b/include/vips/util.h @@ -314,9 +314,14 @@ int im_local_array( IMAGE *im, void **out, int n, im_construct_fn cons, im_callback_fn dest, void *a, void *b, void *c ); gint64 im_file_length( int fd ); +int im__write( int fd, const void *buf, size_t count ); char *im__file_read( FILE *fp, const char *name, unsigned int *length_out ); char *im__file_read_name( const char *name, unsigned int *length_out ); +int im__file_write( void *data, size_t size, size_t nmemb, FILE *stream ); + +gboolean im_isnative( im_arch_type arch ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/include/vips/vips.h b/include/vips/vips.h index 8a415842..505f93a8 100644 --- a/include/vips/vips.h +++ b/include/vips/vips.h @@ -492,6 +492,7 @@ typedef struct { #include #include +/* #include */ #include #include #include diff --git a/libsrc/Makefile.am b/libsrc/Makefile.am index 1f068874..45f62199 100644 --- a/libsrc/Makefile.am +++ b/libsrc/Makefile.am @@ -17,6 +17,7 @@ SUBDIRS = \ conversion \ convolution \ $(C_COMPILE_DIR) \ + format \ freq_filt \ histograms_lut \ inplace \ @@ -42,6 +43,7 @@ libvips_la_LIBADD = \ conversion/libconversion.la \ convolution/libconvolution.la \ $(C_LIB) \ + format/libformat.la \ freq_filt/libfreq_filt.la \ histograms_lut/libhistograms_lut.la \ inplace/libinplace.la \ diff --git a/libsrc/conversion/Makefile.am b/libsrc/conversion/Makefile.am index 6c03baaf..ec6fe1cd 100644 --- a/libsrc/conversion/Makefile.am +++ b/libsrc/conversion/Makefile.am @@ -2,12 +2,9 @@ noinst_LTLIBRARIES = libconversion.la libconversion_la_SOURCES = \ im_bernd.c \ - im_vips2tiff.c \ - im_tiff2vips.c \ conver_dispatch.c \ dbh.h \ im_bandjoin.c \ - im_analyze2vips.c \ im_black.c \ im_c2amph.c \ im_c2rect.c \ @@ -16,26 +13,18 @@ libconversion_la_SOURCES = \ im_c2real.c \ im_clip.c \ im_copy.c \ - im_csv2vips.c \ - im_vips2csv.c \ im_extract.c \ - im_exr2vips.c \ im_falsecolour.c \ im_fliphor.c \ im_flipver.c \ im_gbandjoin.c \ im_insert.c \ - im_jpeg2vips.c \ im_lrjoin.c \ - im_magick2vips.c \ im_mask2vips.c \ im_msb.c \ - im_png2vips.c \ - im_ppm2vips.c \ im_recomb.c \ im_replicate.c \ im_grid.c \ - im_raw2vips.c \ im_ri2c.c \ im_rightshift_size.c \ im_rot180.c \ @@ -48,13 +37,9 @@ libconversion_la_SOURCES = \ im_system.c \ im_print.c \ im_tbjoin.c \ - im_tile_cache.c \ im_text.c \ im_thresh.c \ im_vips2mask.c \ - im_vips2jpeg.c \ - im_vips2ppm.c \ - im_vips2png.c \ im_wrap.c \ im_zoom.c diff --git a/libsrc/conversion/conver_dispatch.c b/libsrc/conversion/conver_dispatch.c index 8cb0f0a4..2847425c 100644 --- a/libsrc/conversion/conver_dispatch.c +++ b/libsrc/conversion/conver_dispatch.c @@ -1444,355 +1444,6 @@ static im_function zoom_desc = { zoom_args /* Arg list */ }; -static int -jpeg2vips_vec( im_object *argv ) -{ - char *in = argv[0]; - IMAGE *out = argv[1]; - - if( im_jpeg2vips( in, out ) ) - return( -1 ); - - return( 0 ); -} - -static im_arg_desc jpeg2vips_args[] = { - IM_INPUT_STRING( "in" ), - IM_OUTPUT_IMAGE( "out" ) -}; - -static im_function jpeg2vips_desc = { - "im_jpeg2vips", /* Name */ - "convert from jpeg", /* Description */ - 0, /* Flags */ - jpeg2vips_vec, /* Dispatch function */ - IM_NUMBER( jpeg2vips_args ), /* Size of arg list */ - jpeg2vips_args /* Arg list */ -}; - -static int -vips2jpeg_vec( im_object *argv ) -{ - IMAGE *in = argv[0]; - char *out = argv[1]; - - if( im_vips2jpeg( in, out ) ) - return( -1 ); - - return( 0 ); -} - -static im_arg_desc vips2jpeg_args[] = { - IM_INPUT_IMAGE( "in" ), - IM_INPUT_STRING( "out" ) -}; - -static im_function vips2jpeg_desc = { - "im_vips2jpeg", /* Name */ - "convert to jpeg", /* Description */ - 0, /* Flags */ - vips2jpeg_vec, /* Dispatch function */ - IM_NUMBER( vips2jpeg_args ), /* Size of arg list */ - vips2jpeg_args /* Arg list */ -}; - -static int -vips2mimejpeg_vec( im_object *argv ) -{ - IMAGE *in = argv[0]; - int qfac = *((int *) argv[1]); - - if( im_vips2mimejpeg( in, qfac ) ) - return( -1 ); - - return( 0 ); -} - -static im_arg_desc vips2mimejpeg_args[] = { - IM_INPUT_IMAGE( "in" ), - IM_INPUT_INT( "qfac" ) -}; - -static im_function vips2mimejpeg_desc = { - "im_vips2mimejpeg", /* Name */ - "convert to jpeg as mime type on stdout", /* Description */ - 0, /* Flags */ - vips2mimejpeg_vec, /* Dispatch function */ - IM_NUMBER( vips2mimejpeg_args ), /* Size of arg list */ - vips2mimejpeg_args /* Arg list */ -}; - -/* Args for vips2png. - */ -static im_arg_desc vips2png_args[] = { - IM_INPUT_IMAGE( "in" ), - IM_INPUT_STRING( "out" ) -}; - -/* Call im_vips2png via arg vector. - */ -static int -vips2png_vec( im_object *argv ) -{ - return( im_vips2png( argv[0], argv[1] ) ); -} - -/* Description of im_vips2png. - */ -static im_function vips2png_desc = { - "im_vips2png", /* Name */ - "convert VIPS image to PNG file", /* Description */ - 0, - vips2png_vec, /* Dispatch function */ - IM_NUMBER( vips2png_args ), /* Size of arg list */ - vips2png_args /* Arg list */ -}; - -/* Args for png2vips. - */ -static im_arg_desc png2vips_args[] = { - IM_INPUT_STRING( "in" ), - IM_OUTPUT_IMAGE( "out" ) -}; - -/* Call im_png2vips via arg vector. - */ -static int -png2vips_vec( im_object *argv ) -{ - return( im_png2vips( argv[0], argv[1] ) ); -} - -/* Description of im_png2vips. - */ -static im_function png2vips_desc = { - "im_png2vips", /* Name */ - "convert PNG file to VIPS image", /* Description */ - 0, - png2vips_vec, /* Dispatch function */ - IM_NUMBER( png2vips_args ), /* Size of arg list */ - png2vips_args /* Arg list */ -}; - -/* Args for exr2vips. - */ -static im_arg_desc exr2vips_args[] = { - IM_INPUT_STRING( "in" ), - IM_OUTPUT_IMAGE( "out" ) -}; - -/* Call im_exr2vips via arg vector. - */ -static int -exr2vips_vec( im_object *argv ) -{ - return( im_exr2vips( argv[0], argv[1] ) ); -} - -/* Description of im_exr2vips. - */ -static im_function exr2vips_desc = { - "im_exr2vips", /* Name */ - "convert an OpenEXR file to VIPS", /* Description */ - 0, - exr2vips_vec, /* Dispatch function */ - IM_NUMBER( exr2vips_args ), /* Size of arg list */ - exr2vips_args /* Arg list */ -}; - -/* Args for vips2tiff. - */ -static im_arg_desc vips2tiff_args[] = { - IM_INPUT_IMAGE( "in" ), - IM_INPUT_STRING( "out" ) -}; - -/* Call im_vips2tiff via arg vector. - */ -static int -vips2tiff_vec( im_object *argv ) -{ - return( im_vips2tiff( argv[0], argv[1] ) ); -} - -/* Description of im_vips2tiff. - */ -static im_function vips2tiff_desc = { - "im_vips2tiff", /* Name */ - "convert VIPS image to TIFF file", /* Description */ - 0, - vips2tiff_vec, /* Dispatch function */ - IM_NUMBER( vips2tiff_args ), /* Size of arg list */ - vips2tiff_args /* Arg list */ -}; - -/* Args for magick2vips. - */ -static im_arg_desc magick2vips_args[] = { - IM_INPUT_STRING( "in" ), - IM_OUTPUT_IMAGE( "out" ) -}; - -/* Call im_magick2vips via arg vector. - */ -static int -magick2vips_vec( im_object *argv ) -{ - return( im_magick2vips( argv[0], argv[1] ) ); -} - -/* Description of im_magick2vips. - */ -static im_function magick2vips_desc = { - "im_magick2vips", /* Name */ - "load file with libMagick", /* Description */ - 0, - magick2vips_vec, /* Dispatch function */ - IM_NUMBER( magick2vips_args ), /* Size of arg list */ - magick2vips_args /* Arg list */ -}; - -/* Args for tiff2vips. - */ -static im_arg_desc tiff2vips_args[] = { - IM_INPUT_STRING( "in" ), - IM_OUTPUT_IMAGE( "out" ) -}; - -/* Call im_tiff2vips via arg vector. - */ -static int -tiff2vips_vec( im_object *argv ) -{ - return( im_tiff2vips( argv[0], argv[1] ) ); -} - -/* Description of im_tiff2vips. - */ -static im_function tiff2vips_desc = { - "im_tiff2vips", /* Name */ - "convert TIFF file to VIPS image", /* Description */ - 0, - tiff2vips_vec, /* Dispatch function */ - IM_NUMBER( tiff2vips_args ), /* Size of arg list */ - tiff2vips_args /* Arg list */ -}; - -static int -analyze2vips_vec( im_object *argv ) -{ - const char *in = argv[0]; - IMAGE *out = argv[1]; - - return( im_analyze2vips( in, out ) ); -} - -static im_arg_desc analyze2vips_arg_types[] = { - IM_INPUT_STRING( "filename" ), - IM_OUTPUT_IMAGE( "im" ) -}; - -static im_function analyze2vips_desc = { - "im_analyze2vips", /* Name */ - "read a file in analyze format",/* Description */ - 0, /* Flags */ - analyze2vips_vec, /* Dispatch function */ - IM_NUMBER( analyze2vips_arg_types ),/* Size of arg list */ - analyze2vips_arg_types /* Arg list */ -}; - -static int -csv2vips_vec( im_object *argv ) -{ - const char *in = argv[0]; - IMAGE *out = argv[1]; - - return( im_csv2vips( in, out ) ); -} - -static im_arg_desc csv2vips_arg_types[] = { - IM_INPUT_STRING( "filename" ), - IM_OUTPUT_IMAGE( "im" ) -}; - -static im_function csv2vips_desc = { - "im_csv2vips", /* Name */ - "read a file in csv format",/* Description */ - 0, /* Flags */ - csv2vips_vec, /* Dispatch function */ - IM_NUMBER( csv2vips_arg_types ),/* Size of arg list */ - csv2vips_arg_types /* Arg list */ -}; - -static int -vips2csv_vec( im_object *argv ) -{ - IMAGE *in = argv[0]; - const char *filename = argv[1]; - - return( im_vips2csv( in, filename ) ); -} - -static im_arg_desc vips2csv_arg_types[] = { - IM_INPUT_IMAGE( "in" ), - IM_INPUT_STRING( "filename" ) -}; - -static im_function vips2csv_desc = { - "im_vips2csv", /* Name */ - "write an image in csv format", /* Description */ - 0, /* Flags */ - vips2csv_vec, /* Dispatch function */ - IM_NUMBER( vips2csv_arg_types ),/* Size of arg list */ - vips2csv_arg_types /* Arg list */ -}; - -static int -ppm2vips_vec( im_object *argv ) -{ - const char *in = argv[0]; - IMAGE *out = argv[1]; - - return( im_ppm2vips( in, out ) ); -} - -static im_arg_desc ppm2vips_arg_types[] = { - IM_INPUT_STRING( "filename" ), - IM_OUTPUT_IMAGE( "im" ) -}; - -static im_function ppm2vips_desc = { - "im_ppm2vips", /* Name */ - "read a file in pbm/pgm/ppm format", /* Description */ - 0, /* Flags */ - ppm2vips_vec, /* Dispatch function */ - IM_NUMBER( ppm2vips_arg_types ),/* Size of arg list */ - ppm2vips_arg_types /* Arg list */ -}; - -static int -vips2ppm_vec( im_object *argv ) -{ - IMAGE *im = argv[0]; - const char *filename = argv[1]; - - return( im_vips2ppm( im, filename ) ); -} - -static im_arg_desc vips2ppm_arg_types[] = { - IM_INPUT_IMAGE( "im" ), - IM_INPUT_STRING( "filename" ) -}; - -static im_function vips2ppm_desc = { - "im_vips2ppm", /* Name */ - "write a file in pbm/pgm/ppm format", /* Description */ - 0, /* Flags */ - vips2ppm_vec, /* Dispatch function */ - IM_NUMBER( vips2ppm_arg_types ),/* Size of arg list */ - vips2ppm_arg_types /* Arg list */ -}; - /* Call im_msb via arg vector. */ static int @@ -1934,7 +1585,6 @@ static im_function *conv_list[] = { ©_swap_desc, ©_set_desc, ©_set_meta_desc, - &csv2vips_desc, &extract_area_desc, &extract_areabands_desc, &extract_band_desc, @@ -1947,16 +1597,10 @@ static im_function *conv_list[] = { &grid_desc, &insert_desc, &insert_noexpand_desc, - &jpeg2vips_desc, &lrjoin_desc, - &magick2vips_desc, &mask2vips_desc, &msb_desc, &msb_band_desc, - &png2vips_desc, - &exr2vips_desc, - &ppm2vips_desc, - &analyze2vips_desc, &print_desc, &recomb_desc, &replicate_desc, @@ -1973,14 +1617,7 @@ static im_function *conv_list[] = { &tbjoin_desc, &text_desc, &thresh_desc, - &tiff2vips_desc, - &vips2csv_desc, - &vips2jpeg_desc, &vips2mask_desc, - &vips2mimejpeg_desc, - &vips2png_desc, - &vips2ppm_desc, - &vips2tiff_desc, &wrap_desc, &zoom_desc }; diff --git a/libsrc/conversion/dbh.h b/libsrc/conversion/dbh.h deleted file mode 100644 index 782cbf67..00000000 --- a/libsrc/conversion/dbh.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * (c) Copyright, 1986-1991 - * Biodynamics Research Unit - * Mayo Foundation - * - * dbh.h - * - * - * database sub-definitions - */ - -/* - * - * The previous-generation header for Analyze images. Although (c) Mayo - * Foundation, it has been in the public domain for many years. - * - * Analyze images have a 348 byte header stored in a file with a .hdr suffix, - * and a corresponding .img file containing just the pixel data. - * - */ - -struct header_key /* header_key */ - { /* off + size*/ - int sizeof_hdr; /* 0 + 4 */ - char data_type[10]; /* 4 + 10 */ - char db_name[18]; /* 14 + 18 */ - int extents; /* 32 + 4 */ - short int session_error; /* 36 + 2 */ - char regular; /* 38 + 1 */ - char hkey_un0; /* 39 + 1 */ - }; /* total=40 */ - -struct image_dimension /* image_dimension */ - { /* off + size*/ - short int dim[8]; /* 0 + 16 */ - char vox_units[4]; /* 16 + 4 */ - char cal_units[8]; /* 20 + 4 */ - short int unused1; /* 24 + 2 */ - short int datatype; /* 30 + 2 */ - short int bitpix; /* 32 + 2 */ - short int dim_un0; /* 34 + 2 */ - float pixdim[8]; /* 36 + 32 */ - - /* pixdim[] specifies the voxel dimensions: - pixdim[1] - voxel width - pixdim[2] - voxel height - pixdim[3] - interslice distance - ..etc - */ - float vox_offset; /* 68 + 4 */ - float funused1; /* 72 + 4 */ - float funused2; /* 76 + 4 */ - float funused3; /* 80 + 4 */ - float cal_max; /* 84 + 4 */ - float cal_min; /* 88 + 4 */ - int compressed; /* 92 + 4 */ - int verified; /* 96 + 4 */ - int glmax, glmin; /* 100 + 8 */ - }; - -struct data_history /* data_history */ - { /* off + size*/ - char descrip[80]; /* 0 + 80 */ - char aux_file[24]; /* 80 + 24 */ - char orient; /* 104 + 1 */ - char originator[10]; /* 105 + 10 */ - char generated[10]; /* 115 + 10 */ - char scannum[10]; /* 125 + 10 */ - char patient_id[10]; /* 135 + 10 */ - char exp_date[10]; /* 145 + 10 */ - char exp_time[10]; /* 155 + 10 */ - char hist_un0[3]; /* 165 + 3 */ - int views; /* 168 + 4 */ - int vols_added; /* 172 + 4 */ - int start_field; /* 176 + 4 */ - int field_skip; /* 180 + 4 */ - int omax,omin; /* 184 + 8 */ - int smax,smin; /* 192 + 8 */ - }; /* total=200 */ - -struct dsr /* dsr */ - { /* off + size*/ - struct header_key hk; /* 0 + 40 */ - struct image_dimension dime; /* 40 + 108 */ - struct data_history hist; /* 148 + 200 */ - }; /* total=348 */ - -/* Acceptable values for hdr.dime.datatype */ -#define DT_UNKNOWN 0 -#define DT_BINARY 1 -#define DT_UNSIGNED_CHAR 2 -#define DT_SIGNED_SHORT 4 -#define DT_SIGNED_INT 8 -#define DT_FLOAT 16 -#define DT_COMPLEX 32 -#define DT_DOUBLE 64 -#define DT_RGB 128 diff --git a/libsrc/conversion/im_analyze2vips.c b/libsrc/conversion/im_analyze2vips.c deleted file mode 100644 index d5f9eeb2..00000000 --- a/libsrc/conversion/im_analyze2vips.c +++ /dev/null @@ -1,583 +0,0 @@ -/* Read a Analyze file. Old-style header (so called 7.5 format). - * - * 3/8/05 - * - dbh.h header from Ralph Myers - * 22/8/05 - * - better byteswapper - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "dbh.h" - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* The things we can have in header fields. Can't use GType, since we want a - * static value we can use in a declaration. - */ -typedef enum { - BYTE, - SHORT, - INT, - FLOAT, - STRING -} Type; - -/* A field in the dsr header. - */ -typedef struct { - const char *name; /* Eg. "header_key.sizeof_hdr" */ - Type type; - glong offset; /* Offset in struct */ - int len; /* Sizeof ... useful for string types */ -} Field; - -static Field dsr_header[] = { - { "dsr-header_key.sizeof_hdr", INT, - G_STRUCT_OFFSET( struct dsr, hk.sizeof_hdr ), 4 }, - { "dsr-header_key.data_type", STRING, - G_STRUCT_OFFSET( struct dsr, hk.data_type ), 10 }, - { "dsr-header_key.db_name", STRING, - G_STRUCT_OFFSET( struct dsr, hk.db_name ), 18 }, - { "dsr-header_key.extents", INT, - G_STRUCT_OFFSET( struct dsr, hk.extents ), 4 }, - { "dsr-header_key.session_error", SHORT, - G_STRUCT_OFFSET( struct dsr, hk.session_error ), 2 }, - { "dsr-header_key.regular", BYTE, - G_STRUCT_OFFSET( struct dsr, hk.regular ), 1 }, - { "dsr-header_key.hkey_un0", BYTE, - G_STRUCT_OFFSET( struct dsr, hk.hkey_un0 ), 1 }, - - { "dsr-image_dimension.dim[0]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[0] ), 2 }, - { "dsr-image_dimension.dim[1]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[1] ), 2 }, - { "dsr-image_dimension.dim[2]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[2] ), 2 }, - { "dsr-image_dimension.dim[3]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[3] ), 2 }, - { "dsr-image_dimension.dim[4]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[4] ), 2 }, - { "dsr-image_dimension.dim[5]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[5] ), 2 }, - { "dsr-image_dimension.dim[6]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[6] ), 2 }, - { "dsr-image_dimension.dim[7]", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim[7] ), 2 }, - { "dsr-image_dimension.vox_units[0]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.vox_units[0] ), 1 }, - { "dsr-image_dimension.vox_units[1]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.vox_units[1] ), 1 }, - { "dsr-image_dimension.vox_units[2]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.vox_units[2] ), 1 }, - { "dsr-image_dimension.vox_units[3]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.vox_units[3] ), 1 }, - { "dsr-image_dimension.cal_units[0]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[0] ), 1 }, - { "dsr-image_dimension.cal_units[1]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[1] ), 1 }, - { "dsr-image_dimension.cal_units[2]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[2] ), 1 }, - { "dsr-image_dimension.cal_units[3]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[3] ), 1 }, - { "dsr-image_dimension.cal_units[4]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[4] ), 1 }, - { "dsr-image_dimension.cal_units[5]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[5] ), 1 }, - { "dsr-image_dimension.cal_units[6]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[6] ), 1 }, - { "dsr-image_dimension.cal_units[7]", BYTE, - G_STRUCT_OFFSET( struct dsr, dime.cal_units[7] ), 1 }, - { "dsr-image_dimension.data_type", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.datatype ), 2 }, - { "dsr-image_dimension.bitpix", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.bitpix ), 2 }, - { "dsr-image_dimension.dim_un0", SHORT, - G_STRUCT_OFFSET( struct dsr, dime.dim_un0 ), 2 }, - { "dsr-image_dimension.pixdim[0]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[0] ), 4 }, - { "dsr-image_dimension.pixdim[1]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[1] ), 4 }, - { "dsr-image_dimension.pixdim[2]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[2] ), 4 }, - { "dsr-image_dimension.pixdim[3]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[3] ), 4 }, - { "dsr-image_dimension.pixdim[4]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[4] ), 4 }, - { "dsr-image_dimension.pixdim[5]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[5] ), 4 }, - { "dsr-image_dimension.pixdim[6]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[6] ), 4 }, - { "dsr-image_dimension.pixdim[7]", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.pixdim[7] ), 4 }, - { "dsr-image_dimension.vox_offset", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.vox_offset ), 4 }, - { "dsr-image_dimension.cal_max", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.cal_max ), 4 }, - { "dsr-image_dimension.cal_min", FLOAT, - G_STRUCT_OFFSET( struct dsr, dime.cal_min ), 4 }, - { "dsr-image_dimension.compressed", INT, - G_STRUCT_OFFSET( struct dsr, dime.compressed ), 4 }, - { "dsr-image_dimension.verified", INT, - G_STRUCT_OFFSET( struct dsr, dime.verified ), 4 }, - { "dsr-image_dimension.glmax", INT, - G_STRUCT_OFFSET( struct dsr, dime.glmax ), 4 }, - { "dsr-image_dimension.glmin", INT, - G_STRUCT_OFFSET( struct dsr, dime.glmin ), 4 }, - - { "dsr-data_history.descrip", STRING, - G_STRUCT_OFFSET( struct dsr, hist.descrip ), 80 }, - { "dsr-data_history.aux_file", STRING, - G_STRUCT_OFFSET( struct dsr, hist.aux_file ), 24 }, - { "dsr-data_history.orient", BYTE, - G_STRUCT_OFFSET( struct dsr, hist.orient ), 1 }, - { "dsr-data_history.originator", STRING, - G_STRUCT_OFFSET( struct dsr, hist.originator ), 10 }, - { "dsr-data_history.generated", STRING, - G_STRUCT_OFFSET( struct dsr, hist.generated ), 10 }, - { "dsr-data_history.scannum", STRING, - G_STRUCT_OFFSET( struct dsr, hist.scannum ), 10 }, - { "dsr-data_history.patient_id", STRING, - G_STRUCT_OFFSET( struct dsr, hist.patient_id ), 10 }, - { "dsr-data_history.exp_date", STRING, - G_STRUCT_OFFSET( struct dsr, hist.exp_date ), 10 }, - { "dsr-data_history.exp_time", STRING, - G_STRUCT_OFFSET( struct dsr, hist.exp_time ), 10 }, - { "dsr-data_history.hist_un0", STRING, - G_STRUCT_OFFSET( struct dsr, hist.hist_un0 ), 3 }, - { "dsr-data_history.views", INT, - G_STRUCT_OFFSET( struct dsr, hist.views ), 4 }, - { "dsr-data_history.vols_added", INT, - G_STRUCT_OFFSET( struct dsr, hist.vols_added ), 4 }, - { "dsr-data_history.start_field", INT, - G_STRUCT_OFFSET( struct dsr, hist.start_field ), 4 }, - { "dsr-data_history.field_skip", INT, - G_STRUCT_OFFSET( struct dsr, hist.field_skip ), 4 }, - { "dsr-data_history.omax", INT, - G_STRUCT_OFFSET( struct dsr, hist.omax ), 4 }, - { "dsr-data_history.omin", INT, - G_STRUCT_OFFSET( struct dsr, hist.omin ), 4 }, - { "dsr-data_history.smax", INT, - G_STRUCT_OFFSET( struct dsr, hist.smax ), 4 }, - { "dsr-data_history.smin", INT, - G_STRUCT_OFFSET( struct dsr, hist.smin ), 4 } -}; - -/* Given a filename, generate the names for the header and the image data. - * - * Eg. - * "fred" -> "fred.hdr", "fred.img" - * "fred.img" -> "fred.hdr", "fred.img" - */ -static void -generate_filenames( const char *path, char *header, char *image ) -{ - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - - const char *olds[] = { ".img", ".hdr" }; - - /* Take off any modifiers. - */ - im_filename_split( path, name, mode ); - - im__change_suffix( name, header, FILENAME_MAX, ".hdr", olds, 2 ); - im__change_suffix( name, image, FILENAME_MAX, ".img", olds, 2 ); -} - -/* str is a str which may not be NULL-terminated. Return a pointer to a static - * buffer with a NULL-terminated version so we can safely printf() the string. - * Also, make sure the string is plain ascii. - */ -static char * -getstr( int mx, const char *str ) -{ - static char buf[256]; - int i; - - assert( mx < 256 ); - - strncpy( buf, str, mx ); - buf[mx]= '\0'; - - /* How annoying, patient_id has some funny ctrlchars in that mess up - * xml encode later. - */ - for( i = 0; i < mx && buf[i]; i++ ) - if( !isascii( buf[i] ) || buf[i] < 32 ) - buf[i] = '@'; - - return( buf ); -} - -#ifdef DEBUG -static void -print_dsr( struct dsr *d ) -{ - int i; - - for( i = 0; i < IM_NUMBER( dsr_header ); i++ ) { - printf( "%s = ", dsr_header[i].name ); - - switch( dsr_header[i].type ) { - case BYTE: - printf( "%d\n", G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ); - break; - - case SHORT: - printf( "%d\n", G_STRUCT_MEMBER( short, d, - dsr_header[i].offset ) ); - break; - - case INT: - printf( "%d\n", G_STRUCT_MEMBER( int, d, - dsr_header[i].offset ) ); - break; - - case FLOAT: - printf( "%g\n", G_STRUCT_MEMBER( float, d, - dsr_header[i].offset ) ); - break; - - case STRING: - printf( "\"%s\"\n", getstr( dsr_header[i].len, - &G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ) ); - break; - - default: - assert( 0 ); - } - } -} -#endif /*DEBUG*/ - -static struct dsr * -read_header( const char *header ) -{ - struct dsr *d; - unsigned int len; - - if( !(d = (struct dsr *) im__file_read_name( header, &len )) ) - return( NULL ); - if( len != sizeof( struct dsr ) ) { - im_error( "im_analyze2vips", - _( "header file size incorrect" ) ); - im_free( d ); - return( NULL ); - } - - /* Ouch! Should check at configure time I guess. - */ - assert( sizeof( struct dsr ) == 348 ); - - /* dsr headers are always SPARC byte order (MSB first). Do we need to - * swap? - */ - if( !im_amiMSBfirst() ) { - int i; - - for( i = 0; i < IM_NUMBER( dsr_header ); i++ ) { - unsigned char *p; - - - switch( dsr_header[i].type ) { - case SHORT: - p = &G_STRUCT_MEMBER( unsigned char, d, - dsr_header[i].offset ); - im__read_2byte( 1, p, &p ); - break; - - case INT: - case FLOAT: - p = &G_STRUCT_MEMBER( unsigned char, d, - dsr_header[i].offset ); - im__read_4byte( 1, p, &p ); - break; - - case BYTE: - case STRING: - break; - - default: - assert( 0 ); - } - } - } - - if( len != d->hk.sizeof_hdr ) { - im_error( "im_analyze2vips", - _( "header file size incorrect" ) ); - im_free( d ); - return( NULL ); - } - - return( d ); -} - -/* Try to get VIPS header properties from a dsr. - */ -static int -get_vips_properties( struct dsr *d, - int *width, int *height, int *bands, int *fmt ) -{ - int i; - - if( d->dime.dim[0] < 2 || d->dime.dim[0] > 7 ) { - im_error( "im_analyze2vips", - _( "%d-dimensional images not supported" ), - d->dime.dim[0] ); - return( -1 ); - } - - /* Size of base 2d images. - */ - *width = d->dime.dim[1]; - *height = d->dime.dim[2]; - - for( i = 3; i <= d->dime.dim[0]; i++ ) - *height *= d->dime.dim[i]; - - /* Check it's a datatype we can handle. - */ - switch( d->dime.datatype ) { - case DT_UNSIGNED_CHAR: - *bands = 1; - *fmt = IM_BANDFMT_UCHAR; - break; - - case DT_SIGNED_SHORT: - *bands = 1; - *fmt = IM_BANDFMT_SHORT; - break; - - case DT_SIGNED_INT: - *bands = 1; - *fmt = IM_BANDFMT_INT; - break; - - case DT_FLOAT: - *bands = 1; - *fmt = IM_BANDFMT_FLOAT; - break; - - case DT_COMPLEX: - *bands = 1; - *fmt = IM_BANDFMT_COMPLEX; - break; - - case DT_DOUBLE: - *bands = 1; - *fmt = IM_BANDFMT_DOUBLE; - break; - - case DT_RGB: - *bands = 3; - *fmt = IM_BANDFMT_UCHAR; - break; - - default: - im_error( "im_analyze2vips", - _( "datatype %d not supported" ), d->dime.datatype ); - return( -1 ); - } - -#ifdef DEBUG - printf( "get_vips_properties: width = %d\n", *width ); - printf( "get_vips_properties: height = %d\n", *height ); - printf( "get_vips_properties: bands = %d\n", *bands ); - printf( "get_vips_properties: fmt = %d\n", *fmt ); -#endif /*DEBUG*/ - - return( 0 ); -} - -static void -attach_meta( IMAGE *out, struct dsr *d ) -{ - int i; - - im_meta_set_blob( out, "dsr", - (im_callback_fn) im_free, d, d->hk.sizeof_hdr ); - - for( i = 0; i < IM_NUMBER( dsr_header ); i++ ) { - switch( dsr_header[i].type ) { - case BYTE: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ); - break; - - case SHORT: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( short, d, - dsr_header[i].offset ) ); - break; - - case INT: - im_meta_set_int( out, dsr_header[i].name, - G_STRUCT_MEMBER( int, d, - dsr_header[i].offset ) ); - break; - - case FLOAT: - im_meta_set_double( out, dsr_header[i].name, - G_STRUCT_MEMBER( float, d, - dsr_header[i].offset ) ); - break; - - case STRING: - im_meta_set_string( out, dsr_header[i].name, - getstr( dsr_header[i].len, - &G_STRUCT_MEMBER( char, d, - dsr_header[i].offset ) ) ); - break; - - default: - assert( 0 ); - } - } -} - -int -im_isanalyze( const char *filename ) -{ - char header[FILENAME_MAX]; - char image[FILENAME_MAX]; - struct dsr *d; - int width, height; - int bands; - int fmt; - - generate_filenames( filename, header, image ); - if( !(d = read_header( header )) ) - return( 0 ); - -#ifdef DEBUG - print_dsr( d ); -#endif /*DEBUG*/ - - if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { - im_free( d ); - return( 0 ); - } - im_free( d ); - - return( 1 ); -} - -int -im_analyze2vips_header( const char *filename, IMAGE *out ) -{ - char header[FILENAME_MAX]; - char image[FILENAME_MAX]; - struct dsr *d; - int width, height; - int bands; - int fmt; - - generate_filenames( filename, header, image ); - if( !(d = read_header( header )) ) - return( -1 ); - -#ifdef DEBUG - print_dsr( d ); -#endif /*DEBUG*/ - - if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { - im_free( d ); - return( -1 ); - } - - im_initdesc( out, width, height, bands, im_bits_of_fmt( fmt ), fmt, - IM_CODING_NONE, - bands == 1 ? IM_TYPE_B_W : IM_TYPE_sRGB, - 1.0, 1.0, - 0, 0 ); - - attach_meta( out, d ); - - return( 0 ); -} - -int -im_analyze2vips( const char *filename, IMAGE *out ) -{ - char header[FILENAME_MAX]; - char image[FILENAME_MAX]; - struct dsr *d; - IMAGE *t[2]; - int width, height; - int bands; - int fmt; - im_arch_type arch = im_amiMSBfirst() ? - IM_ARCH_NATIVE : IM_ARCH_BYTE_SWAPPED; - - generate_filenames( filename, header, image ); - if( !(d = read_header( header )) ) - return( -1 ); - -#ifdef DEBUG - print_dsr( d ); -#endif /*DEBUG*/ - - if( get_vips_properties( d, &width, &height, &bands, &fmt ) || - im_open_local_array( out, t, 2, "im_analyze2vips", "p" ) || - im_raw2vips( image, t[0], width, height, - bands * im_bits_of_fmt( fmt ) / 8, 0 ) || - im_copy_morph( t[0], t[1], bands, fmt, IM_CODING_NONE ) || - im_copy_from( t[1], out, arch ) ) { - im_free( d ); - return( -1 ); - } - - attach_meta( out, d ); - - return( 0 ); -} - diff --git a/libsrc/conversion/im_csv2vips.c b/libsrc/conversion/im_csv2vips.c deleted file mode 100644 index 8f07076e..00000000 --- a/libsrc/conversion/im_csv2vips.c +++ /dev/null @@ -1,316 +0,0 @@ -/* Read a csv file. - * - * 19/12/05 JC - * - hacked from ppm reader - * 11/9/06 - * - now distingushes whitespace and separators, so we can have blank - * fields - * 20/9/06 - * - oop, unquoted trailing columns could get missed - * 17/5/07 - * - added im_csv2vips_header() - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -static int -skip_line( FILE *fp ) -{ - int ch; - - while( (ch = fgetc( fp )) != '\n' && ch != EOF ) - ; - - return( ch ); -} - -static int -skip_white( FILE *fp, const char whitemap[256] ) -{ - int ch; - - do { - ch = fgetc( fp ); - } while (ch != EOF && ch != '\n' && whitemap[ch] ); - - ungetc( ch, fp ); - - return( ch ); -} - -static int -skip_to_sep( FILE *fp, const char sepmap[256] ) -{ - int ch; - - do { - ch = fgetc( fp ); - } while (ch != EOF && ch != '\n' && !sepmap[ch] ); - - ungetc( ch, fp ); - - return( ch ); -} - -/* Read a single item. Syntax is: - * - * item : whitespace* double? whitespace* [EOF|EOL|separator] - * - * Return the char that caused failure on fail (EOF or \n). - */ -static int -read_double( FILE *fp, const char whitemap[256], const char sepmap[256], - int lineno, int colno, double *out ) -{ - int ch; - - /* The fscanf() may change this ... but all other cases need a zero. - */ - *out = 0; - - ch = skip_white( fp, whitemap ); - if( ch == EOF || ch == '\n' ) - return( ch ); - - if( !sepmap[ch] && fscanf( fp, "%lf", out ) != 1 ) { - /* Only a warning, since (for example) exported spreadsheets - * will often have text or date fields. - */ - im_warn( "im_csv2vips", - _( "error parsing number, line %d, column %d" ), - lineno, colno ); - - /* Step over the bad data to the next separator. - */ - ch = skip_to_sep( fp, sepmap ); - } - - /* Don't need to check result, we have read a field successfully. - */ - ch = skip_white( fp, whitemap ); - - /* If it's a separator, we have to step over it. - */ - if( ch != EOF && sepmap[ch] ) - (void) fgetc( fp ); - - return( 0 ); -} - -static int -read_csv( FILE *fp, IMAGE *out, - int start_skip, - const char *whitespace, const char *separator, - int lines ) -{ - int i; - char whitemap[256]; - char sepmap[256]; - const char *p; - fpos_t pos; - int columns; - int ch; - double d; - double *buf; - int y; - - /* Make our char maps. - */ - for( i = 0; i < 256; i++ ) { - whitemap[i] = 0; - sepmap[i] = 0; - } - for( p = whitespace; *p; p++ ) - whitemap[(int) *p] = 1; - for( p = separator; *p; p++ ) - sepmap[(int) *p] = 1; - - /* Skip first few lines. - */ - for( i = 0; i < start_skip; i++ ) - if( skip_line( fp ) == EOF ) { - im_error( "im_csv2vips", - _( "end of file while skipping start" ) ); - return( -1 ); - } - - /* Parse the first line to get number of columns. Only bother checking - * fgetpos() the first time we use it: assume it's working after this. - */ - if( fgetpos( fp, &pos ) ) { - im_error_system( errno, "im_csv2vips", _( "unable to seek" ) ); - return( -1 ); - } - for( columns = 0; (ch = read_double( fp, whitemap, sepmap, - start_skip + 1, columns + 1, &d )) == 0; columns++ ) - ; - fsetpos( fp, &pos ); - - if( columns == 0 ) { - im_error( "im_csv2vips", _( "empty line" ) ); - return( -1 ); - } - if( ch == -2 ) - /* Failed to parse a number. - */ - return( -1 ); - - /* If lines is -1, we have to parse the whole file to get the - * number of lines out. - */ - if( lines == -1 ) { - fgetpos( fp, &pos ); - for( lines = 0; skip_line( fp ) != EOF; lines++ ) - ; - fsetpos( fp, &pos ); - } - - im_initdesc( out, columns, lines, 1, - IM_BBITS_DOUBLE, IM_BANDFMT_DOUBLE, - IM_CODING_NONE, IM_TYPE_B_W, 1.0, 1.0, 0, 0 ); - - if( im_outcheck( out ) || im_setupout( out ) || - !(buf = IM_ARRAY( out, IM_IMAGE_N_ELEMENTS( out ), double )) ) - return( -1 ); - - for( y = 0; y < lines; y++ ) { - int x; - - for( x = 0; x < columns; x++ ) { - ch = read_double( fp, whitemap, sepmap, - y + start_skip + 1, x + 1, &d ); - if( ch == EOF ) { - im_error( "im_csv2vips", - _( "unexpected end of file" ) ); - return( -1 ); - } - else if( ch == '\n' ) { - im_error( "im_csv2vips", - _( "unexpected end of line" ) ); - return( -1 ); - } - else if( ch ) - /* Parse error. - */ - return( -1 ); - - buf[x] = d; - } - - if( im_writeline( y, out, (PEL *) buf ) ) - return( -1 ); - - /* Skip over the '\n' to the next line. - */ - skip_line( fp ); - } - - return( 0 ); -} - -int -im_csv2vips( const char *filename, IMAGE *out ) -{ - /* Read options. - */ - int start_skip = 0; - char *whitespace = " \""; - char *separator = ";,\t"; - int lines = -1; - - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char *p, *q, *r; - FILE *fp; - - /* Parse mode string. - */ - im_filename_split( filename, name, mode ); - p = &mode[0]; - while( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "ski", q ) && (r = im_getsuboption( q )) ) - start_skip = atoi( r ); - else if( im_isprefix( "whi", q ) && (r = im_getsuboption( q )) ) - whitespace = r; - else if( im_isprefix( "sep", q ) && (r = im_getsuboption( q )) ) - separator = r; - else if( im_isprefix( "lin", q ) && (r = im_getsuboption( q )) ) - lines = atoi( r ); - } - - if( !(fp = fopen( name, "r" )) ) { - im_error( "im_csv2vips", - _( "unable to open \"%s\"" ), name ); - return( -1 ); - } - - if( read_csv( fp, out, start_skip, whitespace, separator, lines ) ) { - fclose( fp ); - return( -1 ); - } - fclose( fp ); - - return( 0 ); -} - -/* We can't just read the header of a CSV. Instead, we read to a temp image, - * then copy just the header to the output. - */ -int -im_csv2vips_header( const char *filename, IMAGE *out ) -{ - IMAGE *t; - - if( !(t = im_open( "im_csv2vips_header", "p" )) ) - return( -1 ); - if( im_csv2vips( filename, t ) || - im_cp_desc( out, t ) ) { - im_close( t ); - return( -1 ); - } - im_close( t ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_exr2vips.c b/libsrc/conversion/im_exr2vips.c deleted file mode 100644 index c5e58686..00000000 --- a/libsrc/conversion/im_exr2vips.c +++ /dev/null @@ -1,427 +0,0 @@ -/* Convert OpenEXR to VIPS - * - * 1/5/06 - * - from im_png2vips.c - * 17/5/06 - * - oops, buffer calcs were wrong - * 19/5/06 - * - added tiled read, with a separate cache - * - removed *255 we had before, better to do something clever with - * chromaticities - - - colour management - - attributes - - more of OpenEXR's pixel formats - - more than just RGBA channels - - the openexr C API is very limited ... it seems RGBA half pixels is - all you can do - - openexr lets you have different formats in different channels :-( - - there's no API to read the "chromaticities" attribute :-( - - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_OPENEXR - -#include - -int -im_exr2vips( const char *name, IMAGE *out ) -{ - im_error( "im_exr2vips", _( "OpenEXR support disabled" ) ); - return( -1 ); -} - -int -im_exr2vips_header( const char *name, IMAGE *out ) -{ - im_error( "im_exr2vips_header", _( "OpenEXR support disabled" ) ); - return( -1 ); -} - -#else /*HAVE_OPENEXR*/ - -#include -#include -#include -#include - -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* What we track during a OpenEXR read. - */ -typedef struct { - char *name; - IMAGE *out; - - ImfTiledInputFile *tiles; - ImfInputFile *lines; - const ImfHeader *header; - Rect window; - int tile_width; - int tile_height; - - /* Need to single-thread calls to ReadTile. - */ - GMutex *lock; -} Read; - -static void -get_imf_error( void ) -{ - im_error( "im_exr2vips", _( "EXR error: %s" ), ImfErrorMessage() ); -} - -static void -read_destroy( Read *read ) -{ - IM_FREE( read->name ); - - IM_FREEF( ImfCloseTiledInputFile, read->tiles ); - IM_FREEF( ImfCloseInputFile, read->lines ); - - IM_FREEF( g_mutex_free, read->lock ); - - im_free( read ); -} - -static Read * -read_new( const char *name, IMAGE *out ) -{ - Read *read; - int xmin, ymin; - int xmax, ymax; - - if( !(read = IM_NEW( NULL, Read )) ) - return( NULL ); - - read->name = im_strdup( NULL, name ); - read->out = out; - read->tiles = NULL; - read->lines = NULL; - read->lock = NULL; - - if( im_add_close_callback( out, - (im_callback_fn) read_destroy, read, NULL ) ) { - read_destroy( read ); - return( NULL ); - } - - /* Try to open tiled first ... if that fails, fall back to scanlines. - - FIXME ... seems a bit ugly, but how else can you spot a tiled - EXR image? - - */ - if( !(read->tiles = ImfOpenTiledInputFile( read->name )) ) { - if( !(read->lines = ImfOpenInputFile( read->name )) ) { - get_imf_error(); - return( NULL ); - } - } - -#ifdef DEBUG - if( read->tiles ) - printf( "im_exr2vips: opening in tiles mode\n" ); - else - printf( "im_exr2vips: opening in scanline mode\n" ); -#endif /*DEBUG*/ - - if( read->tiles ) { - read->header = ImfTiledInputHeader( read->tiles ); - read->lock = g_mutex_new(); - read->tile_width = ImfTiledInputTileXSize( read->tiles ); - read->tile_height = ImfTiledInputTileYSize( read->tiles ); - } - else - read->header = ImfInputHeader( read->lines ); - - ImfHeaderDataWindow( read->header, &xmin, &ymin, &xmax, &ymax ); - read->window.left = xmin; - read->window.top = ymin; - read->window.width = xmax - xmin + 1; - read->window.height = ymax - ymin + 1; - - return( read ); -} - -/* Read a OpenEXR file (header) into a VIPS (header). - */ -static int -exr2vips_header( Read *read, IMAGE *out ) -{ - /* - - FIXME ... not really sRGB. I think EXR is actually linear (no - gamma). We ought to read the chromaticities from the header, put - through a 3x3 matrix and output as XYZ - - */ - im_initdesc( out, - read->window.width, read->window.height, 4, - IM_BBITS_FLOAT, IM_BANDFMT_FLOAT, - IM_CODING_NONE, IM_TYPE_sRGB, 1.0, 1.0, 0, 0 ); - - return( 0 ); -} - -/* Read a OpenEXR file header into a VIPS header. - */ -int -im_exr2vips_header( const char *name, IMAGE *out ) -{ - Read *read; - - if( !(read = read_new( name, out )) || - exr2vips_header( read, out ) ) - return( -1 ); - - return( 0 ); -} - -static int -fill_region( REGION *out, void *seq, void *a, void *b ) -{ - ImfRgba *imf_buffer = (ImfRgba *) seq; - Read *read = (Read *) a; - Rect *r = &out->valid; - - const int tw = read->tile_width; - const int th = read->tile_height; - - /* Find top left of tiles we need. - */ - const int xs = (r->left / tw) * tw; - const int ys = (r->top / th) * th; - - int x, y, z; - Rect image; - - /* Area of image. - */ - image.left = 0; - image.top = 0; - image.width = read->out->Xsize; - image.height = read->out->Ysize; - - for( y = ys; y < IM_RECT_BOTTOM( r ); y += th ) - for( x = xs; x < IM_RECT_RIGHT( r ); x += tw ) { - Rect tile; - Rect hit; - int result; - - if( !ImfTiledInputSetFrameBuffer( read->tiles, - imf_buffer - - (read->window.left + x) - - (read->window.top + y) * tw, - 1, tw ) ) { - get_imf_error(); - return( -1 ); - } - -#ifdef DEBUG - printf( "im_exr2vips: requesting tile %d x %d\n", - x / tw, y / th ); -#endif /*DEBUG*/ - - g_mutex_lock( read->lock ); - result = ImfTiledInputReadTile( read->tiles, - x / tw, y / th, 0, 0 ); - g_mutex_unlock( read->lock ); - - if( !result ) { - get_imf_error(); - return( -1 ); - } - - /* The tile in the file, in VIPS coordinates. - */ - tile.left = x; - tile.top = y; - tile.width = tw; - tile.height = th; - im_rect_intersectrect( &tile, &image, &tile ); - - /* The part of this tile that hits the region. - */ - im_rect_intersectrect( &tile, r, &hit ); - - /* Convert to float and write to the region. - */ - for( z = 0; z < hit.height; z++ ) { - ImfRgba *p = imf_buffer + - (hit.left - tile.left) + - (hit.top - tile.top + z) * tw; - float *q = (float *) IM_REGION_ADDR( out, - hit.left, hit.top + z ); - - ImfHalfToFloatArray( 4 * hit.width, - (ImfHalf *) p, q ); - } - } - - return( 0 ); -} - -/* Allocate a tile buffer. - */ -static void * -seq_start( IMAGE *out, void *a, void *b ) -{ - Read *read = (Read *) a; - ImfRgba *imf_buffer; - - if( !(imf_buffer = IM_ARRAY( out, - read->tile_width * read->tile_height, ImfRgba )) ) - return( NULL ); - - return( imf_buffer ); -} - -/* Read tilewise. - */ -static int -exr2vips_tiles( Read *read, IMAGE *out ) -{ - if( exr2vips_header( read, out ) || - im_poutcheck( out ) || - im_demand_hint( out, IM_SMALLTILE, NULL ) || - im_generate( out, seq_start, fill_region, NULL, read, NULL ) ) - return( -1 ); - - return( 0 ); -} - -/* Read scanlinewise. - */ -static int -exr2vips_lines( Read *read, IMAGE *out ) -{ - const int left = read->window.left; - const int top = read->window.top; - const int width = read->window.width; - const int height = read->window.height; - - ImfRgba *imf_buffer; - float *vips_buffer; - int y; - - if( !(imf_buffer = IM_ARRAY( out, width, ImfRgba )) || - !(vips_buffer = IM_ARRAY( out, 4 * width, float )) || - exr2vips_header( read, out ) || - im_outcheck( out ) || - im_setupout( out ) ) - return( -1 ); - - for( y = 0; y < height; y++ ) { - if( !ImfInputSetFrameBuffer( read->lines, - imf_buffer - left - (top + y) * width, - 1, width ) ) { - get_imf_error(); - return( -1 ); - } - if( !ImfInputReadPixels( read->lines, top + y, top + y ) ) { - get_imf_error(); - return( -1 ); - } - - ImfHalfToFloatArray( 4 * width, - (ImfHalf *) imf_buffer, vips_buffer ); - - if( im_writeline( y, out, (PEL *) vips_buffer ) ) - return( -1 ); - } - - return( 0 ); -} - -static int -exr2vips( Read *read ) -{ - if( read->tiles ) { - IMAGE *raw; - - /* Tile cache: keep enough for two complete rows of tiles. - * This lets us do (smallish) area ops, like im_conv(), while - * still only hitting each OpenEXR tile once. - */ - if( !(raw = im_open_local( read->out, "cache", "p" )) ) - return( -1 ); - if( exr2vips_tiles( read, raw ) ) - return( -1 ); - if( im_tile_cache( raw, read->out, - read->tile_width, read->tile_height, - 2 * (1 + raw->Xsize / read->tile_width) ) ) - return( -1 ); - } - else { - if( exr2vips_lines( read, read->out ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Read a OpenEXR file into a VIPS image. - */ -int -im_exr2vips( const char *name, IMAGE *out ) -{ - Read *read; - -#ifdef DEBUG - printf( "im_exr2vips: reading \"%s\"\n", name ); -#endif /*DEBUG*/ - - if( !(read = read_new( name, out )) || - exr2vips( read ) ) - return( -1 ); - - return( 0 ); -} - -#endif /*HAVE_OPENEXR*/ diff --git a/libsrc/conversion/im_jpeg2vips.c b/libsrc/conversion/im_jpeg2vips.c deleted file mode 100644 index a557df84..00000000 --- a/libsrc/conversion/im_jpeg2vips.c +++ /dev/null @@ -1,714 +0,0 @@ -/* Convert 1 or 3-band 8-bit VIPS images to/from JPEG. - * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 12/11/04 - * - better demand size choice for eval - * 30/6/05 JC - * - update im_error()/im_warn() - * - now loads and saves exif data - * 30/7/05 - * - now loads ICC profiles - * - now saves ICC profiles from the VIPS header - * 24/8/05 - * - jpeg load sets vips xres/yres from exif, if possible - * - jpeg save sets exif xres/yres from vips, if possible - * 29/8/05 - * - cut from old vips_jpeg.c - * 13/10/06 - * - add -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_JPEG - -#include - -int -im_jpeg2vips_header( const char *name, IMAGE *out ) -{ - im_error( "im_jpeg2vips_header", _( "JPEG support disabled" ) ); - - return( -1 ); -} - -int -im_jpeg2vips( const char *name, IMAGE *out ) -{ - im_error( "im_jpeg2vips", _( "JPEG support disabled" ) ); - - return( -1 ); -} - -#else /*HAVE_JPEG*/ - -#include -#include -#include -#include -#include - -#ifdef HAVE_EXIF -#ifdef UNTAGGED_EXIF -#include -#include -#include -#include -#else /*!UNTAGGED_EXIF*/ -#include -#include -#include -#include -#endif /*UNTAGGED_EXIF*/ -#endif /*HAVE_EXIF*/ - -#include -#include - -/* jpeglib includes jconfig.h, which can define HAVE_STDLIB_H ... which we - * also define. Make sure it's turned off. - */ -#ifdef HAVE_STDLIB_H -#undef HAVE_STDLIB_H -#endif /*HAVE_STDLIB_H*/ - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Define a new error handler for when we bomb out. - */ -typedef struct { - /* Public fields. - */ - struct jpeg_error_mgr pub; - - /* Private stuff for us. - */ - jmp_buf jmp; /* longjmp() here to get back to VIPS */ - FILE *fp; /* fclose() if non-NULL */ -} ErrorManager; - -/* New output message method - send to VIPS. - */ -METHODDEF(void) -new_output_message( j_common_ptr cinfo ) -{ - char buffer[JMSG_LENGTH_MAX]; - - (*cinfo->err->format_message)( cinfo, buffer ); - im_error( "vips_jpeg", _( "%s" ), buffer ); - -#ifdef DEBUG - printf( "vips_jpeg.c: new_output_message: \"%s\"\n", buffer ); -#endif /*DEBUG*/ -} - -/* New error_exit handler. - */ -METHODDEF(void) -new_error_exit( j_common_ptr cinfo ) -{ - ErrorManager *eman = (ErrorManager *) cinfo->err; - -#ifdef DEBUG - printf( "vips_jpeg.c: new_error_exit\n" ); -#endif /*DEBUG*/ - - /* Close the fp if necessary. - */ - if( eman->fp ) { - (void) fclose( eman->fp ); - eman->fp = NULL; - } - - /* Send the error message to VIPS. This method is overridden above. - */ - (*cinfo->err->output_message)( cinfo ); - - /* Jump back. - */ - longjmp( eman->jmp, 1 ); -} - -#ifdef HAVE_EXIF -#ifdef DEBUG_VERBOSE -/* Print exif for debugging ... hacked from exif-0.6.9/actions.c - */ -static void -show_tags( ExifData *data ) -{ - int i; - unsigned int tag; - const char *name; - - printf( "show EXIF tags:\n" ); - - for( i = 0; i < EXIF_IFD_COUNT; i++ ) - printf( "%-7.7s", exif_ifd_get_name( i ) ); - printf( "\n" ); - - for( tag = 0; tag < 0xffff; tag++ ) { - name = exif_tag_get_title( tag ); - if( !name ) - continue; - printf( " 0x%04x %-29.29s", tag, name ); - for( i = 0; i < EXIF_IFD_COUNT; i++ ) - if( exif_content_get_entry( data->ifd[i], tag ) ) - printf( " * " ); - else - printf( " - " ); - printf( "\n" ); - } -} - -static void -show_entry( ExifEntry *entry, void *client ) -{ - char exif_text[256]; - - printf( "%s", exif_tag_get_title( entry->tag ) ); - printf( "|" ); - printf( "%s", exif_entry_get_value( entry, exif_text, 256 ) ); - printf( "|" ); - printf( "%s", exif_format_get_name( entry->format ) ); - printf( "|" ); - printf( "%d bytes", entry->size ); - printf( "\n" ); -} - -static void -show_ifd( ExifContent *content, void *client ) -{ - exif_content_foreach_entry( content, show_entry, client ); - printf( "-\n" ); -} - -void -show_values( ExifData *data ) -{ - ExifByteOrder order; - - order = exif_data_get_byte_order( data ); - printf( "EXIF tags in '%s' byte order\n", - exif_byte_order_get_name( order ) ); - - printf( "%-20.20s", "Tag" ); - printf( "|" ); - printf( "%-58.58s", "Value" ); - printf( "\n" ); - - exif_data_foreach_content( data, show_ifd, NULL ); - - if( data->size ) - printf( "contains thumbnail of %d bytes\n", data->size ); -} -#endif /*DEBUG_VERBOSE*/ -#endif /*HAVE_EXIF*/ - -#ifdef HAVE_EXIF -static void -attach_exif_entry( ExifEntry *entry, IMAGE *im ) -{ - char name_text[256]; - VBuf name; - char value_text[256]; - VBuf value; - char exif_value[256]; - - im_buf_init_static( &name, name_text, 256 ); - im_buf_init_static( &value, value_text, 256 ); - - im_buf_appendf( &name, "exif-%s", exif_tag_get_title( entry->tag ) ); - im_buf_appendf( &value, "%s (%s, %d bytes)", - exif_entry_get_value( entry, exif_value, 256 ), - exif_format_get_name( entry->format ), - entry->size ); - - /* Can't do anything sensible with the error return. - */ - (void) im_meta_set_string( im, - im_buf_all( &name ), im_buf_all( &value ) ); -} - -static void -attach_exif_content( ExifContent *content, IMAGE *im ) -{ - exif_content_foreach_entry( content, - (ExifContentForeachEntryFunc) attach_exif_entry, im ); -} - -/* Just find the first occurence of the tag (is this correct?) - */ -static ExifEntry * -find_entry( ExifData *ed, ExifTag tag ) -{ - int i; - - for( i = 0; i < EXIF_IFD_COUNT; i++ ) { - ExifEntry *entry; - - if( (entry = exif_content_get_entry( ed->ifd[i], tag )) ) - return( entry ); - } - - return( NULL ); -} - -static int -get_entry_rational( ExifData *ed, ExifTag tag, double *out ) -{ - ExifEntry *entry; - ExifRational rational; - - if( !(entry = find_entry( ed, tag )) || - entry->format != EXIF_FORMAT_RATIONAL || - entry->components != 1 ) - return( -1 ); - - rational = exif_get_rational( entry->data, - exif_data_get_byte_order( ed ) ); - - *out = (double) rational.numerator / rational.denominator; - - return( 0 ); -} - -static int -get_entry_short( ExifData *ed, ExifTag tag, int *out ) -{ - ExifEntry *entry; - - if( !(entry = find_entry( ed, tag )) || - entry->format != EXIF_FORMAT_SHORT || - entry->components != 1 ) - return( -1 ); - - *out = exif_get_short( entry->data, - exif_data_get_byte_order( ed ) ); - - return( 0 ); -} - -static void -set_vips_resolution( IMAGE *im, ExifData *ed ) -{ - double xres, yres; - int unit; - - if( get_entry_rational( ed, EXIF_TAG_X_RESOLUTION, &xres ) || - get_entry_rational( ed, EXIF_TAG_Y_RESOLUTION, &yres ) || - get_entry_short( ed, EXIF_TAG_RESOLUTION_UNIT, &unit ) ) { - im_warn( "im_jpeg2vips", _( "error reading resolution" ) ); - return; - } - - switch( unit ) { - case 2: - /* In inches. - */ - xres /= 25.4; - yres /= 25.4; - break; - - case 3: - /* In cm. - */ - xres /= 10.0; - yres /= 10.0; - break; - - default: - im_warn( "im_jpeg2vips", _( "bad resolution unit" ) ); - return; - } - - im->Xres = xres; - im->Yres = yres; -} -#endif /*HAVE_EXIF*/ - -static int -read_exif( IMAGE *im, void *data, int data_length ) -{ - char *data_copy; - - /* Always attach a copy of the unparsed exif data. - */ - if( !(data_copy = im_malloc( NULL, data_length )) ) - return( -1 ); - memcpy( data_copy, data, data_length ); - if( im_meta_set_blob( im, IM_META_EXIF_NAME, - (im_callback_fn) im_free, data_copy, data_length ) ) { - im_free( data_copy ); - return( -1 ); - } - -#ifdef HAVE_EXIF -{ - ExifData *ed; - - if( !(ed = exif_data_new_from_data( data, data_length )) ) - return( -1 ); - - if( ed->size > 0 ) { -#ifdef DEBUG_VERBOSE - show_tags( ed ); - show_values( ed ); -#endif /*DEBUG_VERBOSE*/ - - /* Attach informational fields for what we find. - - FIXME ... better to have this in the UI layer? - - Or we could attach non-human-readable tags here (int, double - etc) and then move the human stuff to the UI layer? - - */ - exif_data_foreach_content( ed, - (ExifDataForeachContentFunc) attach_exif_content, im ); - - /* Look for resolution fields and use them to set the VIPS - * xres/yres fields. - */ - set_vips_resolution( im, ed ); - } - - exif_data_free( ed ); -} -#endif /*HAVE_EXIF*/ - - return( 0 ); -} - -/* Number of app2 sections we can capture. Each one can be 64k, so 640k should - * be enough for anyone (haha). - */ -#define MAX_APP2_SECTIONS (10) - -/* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to - * do 255-pel. - */ -static int -read_jpeg_header( struct jpeg_decompress_struct *cinfo, - IMAGE *out, gboolean *invert_pels, int shrink ) -{ - jpeg_saved_marker_ptr p; - int type; - - /* Capture app2 sections here for assembly. - */ - void *app2_data[MAX_APP2_SECTIONS] = { 0 }; - int app2_data_length[MAX_APP2_SECTIONS] = { 0 }; - int data_length; - int i; - - /* Read JPEG header. libjpeg will set out_color_space sanely for us - * for YUV YCCK etc. - */ - jpeg_read_header( cinfo, TRUE ); - cinfo->scale_denom = shrink; - jpeg_calc_output_dimensions( cinfo ); - *invert_pels = FALSE; - switch( cinfo->out_color_space ) { - case JCS_GRAYSCALE: - type = IM_TYPE_B_W; - break; - - case JCS_CMYK: - type = IM_TYPE_CMYK; - /* Photoshop writes CMYK JPEG inverted :-( Maybe this is a - * way to spot photoshop CMYK JPGs. - */ - if( cinfo->saw_Adobe_marker ) - *invert_pels = TRUE; - break; - - case JCS_RGB: - default: - type = IM_TYPE_sRGB; - break; - } - - /* Set VIPS header. - */ - im_initdesc( out, - cinfo->output_width, cinfo->output_height, - cinfo->output_components, - IM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, type, - 1.0, 1.0, 0, 0 ); - - /* Look for EXIF and ICC profile. - */ - for( p = cinfo->marker_list; p; p = p->next ) { - switch( p->marker ) { - case JPEG_APP0 + 1: - /* EXIF data. - */ -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of EXIF\n", - p->data_length ); -#endif /*DEBUG*/ - if( read_exif( out, p->data, p->data_length ) ) - return( -1 ); - break; - - case JPEG_APP0 + 2: - /* ICC profile. - */ -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of ICC\n", - p->data_length ); -#endif /*DEBUG*/ - - if( p->data_length > 14 && - im_isprefix( "ICC_PROFILE", - (char *) p->data ) ) { - /* cur_marker numbers from 1, according to - * spec. - */ - int cur_marker = p->data[12] - 1; - - if( cur_marker >= 0 && - cur_marker < MAX_APP2_SECTIONS ) { - app2_data[cur_marker] = p->data + 14; - app2_data_length[cur_marker] = - p->data_length - 14; - } - } - break; - - default: -#ifdef DEBUG - printf( "read_jpeg_header: seen %d bytes of data\n", - p->data_length ); -#endif /*DEBUG*/ - break; - } - } - - /* Assemble ICC sections. - */ - data_length = 0; - for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) - data_length += app2_data_length[i]; - if( data_length ) { - unsigned char *data; - int p; - -#ifdef DEBUG - printf( "read_jpeg_header: assembled %d byte ICC profile\n", - data_length ); -#endif /*DEBUG*/ - - if( !(data = im_malloc( NULL, data_length )) ) - return( -1 ); - - p = 0; - for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) { - memcpy( data + p, app2_data[i], app2_data_length[i] ); - p += app2_data_length[i]; - } - - if( im_meta_set_blob( out, IM_META_ICC_NAME, - (im_callback_fn) im_free, data, data_length ) ) { - im_free( data ); - return( -1 ); - } - } - - return( 0 ); -} - -/* Read a cinfo to a VIPS image. - */ -static int -read_jpeg_image( struct jpeg_decompress_struct *cinfo, IMAGE *out, - gboolean invert_pels ) -{ - int x, y, sz; - JSAMPROW row_pointer[1]; - - /* Check VIPS. - */ - if( im_outcheck( out ) || im_setupout( out ) ) - return( -1 ); - - /* Get size of output line and make a buffer. - */ - sz = cinfo->output_width * cinfo->output_components; - row_pointer[0] = (JSAMPLE *) (*cinfo->mem->alloc_large) - ( (j_common_ptr) cinfo, JPOOL_IMAGE, sz ); - - /* Start up decompressor. - */ - jpeg_start_decompress( cinfo ); - - /* Process image. - */ - for( y = 0; y < out->Ysize; y++ ) { - if( jpeg_read_scanlines( cinfo, &row_pointer[0], 1 ) != 1 ) { - im_error( "im_jpeg2vips", _( "truncated JPEG file" ) ); - return( -1 ); - } - if( invert_pels ) { - for( x = 0; x < sz; x++ ) - row_pointer[0][x] = 255 - row_pointer[0][x]; - } - if( im_writeline( y, out, row_pointer[0] ) ) - return( -1 ); - } - - /* Stop decompressor. - */ - jpeg_finish_decompress( cinfo ); - - return( 0 ); -} - -/* Read a JPEG file into a VIPS image. - */ -static int -jpeg2vips( const char *name, IMAGE *out, gboolean header_only ) -{ - char filename[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char *p, *q; - int shrink; - struct jpeg_decompress_struct cinfo; - ErrorManager eman; - FILE *fp; - int result; - gboolean invert_pels; - - /* Parse the filename. - */ - im_filename_split( name, filename, mode ); - p = &mode[0]; - shrink = 1; - if( (q = im_getnextoption( &p )) ) { - shrink = atoi( q ); - - if( shrink != 1 && shrink != 2 && - shrink != 4 && shrink != 8 ) { - im_error( "im_jpeg2vips", - _( "bad shrink factor %d" ), shrink ); - return( -1 ); - } - } - - /* Make jpeg compression object. - */ - cinfo.err = jpeg_std_error( &eman.pub ); - eman.pub.error_exit = new_error_exit; - eman.pub.output_message = new_output_message; - eman.fp = NULL; - if( setjmp( eman.jmp ) ) { - /* Here for longjmp() from new_error_exit(). - */ - jpeg_destroy_decompress( &cinfo ); - - return( -1 ); - } - jpeg_create_decompress( &cinfo ); - - /* Make input. - */ -#ifdef BINARY_OPEN - if( !(fp = fopen( filename, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(fp = fopen( filename, "r" )) ) { -#endif /*BINARY_OPEN*/ - jpeg_destroy_decompress( &cinfo ); - im_error( "im_jpeg2vips", - _( "unable to open \"%s\"" ), filename ); - - return( -1 ); - } - eman.fp = fp; - jpeg_stdio_src( &cinfo, fp ); - - /* Need to read in APP1 (EXIF metadata) and APP2 (ICC profile). - */ - jpeg_save_markers( &cinfo, JPEG_APP0 + 1, 0xffff ); - jpeg_save_markers( &cinfo, JPEG_APP0 + 2, 0xffff ); - - /* Convert! - */ - result = read_jpeg_header( &cinfo, out, &invert_pels, shrink ); - if( !header_only && !result ) - result = read_jpeg_image( &cinfo, out, invert_pels ); - - /* Close and tidy. - */ - fclose( fp ); - eman.fp = NULL; - jpeg_destroy_decompress( &cinfo ); - - if( eman.pub.num_warnings != 0 ) { - im_warn( "im_jpeg2vips", _( "read gave %ld warnings" ), - eman.pub.num_warnings ); - im_warn( "im_jpeg2vips", "%s", im_error_buffer() ); - } - - return( result ); -} - -/* Read a JPEG file into a VIPS image. - */ -int -im_jpeg2vips( const char *name, IMAGE *out ) -{ - return( jpeg2vips( name, out, FALSE ) ); -} - -int -im_jpeg2vips_header( const char *name, IMAGE *out ) -{ - return( jpeg2vips( name, out, TRUE ) ); -} - -#endif /*HAVE_JPEG*/ diff --git a/libsrc/conversion/im_magick2vips.c b/libsrc/conversion/im_magick2vips.c deleted file mode 100644 index feda6c01..00000000 --- a/libsrc/conversion/im_magick2vips.c +++ /dev/null @@ -1,650 +0,0 @@ -/* Read a file using libMagick - * - * 7/1/03 JC - * - from im_tiff2vips - * 3/2/03 JC - * - some InitializeMagick() fail with NULL arg - * 2/11/04 - * - im_magick2vips_header() also checks sensible width/height - * 28/10/05 - * - copy attributes to meta - * - write many-frame images as a big column if all frames have identical - * width/height/bands/depth - * 31/3/06 - * - test for magick attr support - * 8/5/06 - * - set RGB16/GREY16 if appropriate - * 10/8/07 - * - support 32/64 bit imagemagick too - * 21/2/08 - * - use MaxRGB if QuantumRange is missing (thanks Bob) - * - look for MAGICKCORE_HDRI_SUPPORT (thanks Marcel) - * - use image->attributes if GetNextImageAttribute() is missing - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* Turn on debugging output. -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_MAGICK - -#include - -int -im_magick2vips( const char *filename, IMAGE *im ) -{ - im_error( "im_magick2vips", _( "libMagick support disabled" ) ); - return( -1 ); -} - -int -im_magick2vips_header( const char *filename, IMAGE *im ) -{ - im_error( "im_magick2vips", _( "libMagick support disabled" ) ); - return( -1 ); -} - -#else /*HAVE_MAGICK*/ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* pre-float Magick used to call this MaxRGB. - */ -#if !defined(QuantumRange) -# define QuantumRange MaxRGB -#endif - -/* And this used to be UseHDRI. - */ -#if MAGICKCORE_HDRI_SUPPORT -# define UseHDRI=1 -#endif - -/* What we track during a read call. - */ -typedef struct _Read { - char *filename; - IMAGE *im; - - Image *image; - ImageInfo *image_info; - ExceptionInfo exception; - - int n_frames; - Image **frames; - int frame_height; - - /* Mutex to serialise calls to libMagick during threaded read. - */ - GMutex *lock; -} Read; - -static int -read_destroy( Read *read ) -{ -#ifdef DEBUG - printf( "im_magick2vips: read_destroy: %s\n", read->filename ); -#endif /*DEBUG*/ - - IM_FREEF( DestroyImage, read->image ); - IM_FREEF( DestroyImageInfo, read->image_info ); - IM_FREE( read->frames ); - IM_FREE( read->filename ); - DestroyExceptionInfo( &read->exception ); - IM_FREEF( g_mutex_free, read->lock ); - im_free( read ); - - return( 0 ); -} - -static Read * -read_new( const char *filename, IMAGE *im ) -{ - Read *read; - static int inited = 0; - - if( !inited ) { - InitializeMagick( "" ); - inited = 1; - } - - if( !(read = IM_NEW( NULL, Read )) ) - return( NULL ); - read->filename = im_strdup( NULL, filename ); - read->im = im; - read->image = NULL; - read->image_info = CloneImageInfo( NULL ); - GetExceptionInfo( &read->exception ); - read->n_frames = 0; - read->frames = NULL; - read->frame_height = 0; - read->lock = g_mutex_new(); - - if( im_add_close_callback( im, - (im_callback_fn) read_destroy, read, NULL ) ) { - read_destroy( read ); - return( NULL ); - } - - if( !read->filename || !read->image_info ) - return( NULL ); - - im_strncpy( read->image_info->filename, filename, MaxTextExtent ); - -#ifdef DEBUG - printf( "im_magick2vips: read_new: %s\n", read->filename ); -#endif /*DEBUG*/ - - return( read ); -} - -static int -get_bands( Image *image ) -{ - int bands; - - switch( image->colorspace ) { - case GRAYColorspace: - bands = 1; - break; - - case RGBColorspace: - bands = 3; - break; - - case sRGBColorspace: - bands = 3; - break; - - case CMYKColorspace: - bands = 4; - break; - - default: - im_error( "im_magick2vips", _( "unsupported colorspace %d" ), - (int) image->colorspace ); - return( -1 ); - } - - /* Alpha as well? - */ - if( image->matte ) { - assert( image->colorspace != CMYKColorspace ); - bands += 1; - } - - return( bands ); -} - -static int -parse_header( Read *read ) -{ - IMAGE *im = read->im; - Image *image = read->image; - -#ifdef HAVE_MAGICK_ATTR - const ImageAttribute *attr; -#endif /*HAVE_MAGICK_ATTR*/ - Image *p; - int i; - - im->Xsize = image->columns; - im->Ysize = image->rows; - read->frame_height = image->rows; - if( (im->Bands = get_bands( image )) < 0 ) - return( -1 ); - - switch( image->depth ) { - case 8: - im->BandFmt = IM_BANDFMT_UCHAR; - im->Bbits = IM_BBITS_BYTE; - break; - - case 16: - im->BandFmt = IM_BANDFMT_USHORT; - im->Bbits = IM_BBITS_SHORT; - break; - -#ifdef UseHDRI - case 32: - im->BandFmt = IM_BANDFMT_FLOAT; - im->Bbits = IM_BBITS_FLOAT; - break; - - case 64: - im->BandFmt = IM_BANDFMT_DOUBLE; - im->Bbits = IM_BBITS_DOUBLE; - break; -#else /*!UseHDRI*/ - case 32: - im->BandFmt = IM_BANDFMT_UINT; - im->Bbits = IM_BBITS_INT; - break; - - /* No 64-bit int format in VIPS. - */ -#endif /*UseHDRI*/ - - default: - im_error( "im_magick2vips", _( "unsupported bit depth %d" ), - (int) image->depth ); - return( -1 ); - } - - switch( image->colorspace ) { - case GRAYColorspace: - if( im->BandFmt == IM_BANDFMT_USHORT ) - im->Type = IM_TYPE_GREY16; - else - im->Type = IM_TYPE_B_W; - break; - - case RGBColorspace: - if( im->BandFmt == IM_BANDFMT_USHORT ) - im->Type = IM_TYPE_RGB16; - else - im->Type = IM_TYPE_RGB; - break; - - case sRGBColorspace: - if( im->BandFmt == IM_BANDFMT_USHORT ) - im->Type = IM_TYPE_RGB16; - else - im->Type = IM_TYPE_sRGB; - break; - - case CMYKColorspace: - im->Type = IM_TYPE_CMYK; - break; - - default: - im_error( "im_magick2vips", _( "unsupported colorspace %d" ), - (int) image->colorspace ); - return( -1 ); - } - - switch( image->units ) { - case PixelsPerInchResolution: - im->Xres = image->x_resolution / 25.4; - im->Yres = image->y_resolution / 25.4; - break; - - case PixelsPerCentimeterResolution: - im->Xres = image->x_resolution / 10.0; - im->Yres = image->y_resolution / 10.0; - break; - - default: - im->Xres = 1.0; - im->Yres = 1.0; - break; - } - - /* Other fields. - */ - im->Coding = IM_CODING_NONE; - -#ifdef HAVE_MAGICK_ATTR -#ifdef HAVE_GETNEXTIMAGEATTRIBUTE - /* Gah, magick6.something and later only. Attach any attributes. - */ - ResetImageAttributeIterator( image ); - while( (attr = GetNextImageAttribute( image )) ) { -#elif defined(HAVE_GETIMAGEATTRIBUTE) - /* GraphicsMagick is missing the iterator: we have to loop ourselves. - * ->attributes is marked as private in the header, but there's no - * getter so we have to access it directly. - */ - for( attr = image->attributes; attr; attr = attr->next ) { -#else /*stuff*/ - #error attributes enabled, but no access funcs found -#endif - char name_text[256]; - VBuf name; - - im_buf_init_static( &name, name_text, 256 ); - im_buf_appendf( &name, "magick-%s", attr->key ); - im_meta_set_string( im, im_buf_all( &name ), attr->value ); - -#ifdef DEBUG - printf( "key = \"%s\", value = \"%s\"\n", - attr->key, attr->value ); -#endif /*DEBUG*/ - } -#endif /*HAVE_MAGICK_ATTR*/ - - /* Do we have a set of equal-sized frames? Append them. - - FIXME ... there must be an attribute somewhere from dicom read - which says this is a volumetric image - - */ - read->n_frames = 0; - for( p = image; p; (p = GetNextImageInList( p )) ) { - if( p->columns != im->Xsize || - p->rows != im->Ysize || - p->depth != im->Bbits || - get_bands( p ) != im->Bands ) - break; - - read->n_frames += 1; - } - if( p ) - /* Nope ... just do the first image in the list. - */ - read->n_frames = 1; - - /* Record frame pointers. - */ - im->Ysize *= read->n_frames; - if( !(read->frames = IM_ARRAY( NULL, read->n_frames, Image * )) ) - return( -1 ); - p = image; - for( i = 0; i < read->n_frames; i++ ) { - read->frames[i] = p; - p = GetNextImageInList( p ); - } - - return( 0 ); -} - -/* Divide by this to get 0 - MAX from a Quantum. Eg. consider QuantumRange == - * 65535, MAX == 255 (a Q16 ImageMagic representing an 8-bit image). Make sure - * this can't be zero (if QuantumRange < MAX) .. can happen if we have a Q8 - * ImageMagick trying to represent a 16-bit image. - */ -#define SCALE( MAX ) \ - (QuantumRange < (MAX) ? \ - 1 : \ - ((QuantumRange + 1) / ((MAX) + 1))) - -#define GRAY_LOOP( TYPE, MAX ) { \ - TYPE *q = (TYPE *) q8; \ - \ - for( x = 0; x < n; x++ ) \ - q[x] = pixels[x].green / SCALE( MAX ); \ -} - -#define GRAYA_LOOP( TYPE, MAX ) { \ - TYPE *q = (TYPE *) q8; \ - \ - for( x = 0; x < n; x++ ) { \ - q[0] = pixels[x].green / SCALE( MAX ); \ - q[1] = pixels[x].opacity / SCALE( MAX ); \ - \ - q += 2; \ - } \ -} - -#define RGB_LOOP( TYPE, MAX ) { \ - TYPE *q = (TYPE *) q8; \ - \ - for( x = 0; x < n; x++ ) { \ - q[0] = pixels[x].red / SCALE( MAX ); \ - q[1] = pixels[x].green / SCALE( MAX ); \ - q[2] = pixels[x].blue / SCALE( MAX ); \ - \ - q += 3; \ - } \ -} - -#define RGBA_LOOP( TYPE, MAX ) { \ - TYPE *q = (TYPE *) q8; \ - \ - for( x = 0; x < n; x++ ) { \ - q[0] = pixels[x].red / SCALE( MAX ); \ - q[1] = pixels[x].green / SCALE( MAX ); \ - q[2] = pixels[x].blue / SCALE( MAX ); \ - q[3] = pixels[x].opacity / SCALE( MAX ); \ - \ - q += 4; \ - } \ -} - -static void -unpack_pixels( IMAGE *im, PEL *q8, PixelPacket *pixels, int n ) -{ - int x; - - switch( im->Bands ) { - case 1: - /* Gray. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: - GRAY_LOOP( unsigned char, 255 ); break; - case IM_BANDFMT_USHORT: - GRAY_LOOP( unsigned short, 65535 ); break; - case IM_BANDFMT_UINT: - GRAY_LOOP( unsigned int, 4294967295UL ); break; - case IM_BANDFMT_DOUBLE: - GRAY_LOOP( double, QuantumRange ); break; - - default: - assert( 0 ); - } - break; - - case 2: - /* Gray plus alpha. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: - GRAYA_LOOP( unsigned char, 255 ); break; - case IM_BANDFMT_USHORT: - GRAYA_LOOP( unsigned short, 65535 ); break; - case IM_BANDFMT_UINT: - GRAYA_LOOP( unsigned int, 4294967295UL ); break; - case IM_BANDFMT_DOUBLE: - GRAYA_LOOP( double, QuantumRange ); break; - - default: - assert( 0 ); - } - break; - - case 3: - /* RGB. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: - RGB_LOOP( unsigned char, 255 ); break; - case IM_BANDFMT_USHORT: - RGB_LOOP( unsigned short, 65535 ); break; - case IM_BANDFMT_UINT: - RGB_LOOP( unsigned int, 4294967295UL ); break; - case IM_BANDFMT_DOUBLE: - RGB_LOOP( double, QuantumRange ); break; - - default: - assert( 0 ); - } - break; - - case 4: - /* RGBA or CMYK. - */ - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: - RGBA_LOOP( unsigned char, 255 ); break; - case IM_BANDFMT_USHORT: - RGBA_LOOP( unsigned short, 65535 ); break; - case IM_BANDFMT_UINT: - RGBA_LOOP( unsigned int, 4294967295UL ); break; - case IM_BANDFMT_DOUBLE: - RGBA_LOOP( double, QuantumRange ); break; - - default: - assert( 0 ); - } - break; - - default: - assert( 0 ); - } -} - -static PixelPacket * -get_pixels( Image *image, int left, int top, int width, int height ) -{ - PixelPacket *pixels; - - if( !(pixels = GetImagePixels( image, left, top, width, height )) ) - return( NULL ); - -/* Can't happen if red/green/blue are doubles. - */ -#ifndef UseHDRI - /* Unpack palette. - */ - if( image->storage_class == PseudoClass ) { - IndexPacket *indexes = GetIndexes( image ); - int i; - - for( i = 0; i < width * height; i++ ) { - IndexPacket x = indexes[i]; - - if( x < image->colors ) { - pixels[i].red = image->colormap[x].red; - pixels[i].green = image->colormap[x].green; - pixels[i].blue = image->colormap[x].blue; - } - } - } -#endif /*UseHDRI*/ - - return( pixels ); -} - -static int -magick_fill_region( REGION *out, void *seq, void *a, void *b ) -{ - Read *read = (Read *) a; - Rect *r = &out->valid; - int y; - - for( y = 0; y < r->height; y++ ) { - int top = r->top + y; - int frame = top / read->frame_height; - int line = top % read->frame_height; - - PixelPacket *pixels; - - g_mutex_lock( read->lock ); - pixels = get_pixels( read->frames[frame], - r->left, line, r->width, 1 ); - g_mutex_unlock( read->lock ); - - if( !pixels ) { - im_error( "im_magick2vips", - _( "unable to read pixels" ) ); - return( -1 ); - } - - unpack_pixels( read->im, - (PEL *) IM_REGION_ADDR( out, r->left, top ), - pixels, r->width ); - } - - return( 0 ); -} - -int -im_magick2vips( const char *filename, IMAGE *im ) -{ - Read *read; - - if( !(read = read_new( filename, im )) ) - return( -1 ); - - read->image = ReadImage( read->image_info, &read->exception ); - if( !read->image ) { - im_error( "im_magick2vips", _( "unable to read file \"%s\"\n" - "libMagick error: %s %s" ), - filename, - read->exception.reason, read->exception.description ); - return( -1 ); - } - - if( parse_header( read ) || - im_poutcheck( im ) || - im_generate( im, NULL, magick_fill_region, NULL, read, NULL ) ) - return( -1 ); - - return( 0 ); -} - -int -im_magick2vips_header( const char *filename, IMAGE *im ) -{ - Read *read; - - if( !(read = read_new( filename, im )) ) - return( -1 ); - - read->image = PingImage( read->image_info, &read->exception ); - if( !read->image ) { - im_error( "im_magick2vips", _( "unable to ping file " - "\"%s\"\nlibMagick error: %s %s" ), - filename, - read->exception.reason, read->exception.description ); - return( -1 ); - } - - if( parse_header( read ) ) - return( -1 ); - - if( im->Xsize <= 0 || im->Ysize <= 0 ) { - im_error( "im_magick2vips", _( "bad image size" ) ); - return( -1 ); - } - - return( 0 ); -} - -#endif /*HAVE_MAGICK*/ diff --git a/libsrc/conversion/im_png2vips.c b/libsrc/conversion/im_png2vips.c deleted file mode 100644 index a0d91ea8..00000000 --- a/libsrc/conversion/im_png2vips.c +++ /dev/null @@ -1,381 +0,0 @@ -/* Convert 1 to 4-band 8 or 16-bit VIPS images to/from PNG. - * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 22/2/05 - * - read non-interlaced PNG with a line buffer (thanks Michel Brabants) - * 11/1/06 - * - read RGBA palette-ized images more robustly (thanks Tom) - * 20/4/06 - * - auto convert to sRGB/mono (with optional alpha) for save - * 1/5/06 - * - from vips_png.c - * 8/5/06 - * - set RGB16/GREY16 if appropriate - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_PNG - -#include - -int -im_png2vips( const char *name, IMAGE *out ) -{ - im_error( "im_png2vips", _( "PNG support disabled" ) ); - return( -1 ); -} - -int -im_png2vips_header( const char *name, IMAGE *out ) -{ - im_error( "im_png2vips_header", _( "PNG support disabled" ) ); - return( -1 ); -} - -#else /*HAVE_PNG*/ - -#include -#include -#include - -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -#if PNG_LIBPNG_VER < 10003 -#error "PNG library too old." -#endif - -static void -user_error_function( png_structp png_ptr, png_const_charp error_msg ) -{ - im_error( "im_png2vips", _( "PNG error: \"%s\"" ), error_msg ); -} - -static void -user_warning_function( png_structp png_ptr, png_const_charp warning_msg ) -{ - im_error( "im_png2vips", _( "PNG warning: \"%s\"" ), warning_msg ); -} - -/* What we track during a PNG read. - */ -typedef struct { - char *name; - IMAGE *out; - - FILE *fp; - png_structp pPng; - png_infop pInfo; - png_bytep *row_pointer; - png_bytep data; -} Read; - -static void -read_destroy( Read *read ) -{ - if( read->name ) { - im_free( read->name ); - read->name = NULL; - } - if( read->fp ) { - fclose( read->fp ); - read->fp = NULL; - } - if( read->pPng ) - png_destroy_read_struct( &read->pPng, &read->pInfo, NULL ); - if( read->row_pointer ) { - im_free( read->row_pointer ); - read->row_pointer = NULL; - } - if( read->data ) { - im_free( read->data ); - read->data = NULL; - } - - im_free( read ); -} - -static Read * -read_new( const char *name, IMAGE *out ) -{ - Read *read; - - if( !(read = IM_NEW( NULL, Read )) ) - return( NULL ); - - read->name = im_strdup( NULL, name ); - read->out = out; - read->fp = NULL; - read->pPng = NULL; - read->pInfo = NULL; - read->row_pointer = NULL; - read->data = NULL; - -#ifdef BINARY_OPEN - if( !(read->fp = fopen( name, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(read->fp = fopen( name, "r" )) ) { -#endif /*BINARY_OPEN*/ - read_destroy( read ); - im_error( "im_png2vips", _( "unable to open \"%s\"" ), name ); - return( NULL ); - } - - if( !(read->pPng = png_create_read_struct( - PNG_LIBPNG_VER_STRING, NULL, - user_error_function, user_warning_function )) ) { - read_destroy( read ); - return( NULL ); - } - - /* Catch PNG errors from png_create_info_struct(). - */ - if( setjmp( read->pPng->jmpbuf ) ) { - read_destroy( read ); - return( NULL ); - } - - if( !(read->pInfo = png_create_info_struct( read->pPng )) ) { - read_destroy( read ); - return( NULL ); - } - - return( read ); -} - -/* Yuk! Have to malloc enough space for the whole image. Interlaced PNG - * is not really suitable for large objects ... - */ -static int -png2vips_interlace( Read *read ) -{ - const int rowbytes = IM_IMAGE_SIZEOF_LINE( read->out ); - int y; - - if( !(read->row_pointer = IM_ARRAY( NULL, - read->pInfo->height, png_bytep )) ) - return( -1 ); - if( !(read->data = (png_bytep) im_malloc( NULL, - read->pInfo->height * rowbytes )) ) - return( -1 ); - - for( y = 0; y < (int) read->pInfo->height; y++ ) - read->row_pointer[y] = read->data + y * rowbytes; - if( im_outcheck( read->out ) || - im_setupout( read->out ) || - setjmp( read->pPng->jmpbuf ) ) - return( -1 ); - - png_read_image( read->pPng, read->row_pointer ); - - for( y = 0; y < (int) read->pInfo->height; y++ ) - if( im_writeline( y, read->out, read->row_pointer[y] ) ) - return( -1 ); - - return( 0 ); -} - -/* Noninterlaced images can be read without needing enough RAM for the whole - * image. - */ -static int -png2vips_noninterlace( Read *read ) -{ - const int rowbytes = IM_IMAGE_SIZEOF_LINE( read->out ); - int y; - - if( !(read->data = (png_bytep) im_malloc( NULL, rowbytes )) ) - return( -1 ); - if( im_outcheck( read->out ) || - im_setupout( read->out ) || - setjmp( read->pPng->jmpbuf ) ) - return( -1 ); - - for( y = 0; y < (int) read->pInfo->height; y++ ) { - png_read_row( read->pPng, read->data, NULL ); - - if( im_writeline( y, read->out, read->data ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Read a PNG file (header) into a VIPS (header). - */ -static int -png2vips( Read *read, int header_only ) -{ - int bands, bpp, type; - - if( setjmp( read->pPng->jmpbuf ) ) - return( -1 ); - - png_init_io( read->pPng, read->fp ); - png_read_info( read->pPng, read->pInfo ); - - /* png_get_channels() gives us 1 band for palette images ... so look - * at colour_type for output bands. - */ - switch( read->pInfo->color_type ) { - case PNG_COLOR_TYPE_PALETTE: - bands = 3; - - /* Don't know if this is really correct. If there are - * transparent pixels, assume we're going to output RGBA. - */ - if( read->pInfo->num_trans ) - bands = 4; - - break; - - case PNG_COLOR_TYPE_GRAY: bands = 1; break; - case PNG_COLOR_TYPE_GRAY_ALPHA: bands = 2; break; - case PNG_COLOR_TYPE_RGB: bands = 3; break; - case PNG_COLOR_TYPE_RGB_ALPHA: bands = 4; break; - - default: - im_error( "im_png2vips", _( "unsupported colour type" ) ); - return( -1 ); - } - - /* 8 or 16 bit. - */ - bpp = read->pInfo->bit_depth > 8 ? 2 : 1; - - if( bpp > 1 ) { - if( bands < 3 ) - type = IM_TYPE_GREY16; - else - type = IM_TYPE_RGB16; - } - else { - if( bands < 3 ) - type = IM_TYPE_B_W; - else - type = IM_TYPE_sRGB; - } - - /* Expand palette images. - */ - if( read->pInfo->color_type == PNG_COLOR_TYPE_PALETTE ) - png_set_expand( read->pPng ); - - /* Expand <8 bit images to full bytes. - */ - if( read->pInfo->bit_depth < 8 ) - png_set_packing( read->pPng ); - - /* If we're an INTEL byte order machine and this is 16bits, we need - * to swap bytes. - */ - if( read->pInfo->bit_depth > 8 && !im_amiMSBfirst() ) - png_set_swap( read->pPng ); - - /* Set VIPS header. - */ - im_initdesc( read->out, - read->pInfo->width, read->pInfo->height, bands, - bpp == 1 ? IM_BBITS_BYTE : IM_BBITS_SHORT, - bpp == 1 ? IM_BANDFMT_UCHAR : IM_BANDFMT_USHORT, - IM_CODING_NONE, type, 1.0, 1.0, 0, 0 ); - - if( !header_only ) { - if( png_set_interlace_handling( read->pPng ) > 1 ) { - if( png2vips_interlace( read ) ) - return( -1 ); - } - else { - if( png2vips_noninterlace( read ) ) - return( -1 ); - } - } - - return( 0 ); -} - -/* Read a PNG file header into a VIPS header. - */ -int -im_png2vips_header( const char *name, IMAGE *out ) -{ - Read *read; - - if( !(read = read_new( name, out )) ) - return( -1 ); - - if( png2vips( read, 1 ) ) { - read_destroy( read ); - return( -1 ); - } - - read_destroy( read ); - - return( 0 ); -} - -/* Read a PNG file into a VIPS image. - */ -int -im_png2vips( const char *name, IMAGE *out ) -{ - Read *read; - -#ifdef DEBUG - printf( "im_png2vips: reading \"%s\"\n", name ); -#endif /*DEBUG*/ - - if( !(read = read_new( name, out )) ) - return( -1 ); - - if( png2vips( read, 0 ) ) { - read_destroy( read ); - return( -1 ); - } - - read_destroy( read ); - - return( 0 ); -} - -#endif /*HAVE_PNG*/ diff --git a/libsrc/conversion/im_ppm2vips.c b/libsrc/conversion/im_ppm2vips.c deleted file mode 100644 index 2e188dc8..00000000 --- a/libsrc/conversion/im_ppm2vips.c +++ /dev/null @@ -1,440 +0,0 @@ -/* Read a ppm file. - * - * Stephen Chan ... original code - * - * 21/11/00 JC - * - hacked for VIPS - * - reads ppm/pgm/pbm - * - mmaps binary pgm/ppm - * - reads all ascii formats (slowly!) - * 22/11/00 JC - * - oops, ascii read was broken - * - does 16/32 bit ascii now as well - * 24/5/01 - * - im_ppm2vips_header() added - * 22/5/04 - * - does 16/32 bit binary too - * - tiny fix for missing file close on read error - * 19/8/05 - * - use im_raw2vips() for binary read - * 9/9/05 - * - tiny cleanups - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* The largest number/field/whatever we can read. - */ -#define IM_MAX_THING (80) - -static void -skip_line( FILE *fp ) -{ - int ch; - - while( (ch = fgetc( fp )) != '\n' ) - ; -} - -static void -skip_white_space( FILE *fp ) -{ - int ch; - - while( isspace( ch = fgetc( fp ) ) ) - ; - ungetc( ch, fp ); - - if( ch == '#' ) { - skip_line( fp ); - skip_white_space( fp ); - } -} - -static int -read_uint( FILE *fp ) -{ - int i; - char buf[IM_MAX_THING]; - int ch; - - skip_white_space( fp ); - - /* Stop complaints about used-before-set on ch. - */ - ch = -1; - - for( i = 0; i < IM_MAX_THING - 1 && isdigit( ch = fgetc( fp ) ); i++ ) - buf[i] = ch; - buf[i] = '\0'; - - if( i == 0 ) { - im_error( "im_ppm2vips", _( "bad unsigned int" ) ); - return( -1 ); - } - - ungetc( ch, fp ); - - return( atoi( buf ) ); -} - -static int -read_header( FILE *fp, IMAGE *out, int *bits, int *ascii ) -{ - int width, height, bands, fmt, type; - int i; - char buf[IM_MAX_THING]; - int max_value; - - /* ppm types. - */ - static char *magic_names[] = { - "P1", /* pbm ... 1 band 1 bit, ascii */ - "P2", /* pgm ... 1 band many bit, ascii */ - "P3", /* ppm ... 3 band many bit, ascii */ - "P4", /* pbm ... 1 band 1 bit, binary */ - "P5", /* pgm ... 1 band 8 bit, binary */ - "P6" /* ppm ... 3 band 8 bit, binary */ - }; - - /* Characteristics, indexed by ppm type. - */ - static int lookup_bits[] = { - 1, 8, 8, 1, 8, 8 - }; - static int lookup_bands[] = { - 1, 1, 3, 1, 1, 3 - }; - static int lookup_ascii[] = { - 1, 1, 1, 0, 0, 0 - }; - - /* Read in the magic number. - */ - buf[0] = fgetc( fp ); - buf[1] = fgetc( fp ); - buf[2] = '\0'; - - for( i = 0; i < IM_NUMBER( magic_names ); i++ ) - if( strcmp( magic_names[i], buf ) == 0 ) - break; - if( i == IM_NUMBER( magic_names ) ) { - im_error( "im_ppm2vips", _( "bad magic number" ) ); - return( -1 ); - } - *bits = lookup_bits[i]; - bands = lookup_bands[i]; - *ascii = lookup_ascii[i]; - - /* Read in size. - */ - if( (width = read_uint( fp )) < 0 || - (height = read_uint( fp )) < 0 ) - return( -1 ); - - /* Read in max value for >1 bit images. - */ - if( *bits > 1 ) { - if( (max_value = read_uint( fp )) < 0 ) - return( -1 ); - - if( max_value > 255 ) - *bits = 16; - if( max_value > 65535 ) - *bits = 32; - } - - /* For binary images, there is always exactly 1 more whitespace - * character before the data starts. - */ - if( !*ascii && !isspace( fgetc( fp ) ) ) { - im_error( "im_ppm2vips", - _( "not whitespace before start of binary data" ) ); - return( -1 ); - } - - /* Choose a VIPS bandfmt. - */ - switch( *bits ) { - case 1: - case 8: - fmt = IM_BANDFMT_UCHAR; - break; - - case 16: - fmt = IM_BANDFMT_USHORT; - break; - - case 32: - fmt = IM_BANDFMT_UINT; - break; - - default: - assert( 0 ); - } - - if( bands == 1 ) { - if( fmt == IM_BANDFMT_USHORT ) - type = IM_TYPE_GREY16; - else - type = IM_TYPE_B_W; - } - else { - if( fmt == IM_BANDFMT_USHORT ) - type = IM_TYPE_RGB16; - else if( fmt == IM_BANDFMT_UINT ) - type = IM_TYPE_RGB; - else - type = IM_TYPE_sRGB; - } - - im_initdesc( out, width, height, bands, (*bits == 1) ? 8 : *bits, fmt, - IM_CODING_NONE, - type, - 1.0, 1.0, - 0, 0 ); - - return( 0 ); -} - -/* Read a ppm/pgm file using mmap(). - */ -static int -read_mmap( FILE *fp, const char *filename, IMAGE *out ) -{ - const int header_offset = ftell( fp ); - IMAGE *t[2]; - im_arch_type arch = im_amiMSBfirst() ? - IM_ARCH_NATIVE : IM_ARCH_BYTE_SWAPPED; - - if( im_open_local_array( out, t, 2, "im_ppm2vips", "p" ) || - im_raw2vips( filename, t[0], - out->Xsize, out->Ysize, - IM_IMAGE_SIZEOF_PEL( out ), header_offset ) || - im_copy_morph( t[0], t[1], - out->Bands, out->BandFmt, out->Coding ) || - im_copy_from( t[1], out, arch ) ) - return( -1 ); - - return( 0 ); -} - -/* Read an ascii ppm/pgm file. - */ -static int -read_ascii( FILE *fp, IMAGE *out ) -{ - int x, y; - PEL *buf; - - if( im_outcheck( out ) || im_setupout( out ) || - !(buf = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ) - return( -1 ); - - for( y = 0; y < out->Ysize; y++ ) { - for( x = 0; x < out->Xsize * out->Bands; x++ ) { - int val; - - if( (val = read_uint( fp )) < 0 ) - return( -1 ); - - switch( out->BandFmt ) { - case IM_BANDFMT_UCHAR: - buf[x] = IM_CLIP( 0, val, 255 ); - break; - - case IM_BANDFMT_USHORT: - ((unsigned short *) buf)[x] = - IM_CLIP( 0, val, 65535 ); - break; - - case IM_BANDFMT_UINT: - ((unsigned int *) buf)[x] = val; - break; - - default: - assert( 0 ); - } - } - - if( im_writeline( y, out, buf ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Read an ascii 1 bit file. - */ -static int -read_1bit_ascii( FILE *fp, IMAGE *out ) -{ - int x, y; - PEL *buf; - - if( im_outcheck( out ) || im_setupout( out ) || - !(buf = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ) - return( -1 ); - - for( y = 0; y < out->Ysize; y++ ) { - for( x = 0; x < out->Xsize * out->Bands; x++ ) { - int val; - - if( (val = read_uint( fp )) < 0 ) - return( -1 ); - - if( val == 1 ) - buf[x] = 0; - else - buf[x] = 255; - } - - if( im_writeline( y, out, buf ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Read a 1 bit binary file. - */ -static int -read_1bit_binary( FILE *fp, IMAGE *out ) -{ - int x, y, i; - int bits; - PEL *buf; - - if( im_outcheck( out ) || im_setupout( out ) || - !(buf = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ) - return( -1 ); - - bits = fgetc( fp ); - for( i = 0, y = 0; y < out->Ysize; y++ ) { - for( x = 0; x < out->Xsize * out->Bands; x++, i++ ) { - buf[x] = (bits & 128) ? 255 : 0; - bits <<= 1; - if( (i & 7) == 7 ) - bits = fgetc( fp ); - } - - if( im_writeline( y, out, buf ) ) - return( -1 ); - } - - return( 0 ); -} - -static int -parse_ppm( FILE *fp, const char *filename, IMAGE *out ) -{ - int bits; - int ascii; - - if( read_header( fp, out, &bits, &ascii ) ) - return( -1 ); - - /* What sort of read are we doing? - */ - if( !ascii && bits >= 8 ) - return( read_mmap( fp, filename, out ) ); - else if( !ascii && bits == 1 ) - return( read_1bit_binary( fp, out ) ); - else if( ascii && bits == 1 ) - return( read_1bit_ascii( fp, out ) ); - else - return( read_ascii( fp, out ) ); -} - -int -im_ppm2vips_header( const char *filename, IMAGE *out ) -{ - FILE *fp; - int bits; - int ascii; - -#ifdef BINARY_OPEN - if( !(fp = fopen( filename, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(fp = fopen( filename, "r" )) ) { -#endif /*BINARY_OPEN*/ - im_error( "im_ppm2vips_header", - _( "unable to open \"%s\"" ), filename ); - return( -1 ); - } - - if( read_header( fp, out, &bits, &ascii ) ) { - fclose( fp ); - return( -1 ); - } - - fclose( fp ); - - return( 0 ); -} - -int -im_ppm2vips( const char *filename, IMAGE *out ) -{ - FILE *fp; - -#ifdef BINARY_OPEN - if( !(fp = fopen( filename, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(fp = fopen( filename, "r" )) ) { -#endif /*BINARY_OPEN*/ - im_error( "im_ppm2vips", - _( "unable to open \"%s\"" ), filename ); - return( -1 ); - } - - if( parse_ppm( fp, filename, out ) ) { - fclose( fp ); - return( -1 ); - } - - fclose( fp ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_raw2vips.c b/libsrc/conversion/im_raw2vips.c deleted file mode 100644 index e8f50605..00000000 --- a/libsrc/conversion/im_raw2vips.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Read raw image. Just a wrapper over im_binfile(). - * - * 3/8/05 - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -int -im_raw2vips( const char *filename, IMAGE *out, - int width, int height, int bpp, int offset ) -{ - IMAGE *t; - - if( !(t = im_binfile( filename, width, height, bpp, offset )) ) - return( -1 ); - if( im_add_close_callback( out, - (im_callback_fn) im_close, t, NULL ) ) { - im_close( t ); - return( -1 ); - } - if( im_copy( t, out ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_tiff2vips.c b/libsrc/conversion/im_tiff2vips.c deleted file mode 100644 index 213e11c7..00000000 --- a/libsrc/conversion/im_tiff2vips.c +++ /dev/null @@ -1,1467 +0,0 @@ -/* TIFF parts: Copyright (c) 1988, 1990 by Sam Leffler. - * All rights reserved. - * - * This file is provided for unrestricted use provided that this - * legend is included on all tape media and as a part of the - * software program in whole or part. Users may copy, modify or - * distribute this file at will. - * ----------------------------- - * Modifications for VIPS: Kirk Martinez 1994 - * 22/11/94 JC - * - more general - * - memory leaks fixed - * 20/3/95 JC - * - TIFF error handler added - * - read errors detected correctly - * - * Modified to handle LAB in tiff format. - * It convert LAB-tiff format to IM_TYPE_LABQ in vips format. - * Copyright July-1995 Ahmed Abbood. - * - * - * 19/9/95 JC - * - now calls TIFFClose ... stupid - * 25/1/96 JC - * - typo on MINISBLACK ... - * 7/4/97 JC - * - completely redone for TIFF 6 - * - now full baseline TIFF 6 reader, and does CIELAB as well - * 11/4/97 JC - * - added partial read for tiled images - * 23/4/97 JC - * - extra subsample parameter - * - im_istiffpyramid() added - * 5/12/97 JC - * - if loading YCbCr, convert to IM_CODING_LABQ - * 1/5/98 JC - * - now reads 16-bit greyscale and RGB - * 26/10/98 JC - * - now used "rb" mode on systems that need binary open - * 12/11/98 JC - * - no sub-sampling if sub == 1 - * 26/2/99 JC - * - ooops, else missing for subsample stuff above - * 2/10/99 JC - * - tiled 16-bit greyscale read was broken - * - added mutex for TIFFReadTile() calls - * 11/5/00 JC - * - removed TIFFmalloc/TIFFfree usage - * 23/4/01 JC - * - HAVE_TIFF turns on TIFF goodness - * 24/5/01 JC - * - im_tiff2vips_header() added - * 11/7/01 JC - * - subsample now in input filename - * - ... and it's a page number (from 0) instead - * 21/8/02 JC - * - now reads CMYK - * - hmm, dpi -> ppm conversion was wrong! - * 10/9/02 JC - * - oops, handle TIFF errors better - * 2/12/02 JC - * - reads 8-bit RGBA - * 12/12/02 JC - * - reads 16-bit LAB - * 13/2/03 JC - * - pixels/cm res read was wrong - * 17/11/03 Andrey Kiselev - * - read 32-bit float greyscale and rgb - * 5/4/04 - * - better handling of edge tiles (thanks Ruven) - * 16/4/04 - * - cleanup - * - added broken tile read mode - * 18/5/04 Andrey Kiselev - * - better no resolution diagnostic - * 26/5/04 - * - reads 16 bit RGBA - * 28/7/04 - * - arrg, 16bit RGB was broken, thanks haida - * 26/11/04 - * - add a TIFF warning handler, stops occasional libMagick exceptions - * 9/3/05 - * - load 32-bit float LAB - * 8/4/05 - * - onebit read no longer reads one byte too many on multiple of 8 wide - * images - * 22/6/05 - * - 16 bit LAB read was broken - * 9/9/05 - * - read any ICCPROFILE tag - * 8/5/06 - * - set RGB16 and GREY16 Type - * 21/5/06 - * - use external im_tile_cache() operation for great code shrinkage - * - less RAM usage too, esp. with >1 CPU - * - should be slightly faster - * - removed 'broken' read option - * 18/7/07 Andrey Kiselev - * - remove "b" option on TIFFOpen() - * 9/4/08 - * - set IM_META_RESOLUTION_UNIT - * 17/4/08 - * - allow CMYKA (thanks Doron) - * 17/7/08 - * - convert YCbCr to RGB on read - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* Turn on debugging output. -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_TIFF - -#include - -int -im_tiff2vips( const char *tiffile, IMAGE *im ) -{ - im_error( "im_tiff2vips", _( "TIFF support disabled" ) ); - return( -1 ); -} - -int -im_istiffpyramid( const char *name ) -{ - return( 0 ); -} - -int -im_tiff2vips_header( const char *tiffile, IMAGE *im ) -{ - im_error( "im_tiff2vips", _( "TIFF support disabled" ) ); - return( -1 ); -} - -#else /*HAVE_TIFF*/ - -#include -#include -#include -#include - -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Scanline-type process function. - */ -typedef void (*scanline_process_fn)( PEL *q, PEL *p, int n, void *user ); - -/* Stuff we track during a read. - */ -typedef struct { - /* Parameters. - */ - char *filename; - IMAGE *out; - - /* From filename. - */ - int page; - - /* The TIFF we read. - */ - TIFF *tiff; - - /* Process for this image type. - */ - scanline_process_fn sfn; - void *client; - - /* Geometry. - */ - int twidth, theight; /* Tile size */ - - /* Only need one of these, since we mutex around TIFF*(). - */ - GMutex *tlock; /* Lock for TIFF*() calls */ -} ReadTiff; - -/* Reading a YCbCr image ... parameters we use for conversion. - */ -typedef struct { - /* Input and output. - */ - TIFF *tif; /* From here */ - IMAGE *im; /* To here */ - - /* RGB <-> YCbCr conversion. - */ - float LumaRed, LumaGreen, LumaBlue; - - /* RGB -> LAB conversion. - */ - void *table; -} YCbCrParams; - -/* Handle TIFF errors here. Shared with im_vips2tiff. These can be called from - * more than one thread, but im_error and im_warn have mutexes in, so that's - * OK. - */ -void -im__thandler_error( char *module, char *fmt, va_list ap ) -{ - im_verror( module, fmt, ap ); -} - -void -im__thandler_warning( char *module, char *fmt, va_list ap ) -{ - char buf[256]; - - im_vsnprintf( buf, 256, fmt, ap ); - im_warn( module, "%s", buf ); -} - -/* Test for field exists. - */ -static int -tfexists( TIFF *tif, ttag_t tag ) -{ - uint32 a, b; - - if( TIFFGetField( tif, tag, &a, &b ) ) - return( 1 ); - else - return( 0 ); -} - -/* Test a uint16 field. Field must be defined and equal to the value. - */ -static int -tfequals( TIFF *tif, ttag_t tag, uint16 val ) -{ - uint16 fld; - - if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) { - im_error( "im_tiff2vips", - _( "required field %d missing" ), tag ); - return( 0 ); - } - if( fld != val ) { - im_error( "im_tiff2vips", _( "required field %d=%d, not %d" ), - tag, fld, val ); - return( 0 ); - } - - /* All ok. - */ - return( 1 ); -} - -/* Get a uint32 field. - */ -static int -tfget32( TIFF *tif, ttag_t tag, int *out ) -{ - uint32 fld; - - if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) { - im_error( "im_tiff2vips", - _( "required field %d missing" ), tag ); - return( 0 ); - } - - /* All ok. - */ - *out = fld; - return( 1 ); -} - -/* Get a uint16 field. - */ -static int -tfget16( TIFF *tif, ttag_t tag, int *out ) -{ - uint16 fld; - - if( !TIFFGetFieldDefaulted( tif, tag, &fld ) ) { - im_error( "im_tiff2vips", - _( "required field %d missing" ), tag ); - return( 0 ); - } - - /* All ok. - */ - *out = fld; - return( 1 ); -} - -/* Per-scanline process function for IM_CODING_LABQ. - */ -static void -labpack_line( PEL *q, PEL *p, int n, void *dummy ) -{ - int x; - - for( x = 0; x < n; x++ ) { - q[0] = p[0]; - q[1] = p[1]; - q[2] = p[2]; - q[3] = 0; - - q += 4; - p += 3; - } -} - -/* Read an 8-bit LAB image. - */ -static int -parse_labpack( ReadTiff *rtiff, IMAGE *out ) -{ - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 3 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ) - return( -1 ); - - out->Bands = 4; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_LABQ; - out->Type = IM_TYPE_LAB; - - rtiff->sfn = labpack_line; - rtiff->client = NULL; - - return( 0 ); -} - -/* Per-scanline process function for IM_CODING_LABQ. - */ -static void -labs_line( PEL *q, PEL *p, int n, void *dummy ) -{ - int x; - unsigned short *p1 = (unsigned short *) p; - short *q1 = (short *) q; - - for( x = 0; x < n; x++ ) { - q1[0] = p1[0] >> 1; - q1[1] = p1[1]; - q1[2] = p1[2]; - - q1 += 3; - p1 += 3; - } -} - -/* Read a 16-bit LAB image. - */ -static int -parse_labs( ReadTiff *rtiff, IMAGE *out ) -{ - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 3 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) ) - return( -1 ); - - out->Bands = 3; - out->Bbits = 16; - out->BandFmt = IM_BANDFMT_SHORT; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_LABS; - - rtiff->sfn = labs_line; - rtiff->client = NULL; - - return( 0 ); -} - -/* Per-scanline process function for 1 bit images. - */ -static void -onebit_line( PEL *q, PEL *p, int n, void *flg ) -{ - /* Extract PHOTOMETRIC_INTERPRETATION. - */ - int pm = *((int *) flg); - int x, i, z; - PEL bits; - - int black = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 255; - int white = black ^ -1; - - /* (sigh) how many times have I written this? - */ - for( x = 0, i = 0; i < (n >> 3); i++ ) { - bits = (PEL) p[i]; - - for( z = 0; z < 8; z++, x++ ) { - q[x] = (bits & 128) ? white : black; - bits <<= 1; - } - } - - /* Do last byte in line. - */ - if( n & 7 ) { - bits = p[i]; - for( z = 0; z < (n & 7); z++ ) { - q[x + z] = (bits & 128) ? white : black; - bits <<= 1; - } - } -} - -/* Read a 1-bit TIFF image. Pass in pixel values to use for black and white. - */ -static int -parse_onebit( ReadTiff *rtiff, int pm, IMAGE *out ) -{ - int *ppm; - - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 1 ) ) - return( -1 ); - - out->Bands = 1; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_B_W; - - /* Note pm for later. - */ - if( !(ppm = IM_ARRAY( out, 1, int )) ) - return( -1 ); - *ppm = pm; - - rtiff->sfn = onebit_line; - rtiff->client = ppm; - - return( 0 ); -} - -/* Per-scanline process function for 8-bit greyscale images. - */ -static void -greyscale8_line( PEL *q, PEL *p, int n, void *flg ) -{ - /* Extract swap mask. - */ - PEL mask = *((PEL *) flg); - int x; - - /* Read bytes, swapping sense if necessary. - */ - for( x = 0; x < n; x++ ) - q[x] = p[x] ^ mask; -} - -/* Read a 8-bit grey-scale TIFF image. - */ -static int -parse_greyscale8( ReadTiff *rtiff, int pm, IMAGE *out ) -{ - PEL *mask; - - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ) - return( -1 ); - - /* Eor each pel with this later. - */ - if( !(mask = IM_ARRAY( out, 1, PEL )) ) - return( -1 ); - *mask = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 255; - - out->Bands = 1; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_B_W; - - rtiff->sfn = greyscale8_line; - rtiff->client = mask; - - return( 0 ); -} - -/* Per-scanline process function for 16-bit greyscale images. - */ -static void -greyscale16_line( PEL *q, PEL *p, int n, void *flg ) -{ - /* Extract swap mask. - */ - unsigned short mask = *((unsigned short *) flg); - unsigned short *p1 = (unsigned short *) p; - unsigned short *q1 = (unsigned short *) q; - int x; - - /* Read bytes, swapping sense if necessary. - */ - for( x = 0; x < n; x++ ) - q1[x] = p1[x] ^ mask; -} - -/* Read a 16-bit grey-scale TIFF image. - */ -static int -parse_greyscale16( ReadTiff *rtiff, int pm, IMAGE *out ) -{ - unsigned short *mask; - - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) ) - return( -1 ); - - /* Eor each pel with this later. - */ - if( !(mask = IM_ARRAY( out, 1, unsigned short )) ) - return( -1 ); - mask[0] = (pm == PHOTOMETRIC_MINISBLACK) ? 0 : 65535; - - out->Bands = 1; - out->Bbits = 16; - out->BandFmt = IM_BANDFMT_USHORT; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_GREY16; - - rtiff->sfn = greyscale16_line; - rtiff->client = mask; - - return( 0 ); -} - -/* Per-scanline process function for 32-bit floating point greyscale images. - */ -static void -greyscale32f_line( PEL *q, PEL *p, int n ) -{ - float *p1 = (float *) p; - float *q1 = (float *) q; - int x; - - for( x = 0; x < n; x++ ) - q1[x] = p1[x]; -} - -/* Read a 32-bit floating point greyscale TIFF image. What do we do about - * MINISWHITE/MINISBLACK (pm)? Not sure ... just ignore it. - */ -static int -parse_greyscale32f( ReadTiff *rtiff, int pm, IMAGE *out ) -{ - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) ) - return( -1 ); - - out->Bands = 1; - out->Bbits = 32; - out->BandFmt = IM_BANDFMT_FLOAT; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_B_W; - - rtiff->sfn = (scanline_process_fn) greyscale32f_line; - rtiff->client = NULL; - - return( 0 ); -} - -/* Per-scanline process function for palette images. - */ -static void -palette_line( PEL *q, PEL *p, int n, void *flg ) -{ - /* Extract maps. - */ - PEL *red = ((PEL **) flg)[0]; - PEL *green = ((PEL **) flg)[1]; - PEL *blue = ((PEL **) flg)[2]; - int x; - - /* Read bytes, generating colour. - */ - for( x = 0; x < n; x++ ) { - int i = *p++; - - q[0] = red[i]; - q[1] = green[i]; - q[2] = blue[i]; - - q += 3; - } -} - -/* Read a palette-ised TIFF image. Again, we only allow 8-bits for now. - */ -static int -parse_palette( ReadTiff *rtiff, IMAGE *out ) -{ - uint16 *tred, *tgreen, *tblue; - PEL *red, *green, *blue; - PEL **maps; - int i; - - if( !tfequals( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) ) - return( -1 ); - - /* Allocate mem for VIPS colour maps. - */ - if( !(red = IM_ARRAY( out, 256, PEL )) || - !(green = IM_ARRAY( out, 256, PEL )) || - !(blue = IM_ARRAY( out, 256, PEL )) || - !(maps = IM_ARRAY( out, 3, PEL * )) ) - return( -1 ); - - /* Get maps, convert to 8-bit data. - */ - if( !TIFFGetField( rtiff->tiff, - TIFFTAG_COLORMAP, &tred, &tgreen, &tblue ) ) { - im_error( "im_tiff2vips", _( "bad colormap" ) ); - return( -1 ); - } - for( i = 0; i < 256; i++ ) { - red[i] = tred[i] >> 8; - green[i] = tgreen[i] >> 8; - blue[i] = tblue[i] >> 8; - } - maps[0] = red; - maps[1] = green; - maps[2] = blue; - - out->Bands = 3; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_sRGB; - - rtiff->sfn = palette_line; - rtiff->client = maps; - - return( 0 ); -} - -/* Per-scanline process function for 8-bit RGB/RGBA/CMYK/CMYKA/etc. - */ -static void -rgbcmyk8_line( PEL *q, PEL *p, int n, IMAGE *im ) -{ - int x, b; - - for( x = 0; x < n; x++ ) { - for( b = 0; b < im->Bands; b++ ) - q[b] = p[b]; - - q += im->Bands; - p += im->Bands; - } -} - -/* Read an 8-bit RGB/RGBA image. - */ -static int -parse_rgb8( ReadTiff *rtiff, IMAGE *out ) -{ - int bands; - - /* Check other TIFF fields to make sure we can read this. Can have 4 - * bands for RGBA. - */ - if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) || - !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) - return( -1 ); - if( bands != 3 && bands != 4 ) { - im_error( "im_tiff2vips", _( "3 or 4 bands RGB TIFF only" ) ); - return( -1 ); - } - - out->Bands = bands; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_sRGB; - - rtiff->sfn = (scanline_process_fn) rgbcmyk8_line; - rtiff->client = out; - - return( 0 ); -} - -/* Per-scanline process function for RGB/RGBA 16. - */ -static void -rgb16_line( PEL *q, PEL *p, int n, IMAGE *im ) -{ - int x, b; - unsigned short *p1 = (unsigned short *) p; - unsigned short *q1 = (unsigned short *) q; - - for( x = 0; x < n; x++ ) { - for( b = 0; b < im->Bands; b++ ) - q1[b] = p1[b]; - - q1 += im->Bands; - p1 += im->Bands; - } -} - -/* Read a 16-bit RGB/RGBA image. - */ -static int -parse_rgb16( ReadTiff *rtiff, IMAGE *out ) -{ - int bands; - - /* Check other TIFF fields to make sure we can read this. Can have 4 - * bands for RGBA. - */ - if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 16 ) || - !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) - return( -1 ); - if( bands != 3 && bands != 4 ) { - im_error( "im_tiff2vips", _( "3 or 4 bands RGB TIFF only" ) ); - return( -1 ); - } - - out->Bands = bands; - out->Bbits = 16; - out->BandFmt = IM_BANDFMT_USHORT; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_RGB16; - - rtiff->sfn = (scanline_process_fn) rgb16_line; - rtiff->client = out; - - return( 0 ); -} - -/* Per-scanline process function for 32f. - */ -static void -r32f_line( PEL *q, PEL *p, int n, void *dummy ) -{ - int x; - float *p1 = (float *) p; - float *q1 = (float *) q; - - for( x = 0; x < n; x++ ) { - q1[0] = p1[0]; - q1[1] = p1[1]; - q1[2] = p1[2]; - - q1 += 3; - p1 += 3; - } -} - -/* Read a 32-bit float image. RGB or LAB, with or without alpha. - */ -static int -parse_32f( ReadTiff *rtiff, int pm, IMAGE *out ) -{ - int bands; - - if( !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) || - !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 32 ) ) - return( -1 ); - - /* Can be 4 for images with an alpha channel. - */ - assert( bands == 3 || bands == 4 ); - - out->Bands = bands; - out->Bbits = 32; - out->BandFmt = IM_BANDFMT_FLOAT; - out->Coding = IM_CODING_NONE; - - switch( pm ) { - case PHOTOMETRIC_CIELAB: - out->Type = IM_TYPE_LAB; - break; - - case PHOTOMETRIC_RGB: - out->Type = IM_TYPE_sRGB; - break; - - default: - assert( 0 ); - } - - rtiff->sfn = r32f_line; - rtiff->client = NULL; - - return( 0 ); -} - -/* Read a CMYK image. - */ -static int -parse_cmyk( ReadTiff *rtiff, IMAGE *out ) -{ - int bands; - - /* Check other TIFF fields to make sure we can read this. Can have 5 - * bands for CMYKA. - */ - if( !tfequals( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, 8 ) || - !tfequals( rtiff->tiff, TIFFTAG_INKSET, INKSET_CMYK ) || - !tfget16( rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &bands ) ) - return( -1 ); - if( bands != 4 && bands != 5 ) { - im_error( "im_tiff2vips", _( "4 or 5 bands CMYK TIFF only" ) ); - return( -1 ); - } - - out->Bands = bands; - out->Bbits = 8; - out->BandFmt = IM_BANDFMT_UCHAR; - out->Coding = IM_CODING_NONE; - out->Type = IM_TYPE_CMYK; - - rtiff->sfn = (scanline_process_fn) rgbcmyk8_line; - rtiff->client = out; - - return( 0 ); -} - -/* Read resolution from a TIFF image. - */ -static int -parse_resolution( TIFF *tiff, IMAGE *out ) -{ - float x, y; - int ru; - - if( TIFFGetFieldDefaulted( tiff, TIFFTAG_XRESOLUTION, &x ) && - TIFFGetFieldDefaulted( tiff, TIFFTAG_YRESOLUTION, &y ) && - tfget16( tiff, TIFFTAG_RESOLUTIONUNIT, &ru ) ) { - switch( ru ) { - case RESUNIT_NONE: - break; - - case RESUNIT_INCH: - /* In pixels-per-inch ... convert to mm. - */ - x /= 10.0 * 2.54; - y /= 10.0 * 2.54; - im_meta_set_string( out, - IM_META_RESOLUTION_UNIT, "in" ); - break; - - case RESUNIT_CENTIMETER: - /* In pixels-per-centimetre ... convert to mm. - */ - x /= 10.0; - y /= 10.0; - im_meta_set_string( out, - IM_META_RESOLUTION_UNIT, "cm" ); - break; - - default: - im_error( "im_tiff2vips", - _( "unknown resolution unit" ) ); - return( -1 ); - } - } - else { - im_warn( "im_tiff2vips", _( "no resolution information for " - "TIFF image \"%s\" -- defaulting to 1 pixel per mm" ), - TIFFFileName( tiff ) ); - x = 1.0; - y = 1.0; - } - - out->Xres = x; - out->Yres = y; - - return( 0 ); -} - -/* Look at PhotometricInterpretation and BitsPerPixel, and try to figure out - * which of the image classes this is. - */ -static int -parse_header( ReadTiff *rtiff, IMAGE *out ) -{ - int pm, bps, format; - uint32 data_length; - void *data; - - /* Ban separate planes, too annoying. - */ - if( tfexists( rtiff->tiff, TIFFTAG_PLANARCONFIG ) && - !tfequals( rtiff->tiff, - TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ) ) - return( -1 ); - - /* Always need dimensions. - */ - if( !tfget32( rtiff->tiff, TIFFTAG_IMAGEWIDTH, &out->Xsize ) || - !tfget32( rtiff->tiff, TIFFTAG_IMAGELENGTH, &out->Ysize ) || - parse_resolution( rtiff->tiff, out ) ) - return( -1 ); - - /* Try to find out which type of TIFF image it is. - */ - if( !tfget16( rtiff->tiff, TIFFTAG_PHOTOMETRIC, &pm ) || - !tfget16( rtiff->tiff, TIFFTAG_BITSPERSAMPLE, &bps ) ) - return( -1 ); - - switch( pm ) { - case PHOTOMETRIC_CIELAB: - switch( bps ) { - case 8: - if( parse_labpack( rtiff, out ) ) - return( -1 ); - break; - - case 16: - if( parse_labs( rtiff, out ) ) - return( -1 ); - break; - - case 32: - if( !tfget16( rtiff->tiff, - TIFFTAG_SAMPLEFORMAT, &format ) ) - return( -1 ); - - if( format == SAMPLEFORMAT_IEEEFP ) { - if( parse_32f( rtiff, pm, out ) ) - return( -1 ); - } - else { - im_error( "im_tiff2vips", - _( "unsupported sample " - "format %d for lab image" ), - format ); - return( -1 ); - } - - break; - - default: - im_error( "im_tiff2vips", - _( "unsupported depth %d for LAB image" ), - bps ); - return( -1 ); - } - - break; - - case PHOTOMETRIC_MINISWHITE: - case PHOTOMETRIC_MINISBLACK: - switch( bps ) { - case 1: - if( parse_onebit( rtiff, pm, out ) ) - return( -1 ); - - break; - - case 8: - if( parse_greyscale8( rtiff, pm, out ) ) - return( -1 ); - - break; - - case 16: - if( parse_greyscale16( rtiff, pm, out ) ) - return( -1 ); - - break; - - case 32: - if( !tfget16( rtiff->tiff, - TIFFTAG_SAMPLEFORMAT, &format ) ) - return( -1 ); - - if( format == SAMPLEFORMAT_IEEEFP ) { - if( parse_greyscale32f( rtiff, pm, out ) ) - return( -1 ); - } - else { - im_error( "im_tiff2vips", - _( "unsupported sample format " - "%d for greyscale image" ), - format ); - return( -1 ); - } - - break; - - default: - im_error( "im_tiff2vips", _( "unsupported depth %d " - "for greyscale image" ), bps ); - return( -1 ); - } - - break; - - case PHOTOMETRIC_PALETTE: - /* Full colour pallette. - */ - if( parse_palette( rtiff, out ) ) - return( -1 ); - - break; - - case PHOTOMETRIC_YCBCR: - /* Sometimes JPEG in TIFF images are tagged as YCBCR. Ask - * libtiff to convert to RGB for us. - */ - TIFFSetField( rtiff->tiff, - TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); - if( parse_rgb8( rtiff, out ) ) - return( -1 ); - break; - - case PHOTOMETRIC_RGB: - /* RGB. - */ - switch( bps ) { - case 8: - if( parse_rgb8( rtiff, out ) ) - return( -1 ); - break; - - case 16: - if( parse_rgb16( rtiff, out ) ) - return( -1 ); - break; - - case 32: - if( !tfget16( rtiff->tiff, - TIFFTAG_SAMPLEFORMAT, &format ) ) - return( -1 ); - - if( format == SAMPLEFORMAT_IEEEFP ) { - if( parse_32f( rtiff, pm, out ) ) - return( -1 ); - } - else { - im_error( "im_tiff2vips", - _( "unsupported sample " - "format %d for rgb image" ), - format ); - return( -1 ); - } - - break; - - default: - im_error( "im_tiff2vips", _( "unsupported depth %d " - "for RGB image" ), bps ); - return( -1 ); - } - - break; - - case PHOTOMETRIC_SEPARATED: - if( parse_cmyk( rtiff, out ) ) - return( -1 ); - - break; - - default: - im_error( "im_tiff2vips", _( "unknown photometric " - "interpretation %d" ), pm ); - return( -1 ); - } - - /* Read any ICC profile. - */ - if( TIFFGetField( rtiff->tiff, - TIFFTAG_ICCPROFILE, &data_length, &data ) ) { - void *data_copy; - - if( !(data_copy = im_malloc( NULL, data_length )) ) - return( -1 ); - memcpy( data_copy, data, data_length ); - if( im_meta_set_blob( out, IM_META_ICC_NAME, - (im_callback_fn) im_free, data_copy, data_length ) ) { - im_free( data_copy ); - return( -1 ); - } - } - - return( 0 ); -} - -/* Allocate a tile buffer. Have one of these for each thread so we can unpack - * to vips in parallel. - */ -static void * -seq_start( IMAGE *out, void *a, void *b ) -{ - ReadTiff *rtiff = (ReadTiff *) a; - tdata_t *buf; - - if( !(buf = im_malloc( NULL, TIFFTileSize( rtiff->tiff ) )) ) - return( NULL ); - - return( (void *) buf ); -} - -/* Loop over the output region, painting in tiles from the file. - */ -static int -fill_region( REGION *out, void *seq, void *a, void *b ) -{ - tdata_t *buf = (tdata_t *) seq; - ReadTiff *rtiff = (ReadTiff *) a; - Rect *r = &out->valid; - - /* Find top left of tiles we need. - */ - int xs = (r->left / rtiff->twidth) * rtiff->twidth; - int ys = (r->top / rtiff->theight) * rtiff->theight; - - /* Sizeof a line of bytes in the TIFF tile. - */ - int tls = TIFFTileSize( rtiff->tiff ) / rtiff->theight; - - /* Sizeof a pel in the TIFF file. This won't work for formats which - * are <1 byte per pel, like onebit :-( Fortunately, it's only used - * to calculate addresses within a tile, and because we are wrapped in - * im_tile_cache(), we will never have to calculate positions within a - * tile. - */ - int tps = tls / rtiff->twidth; - - int x, y, z; - - for( y = ys; y < IM_RECT_BOTTOM( r ); y += rtiff->theight ) - for( x = xs; x < IM_RECT_RIGHT( r ); x += rtiff->twidth ) { - Rect tile; - Rect hit; - - /* Read that tile. - */ - g_mutex_lock( rtiff->tlock ); - if( TIFFReadTile( rtiff->tiff, buf, - x, y, 0, 0 ) < 0 ) { - g_mutex_unlock( rtiff->tlock ); - return( -1 ); - } - g_mutex_unlock( rtiff->tlock ); - - /* The tile we read. - */ - tile.left = x; - tile.top = y; - tile.width = rtiff->twidth; - tile.height = rtiff->twidth; - - /* The section that hits the region we are building. - */ - im_rect_intersectrect( &tile, r, &hit ); - - /* Unpack to VIPS format. We can do this in parallel. - * Just unpack the section of the tile we need. - */ - for( z = 0; z < hit.height; z++ ) { - PEL *p = (PEL *) buf + - (hit.left - tile.left) * tps + - (hit.top - tile.top + z) * tls; - PEL *q = (PEL *) IM_REGION_ADDR( out, - hit.left, hit.top + z ); - - rtiff->sfn( q, p, hit.width, rtiff->client ); - } - } - - return( 0 ); -} - -static int -seq_stop( void *seq, void *a, void *b ) -{ - im_free( seq ); - - return( 0 ); -} - -/* Tile-type TIFF reader core - pass in a per-tile transform. Generate into - * the im and do it all partially. - */ -static int -read_tilewise( ReadTiff *rtiff, IMAGE *out ) -{ - IMAGE *raw; - - /* Tile cache: keep enough for two complete rows of tiles. - * This lets us do (smallish) area ops, like im_conv(), while - * still only hitting each TIFF tile once. - */ - if( !(raw = im_open_local( out, "cache", "p" )) ) - return( -1 ); - - /* Get tiling geometry. - */ - if( !tfget32( rtiff->tiff, TIFFTAG_TILEWIDTH, &rtiff->twidth ) || - !tfget32( rtiff->tiff, TIFFTAG_TILELENGTH, &rtiff->theight ) ) - return( -1 ); - - /* Make sure we can write PIO-style. - */ - if( im_poutcheck( raw ) ) - return( -1 ); - - /* Parse the TIFF header and set up raw. - */ - if( parse_header( rtiff, raw ) ) - return( -1 ); - - /* Process and save as VIPS. - */ - if( im_demand_hint( raw, IM_SMALLTILE, NULL ) || - im_generate( raw, - seq_start, fill_region, seq_stop, rtiff, NULL ) ) - return( -1 ); - - /* Copy to out, adding a cache. Enough tiles for two complete rows. - */ - if( im_tile_cache( raw, out, - rtiff->twidth, rtiff->theight, - 2 * (1 + raw->Xsize / rtiff->twidth) ) ) - return( -1 ); - - return( 0 ); -} - -/* Scanline-type TIFF reader core - pass in a per-scanline transform. - */ -static int -read_scanlinewise( ReadTiff *rtiff, IMAGE *out ) -{ - PEL *vbuf; - tdata_t tbuf; - int y; - - if( parse_header( rtiff, out ) ) - return( -1 ); - - /* Make sure we can write WIO-style. - */ - if( im_outcheck( out ) || im_setupout( out ) ) - return( -1 ); - - /* Make VIPS output buffer. - */ - if( !(vbuf = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( out ), PEL )) ) - return( -1 ); - - /* Make TIFF line input buffer. - */ - if( !(tbuf = im_malloc( out, TIFFScanlineSize( rtiff->tiff ) )) ) - return( -1 ); - - for( y = 0; y < out->Ysize; y++ ) { - /* Read TIFF scanline. - */ - if( TIFFReadScanline( rtiff->tiff, tbuf, y, 0 ) < 0 ) { - im_error( "im_tiff2vips", _( "read error" ) ); - return( -1 ); - } - - /* Process and save as VIPS. - */ - rtiff->sfn( vbuf, tbuf, out->Xsize, rtiff->client ); - if( im_writeline( y, out, vbuf ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Free a ReadTiff. - */ -static int -readtiff_destroy( ReadTiff *rtiff ) -{ - IM_FREEF( TIFFClose, rtiff->tiff ); - IM_FREEF( g_mutex_free, rtiff->tlock ); - - return( 0 ); -} - -/* Make a ReadTiff. - */ -static ReadTiff * -readtiff_new( const char *filename, IMAGE *out ) -{ - ReadTiff *rtiff; - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char *p, *q; - - if( !(rtiff = IM_NEW( out, ReadTiff )) ) - return( NULL ); - rtiff->filename = NULL; - rtiff->out = out; - im_filename_split( filename, name, mode ); - rtiff->filename = im_strdup( out, name ); - rtiff->page = 0; - rtiff->tiff = NULL; - rtiff->sfn = NULL; - rtiff->client = NULL; - rtiff->twidth = 0; - rtiff->theight = 0; - rtiff->tlock = g_mutex_new(); - - if( im_add_close_callback( out, - (im_callback_fn) readtiff_destroy, rtiff, NULL ) ) { - readtiff_destroy( rtiff ); - return( NULL ); - } - - /* Parse out params. - */ - p = &mode[0]; - if( (q = im_getnextoption( &p )) ) { - rtiff->page = atoi( q ); - - if( rtiff->page < 0 || rtiff->page > 1000 ) { - im_error( "im_tiff2vips", _( "bad page number %d" ), - rtiff->page ); - return( NULL ); - } - } - - return( rtiff ); -} - -/* Pull out the nth directory from a TIFF file. - */ -static TIFF * -get_directory( const char *filename, int page ) -{ - TIFF *tif; - int i; - - /* No need to use "b" and it means something different anyway. - */ - if( !(tif = TIFFOpen( filename, "r" )) ) { - im_error( "im_tiff2vips", - _( "unable to open \"%s\" for input" ), - filename ); - return( NULL ); - } - - for( i = 0; i < page; i++ ) - if( !TIFFReadDirectory( tif ) ) { - /* Run out of directories. - */ - TIFFClose( tif ); - return( NULL ); - } - - return( tif ); -} - -int -im_istiffpyramid( const char *name ) -{ - TIFF *tif; - - TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error ); - TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning ); - - if( (tif = get_directory( name, 2 )) ) { - /* We can see page 2 ... assume it is. - */ - TIFFClose( tif ); - return( 1 ); - } - - return( 0 ); -} - -int -im_tiff2vips( const char *filename, IMAGE *out ) -{ - ReadTiff *rtiff; - -#ifdef DEBUG - printf( "im_tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() ); -#endif /*DEBUG*/ - - TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error ); - TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning ); - - if( !(rtiff = readtiff_new( filename, out )) ) - return( -1 ); - - if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) { - im_error( "im_tiff2vips", _( "TIFF file does not " - "contain page %d" ), rtiff->page ); - return( -1 ); - } - - if( TIFFIsTiled( rtiff->tiff ) ) { - if( read_tilewise( rtiff, out ) ) - return( -1 ); - } - else { - if( read_scanlinewise( rtiff, out ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Just parse the header. - */ -int -im_tiff2vips_header( const char *filename, IMAGE *out ) -{ - ReadTiff *rtiff; - - TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error ); - TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning ); - - if( !(rtiff = readtiff_new( filename, out )) ) - return( -1 ); - - if( !(rtiff->tiff = get_directory( rtiff->filename, rtiff->page )) ) { - im_error( "im_tiff2vips", - _( "TIFF file does not contain page %d" ), - rtiff->page ); - return( -1 ); - } - - if( parse_header( rtiff, out ) ) - return( -1 ); - - return( 0 ); -} - -#endif /*HAVE_TIFF*/ diff --git a/libsrc/conversion/im_tile_cache.c b/libsrc/conversion/im_tile_cache.c deleted file mode 100644 index 1ce3dd16..00000000 --- a/libsrc/conversion/im_tile_cache.c +++ /dev/null @@ -1,391 +0,0 @@ -/* Tile tile cache from tiff2vips ... broken out so it can be shared with - * openexr read. - * - * This isn't the same as im_cache(): we don't sub-divide, and we - * single-thread our callee. - * - * 23/8/06 - * - take ownership of reused tiles in case the cache is being shared - * 13/2/07 - * - relase ownership after fillng with pixels in case we read across - * threads - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* Turn on debugging output. -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Lower and upper bounds for tile cache size. Choose an exact number based on - * tile size. - */ -#define IM_MAX_TILE_CACHE (250) -#define IM_MIN_TILE_CACHE (5) - -/* A tile in our cache. - */ -typedef struct { - struct _Read *read; - - REGION *region; /* REGION with private mem for data */ - int time; /* Time of last use for flush */ - int x; /* xy pos in VIPS image cods */ - int y; -} Tile; - -/* Stuff we track during a read. - */ -typedef struct _Read { - /* Parameters. - */ - IMAGE *in; - IMAGE *out; - int tile_width; - int tile_height; - int max_tiles; - - /* Cache. - */ - int time; /* Update ticks for LRU here */ - int ntiles; /* Current cache size */ - GMutex *lock; /* Lock everything here */ - GSList *cache; /* List of tiles */ -} Read; - -static void -tile_destroy( Tile *tile ) -{ - Read *read = tile->read; - - read->cache = g_slist_remove( read->cache, tile ); - read->ntiles -= 1; - assert( read->ntiles >= 0 ); - tile->read = NULL; - - IM_FREEF( im_region_free, tile->region ); - - im_free( tile ); -} - -static void -read_destroy( Read *read ) -{ - IM_FREEF( g_mutex_free, read->lock ); - - while( read->cache ) { - Tile *tile = (Tile *) read->cache->data; - - tile_destroy( tile ); - } - - im_free( read ); -} - -static Read * -read_new( IMAGE *in, IMAGE *out, - int tile_width, int tile_height, int max_tiles ) -{ - Read *read; - - if( !(read = IM_NEW( NULL, Read )) ) - return( NULL ); - read->in = in; - read->out = out; - read->tile_width = tile_width; - read->tile_height = tile_height; - read->max_tiles = max_tiles; - read->time = 0; - read->ntiles = 0; - read->lock = g_mutex_new(); - read->cache = NULL; - - if( im_add_close_callback( out, - (im_callback_fn) read_destroy, read, NULL ) ) { - read_destroy( read ); - return( NULL ); - } - - return( read ); -} - -static Tile * -tile_new( Read *read ) -{ - Tile *tile; - - if( !(tile = IM_NEW( NULL, Tile )) ) - return( NULL ); - - tile->read = read; - tile->region = NULL; - tile->time = read->time; - tile->x = -1; - tile->y = -1; - read->cache = g_slist_prepend( read->cache, tile ); - assert( read->ntiles >= 0 ); - read->ntiles += 1; - - if( !(tile->region = im_region_create( read->in )) ) { - tile_destroy( tile ); - return( NULL ); - } - - return( tile ); -} - -/* Do we have a tile in the cache? - */ -static Tile * -tile_search( Read *read, int x, int y ) -{ - GSList *p; - - for( p = read->cache; p; p = p->next ) { - Tile *tile = (Tile *) p->data; - - if( tile->x == x && tile->y == y ) - return( tile ); - } - - return( NULL ); -} - -static void -tile_touch( Tile *tile ) -{ - assert( tile->read->ntiles >= 0 ); - - tile->time = tile->read->time++; -} - -/* Fill a tile with pixels. - */ -static int -tile_fill( Tile *tile, int x, int y ) -{ - Rect area; - - tile->x = x; - tile->y = y; - -#ifdef DEBUG - printf( "im_tile_cache: filling tile %d x %d\n", tile->x, tile->y ); -#endif /*DEBUG*/ - - area.left = x; - area.top = y; - area.width = tile->read->tile_width; - area.height = tile->read->tile_height; - if( im_prepare( tile->region, &area ) ) - return( -1 ); - - /* Make sure these pixels aren't part of this thread's buffer cache - * ... they may be read out by another thread. - */ - im__region_no_ownership( tile->region ); - - tile_touch( tile ); - - return( 0 ); -} - -/* Find existing tile, make a new tile, or if we have a full set of tiles, - * reuse LRU. - */ -static Tile * -tile_find( Read *read, int x, int y ) -{ - Tile *tile; - int oldest; - GSList *p; - - /* In cache already? - */ - if( (tile = tile_search( read, x, y )) ) { - tile_touch( tile ); - - return( tile ); - } - - /* Cache not full? - */ - if( read->max_tiles == -1 || - read->ntiles < read->max_tiles ) { - if( !(tile = tile_new( read )) || - tile_fill( tile, x, y ) ) - return( NULL ); - - return( tile ); - } - - /* Reuse an old one. - */ - oldest = read->time; - tile = NULL; - for( p = read->cache; p; p = p->next ) { - Tile *t = (Tile *) p->data; - - if( t->time < oldest ) { - oldest = t->time; - tile = t; - } - } - - assert( tile ); - - /* The tile may have been created by another thread if we are sharing - * the tile cache between several readers. Take ownership of the tile - * to stop assert() failures in im_prepare(). This is safe, since we - * are in a mutex. - */ - im__region_take_ownership( tile->region ); - -#ifdef DEBUG - printf( "im_tile_cache: reusing tile %d x %d\n", tile->x, tile->y ); -#endif /*DEBUG*/ - - if( tile_fill( tile, x, y ) ) - return( NULL ); - - return( tile ); -} - -/* Copy rect from from to to. - */ -static void -copy_region( REGION *from, REGION *to, Rect *area ) -{ - int y; - - /* Area should be inside both from and to. - */ - assert( im_rect_includesrect( &from->valid, area ) ); - assert( im_rect_includesrect( &to->valid, area ) ); - - /* Loop down common area, copying. - */ - for( y = area->top; y < IM_RECT_BOTTOM( area ); y++ ) { - PEL *p = (PEL *) IM_REGION_ADDR( from, area->left, y ); - PEL *q = (PEL *) IM_REGION_ADDR( to, area->left, y ); - - memcpy( q, p, IM_IMAGE_SIZEOF_PEL( from->im ) * area->width ); - } -} - -/* Loop over the output region, filling with data from cache. - */ -static int -fill_region( REGION *out, void *seq, void *a, void *b ) -{ - Read *read = (Read *) a; - const int tw = read->tile_width; - const int th = read->tile_height; - Rect *r = &out->valid; - - /* Find top left of tiles we need. - */ - int xs = (r->left / tw) * tw; - int ys = (r->top / th) * th; - - int x, y; - - g_mutex_lock( read->lock ); - - for( y = ys; y < IM_RECT_BOTTOM( r ); y += th ) - for( x = xs; x < IM_RECT_RIGHT( r ); x += tw ) { - Tile *tile; - Rect tarea; - Rect hit; - - if( !(tile = tile_find( read, x, y )) ) { - g_mutex_unlock( read->lock ); - return( -1 ); - } - - /* The area of the tile. - */ - tarea.left = x; - tarea.top = y; - tarea.width = tw; - tarea.height = th; - - /* The part of the tile that we need. - */ - im_rect_intersectrect( &tarea, r, &hit ); - - copy_region( tile->region, out, &hit ); - } - - g_mutex_unlock( read->lock ); - - return( 0 ); -} - -int -im_tile_cache( IMAGE *in, IMAGE *out, - int tile_width, int tile_height, int max_tiles ) -{ - Read *read; - - if( tile_width <= 0 || tile_height <= 0 || max_tiles < -1 ) { - im_error( "im_tile_cache", _( "bad parameters" ) ); - return( -1 ); - } - if( im_piocheck( in, out ) ) - return( -1 ); - if( im_cp_desc( out, in ) ) - return( -1 ); - if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) ) - return( -1 ); - - if( !(read = read_new( in, out, - tile_width, tile_height, max_tiles )) ) - return( -1 ); - if( im_generate( out, - NULL, fill_region, NULL, read, NULL ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_vips2csv.c b/libsrc/conversion/im_vips2csv.c deleted file mode 100644 index 6d19f9dd..00000000 --- a/libsrc/conversion/im_vips2csv.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Write a csv file. - * - * 9/6/06 - * - hacked from im_debugim - * 23/10/06 - * - allow separator to be specified (default "\t", ) - * 17/11/06 - * - oops, was broken - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -#define PRINT_INT( TYPE ) fprintf( fp, "%d", *((TYPE*)p) ); -#define PRINT_FLOAT( TYPE ) fprintf( fp, "%g", *((TYPE*)p) ); -#define PRINT_COMPLEX( TYPE ) fprintf( fp, "(%g, %g)", \ - ((TYPE*)p)[0], ((TYPE*)p)[1] ); - -static int -vips2csv( IMAGE *in, FILE *fp, const char *sep ) -{ - int w = IM_IMAGE_N_ELEMENTS( in ); - int es = IM_IMAGE_SIZEOF_ELEMENT( in ); - - int x, y; - PEL *p; - - p = (PEL *) in->data; - for( y = 0; y < in->Ysize; y++ ) { - for( x = 0; x < w; x++ ) { - if( x > 0 ) - fprintf( fp, "%s", sep ); - - switch( in->BandFmt ) { - case IM_BANDFMT_UCHAR: - PRINT_INT( unsigned char ); break; - case IM_BANDFMT_CHAR: - PRINT_INT( char ); break; - case IM_BANDFMT_USHORT: - PRINT_INT( unsigned short ); break; - case IM_BANDFMT_SHORT: - PRINT_INT( short ); break; - case IM_BANDFMT_UINT: - PRINT_INT( unsigned int ); break; - case IM_BANDFMT_INT: - PRINT_INT( int ); break; - case IM_BANDFMT_FLOAT: - PRINT_FLOAT( float ); break; - case IM_BANDFMT_DOUBLE: - PRINT_FLOAT( double ); break; - case IM_BANDFMT_COMPLEX: - PRINT_COMPLEX( float ); break; - case IM_BANDFMT_DPCOMPLEX: - PRINT_COMPLEX( double ); break; - - default: - assert( 0 ); - } - - p += es; - } - - fprintf( fp, "\n" ); - } - - return( 0 ); -} - -int -im_vips2csv( IMAGE *in, const char *filename ) -{ - char *separator = "\t"; - - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - FILE *fp; - char *p, *q, *r; - - /* Parse mode string. - */ - im_filename_split( filename, name, mode ); - p = &mode[0]; - while( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "sep", q ) && (r = im_getsuboption( q )) ) - separator = r; - } - - if( im_incheck( in ) ) - return( -1 ); - if( in->Coding != IM_CODING_NONE ) { - im_error( "im_vips2csv", _( "input must be uncoded" ) ); - return( -1 ); - } - - if( !(fp = fopen( name, "w" )) ) { - im_error( "im_cvips2csv", _( "unable to open \"%s\"" ), - name ); - return( -1 ); - } - - if( vips2csv( in, fp, separator ) ) { - fclose( fp ); - return( -1 ); - } - - fclose( fp ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_vips2jpeg.c b/libsrc/conversion/im_vips2jpeg.c deleted file mode 100644 index 2f08d635..00000000 --- a/libsrc/conversion/im_vips2jpeg.c +++ /dev/null @@ -1,896 +0,0 @@ -/* Convert 8-bit VIPS images to/from JPEG. - * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 12/11/04 - * - better demand size choice for eval - * 30/6/05 JC - * - update im_error()/im_warn() - * - now loads and saves exif data - * 30/7/05 - * - now loads ICC profiles - * - now saves ICC profiles from the VIPS header - * 24/8/05 - * - jpeg load sets vips xres/yres from exif, if possible - * - jpeg save sets exif xres/yres from vips, if possible - * 29/8/05 - * - cut from old vips_jpeg.c - * 20/4/06 - * - auto convert to sRGB/mono for save - * 13/10/06 - * - add -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_JPEG - -#include - -int -im_vips2jpeg( IMAGE *in, const char *filename ) -{ - im_error( "im_vips2jpeg", _( "JPEG support disabled" ) ); - - return( -1 ); -} - -int -im_vips2bufjpeg( IMAGE *in, IMAGE *out, int qfac, char **obuf, int *olen ) -{ - im_error( "im_vips2bufjpeg", _( "JPEG support disabled" ) ); - - return( -1 ); -} - -int -im_vips2mimejpeg( IMAGE *in, int qfac ) -{ - im_error( "im_vips2mimejpeg", _( "JPEG support disabled" ) ); - - return( -1 ); -} - -#else /*HAVE_JPEG*/ - -#include -#include -#include -#include -#include - -#ifdef HAVE_EXIF -#ifdef UNTAGGED_EXIF -#include -#include -#include -#include -#else /*!UNTAGGED_EXIF*/ -#include -#include -#include -#include -#endif /*UNTAGGED_EXIF*/ -#endif /*HAVE_EXIF*/ - -#include -#include -#include - -/* jpeglib includes jconfig.h, which can define HAVE_STDLIB_H ... which we - * also define. Make sure it's turned off. - */ -#ifdef HAVE_STDLIB_H -#undef HAVE_STDLIB_H -#endif /*HAVE_STDLIB_H*/ - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Define a new error handler for when we bomb out. - */ -typedef struct { - /* Public fields. - */ - struct jpeg_error_mgr pub; - - /* Private stuff for us. - */ - jmp_buf jmp; /* longjmp() here to get back to VIPS */ - FILE *fp; /* fclose() if non-NULL */ -} ErrorManager; - -/* New output message method - send to VIPS. - */ -METHODDEF(void) -new_output_message( j_common_ptr cinfo ) -{ - char buffer[JMSG_LENGTH_MAX]; - - (*cinfo->err->format_message)( cinfo, buffer ); - im_error( "vips_jpeg", _( "%s" ), buffer ); - -#ifdef DEBUG - printf( "vips_jpeg.c: new_output_message: \"%s\"\n", buffer ); -#endif /*DEBUG*/ -} - -/* New error_exit handler. - */ -METHODDEF(void) -new_error_exit( j_common_ptr cinfo ) -{ - ErrorManager *eman = (ErrorManager *) cinfo->err; - -#ifdef DEBUG - printf( "vips_jpeg.c: new_error_exit\n" ); -#endif /*DEBUG*/ - - /* Close the fp if necessary. - */ - if( eman->fp ) { - (void) fclose( eman->fp ); - eman->fp = NULL; - } - - /* Send the error message to VIPS. This method is overridden above. - */ - (*cinfo->err->output_message)( cinfo ); - - /* Jump back. - */ - longjmp( eman->jmp, 1 ); -} - -/* What we track during a JPEG write. - */ -typedef struct { - IMAGE *in; - struct jpeg_compress_struct cinfo; - ErrorManager eman; - im_threadgroup_t *tg; - JSAMPROW *row_pointer; - char *profile_bytes; - unsigned int profile_length; - IMAGE *inverted; -} Write; - -static void -write_destroy( Write *write ) -{ - jpeg_destroy_compress( &write->cinfo ); - IM_FREEF( im_threadgroup_free, write->tg ); - IM_FREEF( im_close, write->in ); - IM_FREEF( fclose, write->eman.fp ); - IM_FREE( write->row_pointer ); - IM_FREE( write->profile_bytes ); - IM_FREEF( im_close, write->inverted ); - im_free( write ); -} - -static Write * -write_new( IMAGE *in ) -{ - Write *write; - - if( !(write = IM_NEW( NULL, Write )) ) - return( NULL ); - memset( write, 0, sizeof( Write ) ); - - if( !(write->in = im__convert_saveable( in, IM__RGB_CMYK )) ) { - im_error( "im_vips2jpeg", - _( "unable to convert to saveable format" ) ); - write_destroy( write ); - return( NULL ); - } - - write->tg = NULL; - write->row_pointer = NULL; - write->cinfo.err = jpeg_std_error( &write->eman.pub ); - write->eman.pub.error_exit = new_error_exit; - write->eman.pub.output_message = new_output_message; - write->eman.fp = NULL; - write->profile_bytes = NULL; - write->profile_length = 0; - write->inverted = NULL; - - return( write ); -} - -#ifdef HAVE_EXIF -static void -write_rational( ExifEntry *entry, ExifByteOrder bo, void *data ) -{ - ExifRational *v = (ExifRational *) data; - - exif_set_rational( entry->data, bo, *v ); -} - -static void -write_short( ExifEntry *entry, ExifByteOrder bo, void *data ) -{ - ExifShort *v = (ExifShort *) data; - - exif_set_short( entry->data, bo, *v ); -} - -typedef void (*write_fn)( ExifEntry *, ExifByteOrder, void * ); - -static int -write_tag( ExifData *ed, ExifTag tag, ExifFormat f, write_fn fn, void *data ) -{ - ExifByteOrder bo; - int found; - int i; - - bo = exif_data_get_byte_order( ed ); - - /* Need to set the tag in all sections which have it :-( - */ - found = 0; - for( i = 0; i < EXIF_IFD_COUNT; i++ ) { - ExifEntry *entry; - - if( (entry = exif_content_get_entry( ed->ifd[i], tag )) && - entry->format == f && - entry->components == 1 ) { - fn( entry, bo, data ); - found = 1; - } - } - - if( !found ) { - /* There was no tag we could update ... make one in ifd[0]. - */ - ExifEntry *entry; - - entry = exif_entry_new(); - exif_content_add_entry( ed->ifd[0], entry ); - exif_entry_initialize( entry, tag ); - fn( entry, bo, data ); - } - - return( 0 ); -} - -static int -set_exif_resolution( ExifData *ed, IMAGE *im ) -{ - double xres, yres; - ExifRational xres_rational, yres_rational; - ExifShort unit; - - /* Always save as inches - more progs support it for read. - */ - xres = im->Xres * 25.4; - yres = im->Yres * 25.4; - unit = 2; - - /* Wow, how dumb, fix this. - */ - xres_rational.numerator = xres * 100000; - xres_rational.denominator = 100000; - yres_rational.numerator = yres * 100000; - yres_rational.denominator = 100000; - - if( write_tag( ed, EXIF_TAG_X_RESOLUTION, EXIF_FORMAT_RATIONAL, - write_rational, &xres_rational ) || - write_tag( ed, EXIF_TAG_Y_RESOLUTION, EXIF_FORMAT_RATIONAL, - write_rational, &yres_rational ) || - write_tag( ed, EXIF_TAG_RESOLUTION_UNIT, EXIF_FORMAT_SHORT, - write_short, &unit ) ) { - im_error( "im_jpeg2vips", - _( "error setting JPEG resolution" ) ); - return( -1 ); - } - - return( 0 ); -} -#endif /*HAVE_EXIF*/ - -static int -write_exif( Write *write ) -{ - unsigned char *data; - size_t data_length; - unsigned int idl; -#ifdef HAVE_EXIF - ExifData *ed; - - /* Either parse from the embedded EXIF, or if there's none, make - * some fresh EXIF we can write the resolution to. - */ - if( im_header_get_type( write->in, IM_META_EXIF_NAME ) ) { - if( im_meta_get_blob( write->in, IM_META_EXIF_NAME, - (void *) &data, &data_length ) ) - return( -1 ); - - if( !(ed = exif_data_new_from_data( data, data_length )) ) - return( -1 ); - } - else - ed = exif_data_new(); - - /* Set EXIF resolution from VIPS. - */ - if( set_exif_resolution( ed, write->in ) ) { - exif_data_free( ed ); - return( -1 ); - } - - /* Reserialise and write. exif_data_save_data() returns an int for some - * reason. - */ - exif_data_save_data( ed, &data, &idl ); - if( !idl ) { - im_error( "im_jpeg2vips", _( "error saving EXIF" ) ); - exif_data_free( ed ); - return( -1 ); - } - data_length = idl; - -#ifdef DEBUG - printf( "im_vips2jpeg: attaching %d bytes of EXIF\n", data_length ); -#endif /*DEBUG*/ - - exif_data_free( ed ); - jpeg_write_marker( &write->cinfo, JPEG_APP0 + 1, data, data_length ); - free( data ); -#else /*!HAVE_EXIF*/ - /* No libexif ... just copy the embedded EXIF over. - */ - if( im_header_get_type( write->in, IM_META_EXIF_NAME ) ) { - if( im_meta_get_blob( write->in, IM_META_EXIF_NAME, - (void *) &data, &data_length ) ) - return( -1 ); - -#ifdef DEBUG - printf( "im_vips2jpeg: attaching %d bytes of EXIF\n", - data_length ); -#endif /*DEBUG*/ - - jpeg_write_marker( &write->cinfo, JPEG_APP0 + 1, - data, data_length ); - } -#endif /*!HAVE_EXIF*/ - - return( 0 ); -} - -/* ICC writer from lcms, slight tweaks. - */ - -#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ -#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ -#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ -#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) - -/* - * This routine writes the given ICC profile data into a JPEG file. - * It *must* be called AFTER calling jpeg_start_compress() and BEFORE - * the first call to jpeg_write_scanlines(). - * (This ordering ensures that the APP2 marker(s) will appear after the - * SOI and JFIF or Adobe markers, but before all else.) - */ - -static void -write_profile_data (j_compress_ptr cinfo, - const JOCTET *icc_data_ptr, - unsigned int icc_data_len) -{ - unsigned int num_markers; /* total number of markers we'll write */ - int cur_marker = 1; /* per spec, counting starts at 1 */ - unsigned int length; /* number of bytes to write in this marker */ - - /* rounding up will fail for length == 0 */ - assert( icc_data_len > 0 ); - - /* Calculate the number of markers we'll need, rounding up of course */ - num_markers = (icc_data_len + MAX_DATA_BYTES_IN_MARKER - 1) / - MAX_DATA_BYTES_IN_MARKER; - - while (icc_data_len > 0) { - /* length of profile to put in this marker */ - length = icc_data_len; - if (length > MAX_DATA_BYTES_IN_MARKER) - length = MAX_DATA_BYTES_IN_MARKER; - icc_data_len -= length; - - /* Write the JPEG marker header (APP2 code and marker length) */ - jpeg_write_m_header(cinfo, ICC_MARKER, - (unsigned int) (length + ICC_OVERHEAD_LEN)); - - /* Write the marker identifying string "ICC_PROFILE" (null-terminated). - * We code it in this less-than-transparent way so that the code works - * even if the local character set is not ASCII. - */ - jpeg_write_m_byte(cinfo, 0x49); - jpeg_write_m_byte(cinfo, 0x43); - jpeg_write_m_byte(cinfo, 0x43); - jpeg_write_m_byte(cinfo, 0x5F); - jpeg_write_m_byte(cinfo, 0x50); - jpeg_write_m_byte(cinfo, 0x52); - jpeg_write_m_byte(cinfo, 0x4F); - jpeg_write_m_byte(cinfo, 0x46); - jpeg_write_m_byte(cinfo, 0x49); - jpeg_write_m_byte(cinfo, 0x4C); - jpeg_write_m_byte(cinfo, 0x45); - jpeg_write_m_byte(cinfo, 0x0); - - /* Add the sequencing info */ - jpeg_write_m_byte(cinfo, cur_marker); - jpeg_write_m_byte(cinfo, (int) num_markers); - - /* Add the profile data */ - while (length--) { - jpeg_write_m_byte(cinfo, *icc_data_ptr); - icc_data_ptr++; - } - cur_marker++; - } -} - -/* Write an ICC Profile from a file into the JPEG stream. - */ -static int -write_profile_file( Write *write, const char *profile ) -{ - if( !(write->profile_bytes = - im__file_read_name( profile, &write->profile_length )) ) - return( -1 ); - write_profile_data( &write->cinfo, - (JOCTET *) write->profile_bytes, write->profile_length ); - -#ifdef DEBUG - printf( "im_vips2jpeg: attached profile \"%s\"\n", profile ); -#endif /*DEBUG*/ - - return( 0 ); -} - -static int -write_profile_meta( Write *write ) -{ - void *data; - size_t data_length; - - if( im_meta_get_blob( write->in, IM_META_ICC_NAME, - &data, &data_length ) ) - return( -1 ); - - write_profile_data( &write->cinfo, data, data_length ); - -#ifdef DEBUG - printf( "im_vips2jpeg: attached %d byte profile from VIPS header\n", - data_length ); -#endif /*DEBUG*/ - - return( 0 ); -} - -static int -write_jpeg_block( REGION *region, Rect *area, void *a, void *b ) -{ - Write *write = (Write *) a; - int i; - - /* We are running in a background thread. We need to catch longjmp()s - * here instead. - */ - if( setjmp( write->eman.jmp ) ) - return( -1 ); - - for( i = 0; i < area->height; i++ ) - write->row_pointer[i] = (JSAMPROW) - IM_REGION_ADDR( region, 0, area->top + i ); - - jpeg_write_scanlines( &write->cinfo, write->row_pointer, area->height ); - - return( 0 ); -} - -/* Write a VIPS image to a JPEG compress struct. - */ -static int -write_vips( Write *write, int qfac, const char *profile ) -{ - IMAGE *in; - J_COLOR_SPACE space; - - /* The image we'll be writing ... can change, see CMYK. - */ - in = write->in; - - /* Should have been converted for save. - */ - assert( in->BandFmt == IM_BANDFMT_UCHAR ); - assert( in->Coding == IM_CODING_NONE ); - assert( in->Bands == 1 || in->Bands == 3 || in->Bands == 4 ); - - /* Check input image. - */ - if( im_pincheck( in ) ) - return( -1 ); - if( qfac < 0 || qfac > 100 ) { - im_error( "im_vips2jpeg", _( "qfac should be in 0-100" ) ); - return( -1 ); - } - - /* Set compression parameters. - */ - write->cinfo.image_width = in->Xsize; - write->cinfo.image_height = in->Ysize; - write->cinfo.input_components = in->Bands; - if( in->Bands == 4 && in->Type == IM_TYPE_CMYK ) { - space = JCS_CMYK; - /* IJG always sets an Adobe marker, so we should invert CMYK. - */ - if( !(write->inverted = im_open( "vips2jpeg_invert", "p" )) || - im_invert( in, write->inverted ) ) - return( -1 ); - in = write->inverted; - } - else if( in->Bands == 3 ) - space = JCS_RGB; - else if( in->Bands == 1 ) - space = JCS_GRAYSCALE; - else - /* Use luminance compression for all channels. - */ - space = JCS_UNKNOWN; - write->cinfo.in_color_space = space; - - /* Build VIPS output stuff now we know the image we'll be writing. - */ - write->tg = im_threadgroup_create( in ); - write->row_pointer = IM_ARRAY( NULL, write->tg->nlines, JSAMPROW ); - if( !write->tg || !write->row_pointer ) - return( -1 ); - - /* Rest to default. - */ - jpeg_set_defaults( &write->cinfo ); - jpeg_set_quality( &write->cinfo, qfac, TRUE ); - - /* Build compress tables. - */ - jpeg_start_compress( &write->cinfo, TRUE ); - - /* Write any APP markers we need. - */ - if( write_exif( write ) ) - return( -1 ); - - /* A profile supplied as an argument overrides an embedded profile. - */ - if( profile && - write_profile_file( write, profile ) ) - return( -1 ); - if( !profile && - im_header_get_type( in, IM_META_ICC_NAME ) && - write_profile_meta( write ) ) - return( -1 ); - - /* Write data. Note that the write function grabs the longjmp()! - */ - if( im_wbuffer( write->tg, write_jpeg_block, write, NULL ) ) - return( -1 ); - - /* We have to reinstate the setjmp() before we jpeg_finish_compress(). - */ - if( setjmp( write->eman.jmp ) ) - return( -1 ); - - jpeg_finish_compress( &write->cinfo ); - - return( 0 ); -} - -/* Write a VIPS image to a file as JPEG. - */ -int -im_vips2jpeg( IMAGE *in, const char *filename ) -{ - Write *write; - int qfac = 75; - char *profile = NULL; - - char *p, *q; - - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char buf[FILENAME_MAX]; - - /* Parse mode from filename. - */ - im_filename_split( filename, name, mode ); - strcpy( buf, mode ); - p = &buf[0]; - if( (q = im_getnextoption( &p )) ) { - if( strcmp( q, "" ) != 0 ) - qfac = atoi( mode ); - } - if( (q = im_getnextoption( &p )) ) { - if( strcmp( q, "" ) != 0 ) - profile = q; - } - if( (q = im_getnextoption( &p )) ) { - im_error( "im_vips2jpeg", - _( "unknown extra options \"%s\"" ), q ); - return( -1 ); - } - - if( !(write = write_new( in )) ) - return( -1 ); - - if( setjmp( write->eman.jmp ) ) { - /* Here for longjmp() from new_error_exit(). - */ - write_destroy( write ); - - return( -1 ); - } - - /* Can't do this in write_new(), has to be after we've made the - * setjmp(). - */ - jpeg_create_compress( &write->cinfo ); - - /* Make output. - */ -#ifdef BINARY_OPEN - if( !(write->eman.fp = fopen( name, "wb" )) ) { -#else /*BINARY_OPEN*/ - if( !(write->eman.fp = fopen( name, "w" )) ) { -#endif /*BINARY_OPEN*/ - write_destroy( write ); - im_error( "im_vips2jpeg", - _( "unable to open \"%s\"" ), name ); - - return( -1 ); - } - jpeg_stdio_dest( &write->cinfo, write->eman.fp ); - - /* Convert! - */ - if( write_vips( write, qfac, profile ) ) { - write_destroy( write ); - return( -1 ); - } - write_destroy( write ); - - return( 0 ); -} - -/* Just like the above, but we write to a memory buffer. - * - * A memory buffer for the compressed image. - */ -typedef struct { - /* Public jpeg fields. - */ - struct jpeg_destination_mgr pub; - - /* Private stuff during write. - */ - JOCTET *data; /* Allocated area */ - int used; /* Number of bytes written so far */ - int size; /* Max size */ - - /* Copy the compressed area here. - */ - IMAGE *out; /* Allocate relative to this */ - char **obuf; /* Allocated buffer, and size */ - int *olen; -} OutputBuffer; - -/* Init dest method. - */ -METHODDEF(void) -init_destination( j_compress_ptr cinfo ) -{ - OutputBuffer *buf = (OutputBuffer *) cinfo->dest; - int mx = cinfo->image_width * cinfo->image_height * - cinfo->input_components * sizeof( JOCTET ); - - /* Allocate relative to the image we are writing .. freed when we junk - * this output. - */ - buf->data = (JOCTET *) (*cinfo->mem->alloc_large) - ( (j_common_ptr) cinfo, JPOOL_IMAGE, mx ); - buf->used = 0; - buf->size = mx; - - /* Set buf pointers for library. - */ - buf->pub.next_output_byte = buf->data; - buf->pub.free_in_buffer = mx; -} - -/* Buffer full method ... should never get this. - */ -METHODDEF(boolean) -empty_output_buffer( j_compress_ptr cinfo ) -{ - /* Not really a file write error, but why not. Should never happen. - */ - ERREXIT( cinfo, JERR_FILE_WRITE ); - - return( 0 ); -} - -/* Cleanup. Write entire buffer as a MIME type. - */ -METHODDEF(void) -term_destination( j_compress_ptr cinfo ) -{ - OutputBuffer *buf = (OutputBuffer *) cinfo->dest; - int len = buf->size - buf->pub.free_in_buffer; - void *obuf; - - /* Allocate and copy to the VIPS output area. - */ - if( !(obuf = im_malloc( buf->out, len )) ) - ERREXIT( cinfo, JERR_FILE_WRITE ); - memcpy( obuf, buf->data, len ); - *(buf->obuf) = obuf; - *(buf->olen) = len; -} - -/* Set dest to one of our objects. - */ -static void -buf_dest( j_compress_ptr cinfo, IMAGE *out, char **obuf, int *olen ) -{ - OutputBuffer *buf; - - /* The destination object is made permanent so that multiple JPEG - * images can be written to the same file without re-executing - * jpeg_stdio_dest. This makes it dangerous to use this manager and - * a different destination manager serially with the same JPEG object, - * because their private object sizes may be different. - * - * Caveat programmer. - */ - if( !cinfo->dest ) { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) - ( (j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof( OutputBuffer ) ); - } - - buf = (OutputBuffer *) cinfo->dest; - buf->pub.init_destination = init_destination; - buf->pub.empty_output_buffer = empty_output_buffer; - buf->pub.term_destination = term_destination; - - /* Save output parameters. - */ - buf->out = out; - buf->obuf = obuf; - buf->olen = olen; -} - -/* As above, but save to a buffer. The buffer is allocated relative to out. - * On success, buf is set to the output buffer and len to the size of the - * compressed image. - */ -int -im_vips2bufjpeg( IMAGE *in, IMAGE *out, int qfac, char **obuf, int *olen ) -{ - Write *write; - - if( !(write = write_new( in )) ) - return( -1 ); - - /* Clear output parameters. - */ - *obuf = NULL; - *olen = 0; - - /* Make jpeg compression object. - */ - if( setjmp( write->eman.jmp ) ) { - /* Here for longjmp() from new_error_exit(). - */ - write_destroy( write ); - - return( -1 ); - } - jpeg_create_compress( &write->cinfo ); - - /* Attach output. - */ - buf_dest( &write->cinfo, out, obuf, olen ); - - /* Convert! - */ - if( write_vips( write, qfac, NULL ) ) { - write_destroy( write ); - - return( -1 ); - } - write_destroy( write ); - - return( 0 ); -} - -/* As above, but save as a mime jpeg on stdout. - */ -int -im_vips2mimejpeg( IMAGE *in, int qfac ) -{ - IMAGE *base; - int len; - char *buf; - - if( !(base = im_open( "im_vips2mimejpeg:1", "p" )) ) - return( -1 ); - if( im_vips2bufjpeg( in, base, qfac, &buf, &len ) ) { - im_close( base ); - return( -1 ); - } - - /* Write as a MIME type. - */ - printf( "Content-length: %d\r\n", len ); - printf( "Content-type: image/jpeg\r\n" ); - printf( "\r\n" ); - fwrite( buf, sizeof( char ), len, stdout ); - fflush( stdout ); - - im_close( base ); - - if( ferror( stdout ) ) { - im_error( "im_vips2mimejpeg", _( "error writing output" ) ); - return( -1 ); - } - - return( 0 ); -} - -#endif /*HAVE_JPEG*/ diff --git a/libsrc/conversion/im_vips2png.c b/libsrc/conversion/im_vips2png.c deleted file mode 100644 index f66803c5..00000000 --- a/libsrc/conversion/im_vips2png.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Convert 1 to 4-band 8 or 16-bit VIPS images to/from PNG. - * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 22/2/05 - * - read non-interlaced PNG with a line buffer (thanks Michel Brabants) - * 11/1/06 - * - read RGBA palette-ized images more robustly (thanks Tom) - * 20/4/06 - * - auto convert to sRGB/mono (with optional alpha) for save - * 1/5/06 - * - from vips_png.c - * 2/11/07 - * - use im_wbuffer() API for BG writes - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_PNG - -#include - -int -im_vips2png( IMAGE *in, const char *filename ) -{ - im_error( "im_vips2png", _( "PNG support disabled" ) ); - return( -1 ); -} - -#else /*HAVE_PNG*/ - -#include -#include -#include - -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -#if PNG_LIBPNG_VER < 10003 -#error "PNG library too old." -#endif - -static void -user_error_function( png_structp png_ptr, png_const_charp error_msg ) -{ - im_error( "im_vips2png", _( "PNG error: \"%s\"" ), error_msg ); -} - -static void -user_warning_function( png_structp png_ptr, png_const_charp warning_msg ) -{ - im_error( "im_vips2png", _( "PNG warning: \"%s\"" ), warning_msg ); -} - -/* What we track during a PNG write. - */ -typedef struct { - IMAGE *in; - im_threadgroup_t *tg; - - FILE *fp; - png_structp pPng; - png_infop pInfo; - png_bytep *row_pointer; -} Write; - -static void -write_destroy( Write *write ) -{ - IM_FREEF( im_threadgroup_free, write->tg ); - IM_FREEF( im_close, write->in ); - IM_FREEF( fclose, write->fp ); - if( write->pPng ) - png_destroy_write_struct( &write->pPng, &write->pInfo ); - IM_FREE( write->row_pointer ); - - im_free( write ); -} - -static Write * -write_new( IMAGE *in ) -{ - Write *write; - - if( !(write = IM_NEW( NULL, Write )) ) - return( NULL ); - memset( write, 0, sizeof( Write ) ); - - if( !(write->in = im__convert_saveable( in, IM__RGBA )) ) { - im_error( "im_vips2png", - _( "unable to convert to RGB for save" ) ); - write_destroy( write ); - return( NULL ); - } - - write->tg = im_threadgroup_create( write->in ); - write->row_pointer = IM_ARRAY( NULL, write->tg->nlines, png_bytep ); - write->fp = NULL; - write->pPng = NULL; - write->pInfo = NULL; - - if( !write->tg || !write->row_pointer ) { - write_destroy( write ); - return( NULL ); - } - - if( !(write->pPng = png_create_write_struct( - PNG_LIBPNG_VER_STRING, NULL, - user_error_function, user_warning_function )) ) { - write_destroy( write ); - return( NULL ); - } - - /* Catch PNG errors from png_create_info_struct(). - */ - if( setjmp( write->pPng->jmpbuf ) ) { - write_destroy( write ); - return( NULL ); - } - - if( !(write->pInfo = png_create_info_struct( write->pPng )) ) { - write_destroy( write ); - return( NULL ); - } - - return( write ); -} - -static int -write_png_block( REGION *region, Rect *area, void *a, void *b ) -{ - Write *write = (Write *) a; - int i; - - /* Catch PNG errors. Yuk. - */ - if( setjmp( write->pPng->jmpbuf ) ) - return( -1 ); - - for( i = 0; i < area->height; i++ ) - write->row_pointer[i] = (png_bytep) - IM_REGION_ADDR( region, 0, area->top + i ); - - png_write_rows( write->pPng, write->row_pointer, area->height ); - - return( 0 ); -} - -/* Write a VIPS image to PNG. - */ -static int -write_vips( Write *write, int compress, int interlace ) -{ - IMAGE *in = write->in; - - int i, nb_passes; - - assert( in->BandFmt == IM_BANDFMT_UCHAR ); - assert( in->Coding == IM_CODING_NONE ); - assert( in->Bands > 0 && in->Bands < 5 ); - - /* Catch PNG errors. - */ - if( setjmp( write->pPng->jmpbuf ) ) - return( -1 ); - - /* Check input image. - */ - if( im_pincheck( in ) ) - return( -1 ); - if( compress < 0 || compress > 9 ) { - im_error( "im_vips2png", _( "compress should be in [0,9]" ) ); - return( -1 ); - } - - /* Set compression parameters. - */ - png_set_compression_level( write->pPng, compress ); - - write->pInfo->width = in->Xsize; - write->pInfo->height = in->Ysize; - write->pInfo->bit_depth = (in->BandFmt == IM_BANDFMT_UCHAR ? 8 : 16); - write->pInfo->gamma = (float) 1.0; - - switch( in->Bands ) { - case 1: write->pInfo->color_type = PNG_COLOR_TYPE_GRAY; break; - case 2: write->pInfo->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; - case 3: write->pInfo->color_type = PNG_COLOR_TYPE_RGB; break; - case 4: write->pInfo->color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; - - default: - assert( 0 ); - } - - png_write_info( write->pPng, write->pInfo ); - - /* If we're an intel byte order CPU and this is a 16bit image, we need - * to swap bytes. - */ - if( write->pInfo->bit_depth > 8 && !im_amiMSBfirst() ) - png_set_swap( write->pPng ); - - if( interlace ) - nb_passes = png_set_interlace_handling( write->pPng ); - else - nb_passes = 1; - - /* Write data. - */ - for( i = 0; i < nb_passes; i++ ) - if( im_wbuffer( write->tg, write_png_block, write, NULL ) ) - return( -1 ); - - /* The setjmp() was held by our background writer: reset it. - */ - if( setjmp( write->pPng->jmpbuf ) ) - return( -1 ); - - png_write_end( write->pPng, write->pInfo ); - - return( 0 ); -} - -/* Write a VIPS image to a file as PNG. - */ -int -im_vips2png( IMAGE *in, const char *filename ) -{ - Write *write; - int compress; - int interlace; - - char *p, *q; - - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char buf[FILENAME_MAX]; - - if( !(write = write_new( in )) ) - return( -1 ); - - /* Extract write mode from filename and parse. - */ - im_filename_split( filename, name, mode ); - strcpy( buf, mode ); - p = &buf[0]; - compress = 6; - interlace = 0; - if( (q = im_getnextoption( &p )) ) - compress = atoi( q ); - if( (q = im_getnextoption( &p )) ) - interlace = atoi( q ); - - /* Make output. - */ -#ifdef BINARY_OPEN - if( !(write->fp = fopen( name, "wb" )) ) { -#else /*BINARY_OPEN*/ - if( !(write->fp = fopen( name, "w" )) ) { -#endif /*BINARY_OPEN*/ - write_destroy( write ); - im_error( "im_vips2png", _( "unable to open \"%s\"" ), name ); - - return( -1 ); - } - png_init_io( write->pPng, write->fp ); - - /* Convert it! - */ - if( write_vips( write, compress, interlace ) ) { - write_destroy( write ); - im_error( "im_vips2png", _( "unable to write \"%s\"" ), name ); - - return( -1 ); - } - write_destroy( write ); - - return( 0 ); -} - -#endif /*HAVE_PNG*/ diff --git a/libsrc/conversion/im_vips2ppm.c b/libsrc/conversion/im_vips2ppm.c deleted file mode 100644 index 073a8d9f..00000000 --- a/libsrc/conversion/im_vips2ppm.c +++ /dev/null @@ -1,293 +0,0 @@ -/* Write a ppm file. - * - * 28/11/03 JC - * - better no-overshoot on tile loop - * 9/9/05 - * - tiny cleanups - * 3/11/07 - * - use im_wbuffer() for bg writes - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* What we track during a PPM write. - */ -typedef struct { - IMAGE *in; - im_threadgroup_t *tg; - FILE *fp; - char *name; -} Write; - -static void -write_destroy( Write *write ) -{ - IM_FREEF( im_threadgroup_free, write->tg ); - IM_FREEF( fclose, write->fp ); - IM_FREE( write->name ); - - im_free( write ); -} - -static Write * -write_new( IMAGE *in, const char *name ) -{ - Write *write; - - if( !(write = IM_NEW( NULL, Write )) ) - return( NULL ); - - write->in = in; - write->tg = im_threadgroup_create( write->in ); - write->name = im_strdup( NULL, name ); - -#ifdef BINARY_OPEN - if( !(write->fp = fopen( name, "wb" )) ) { -#else /*BINARY_OPEN*/ - if( !(write->fp = fopen( name, "w" )) ) { -#endif /*BINARY_OPEN*/ - im_error( "im_vips2ppm", - _( "unable to open \"%s\" for output" ), name ); - } - - if( !write->tg || !write->name || !write->fp ) { - write_destroy( write ); - return( NULL ); - } - - return( write ); -} - -typedef int (*write_fn)( IMAGE *in, FILE *fp, PEL *p ); - -static int -write_ppm_line_ascii( IMAGE *in, FILE *fp, PEL *p ) -{ - const int sk = IM_IMAGE_SIZEOF_PEL( in ); - const int nb = IM_MIN( 3, in->Bands ); - int x, k; - - /* If IM_CODING_LABQ, write 3 bands. - */ - - for( x = 0; x < in->Xsize; x++ ) { - for( k = 0; k < nb; k++ ) { - switch( in->BandFmt ) { - case IM_BANDFMT_UCHAR: - fprintf( fp, "%d ", p[k] ); - break; - - case IM_BANDFMT_USHORT: - fprintf( fp, "%d ", ((unsigned short *) p)[k] ); - break; - - case IM_BANDFMT_UINT: - fprintf( fp, "%d ", ((unsigned int *) p)[k] ); - break; - - default: - assert( 0 ); - } - } - - fprintf( fp, " " ); - - p += sk; - } - - if( !fprintf( fp, "\n" ) ) { - im_error( "im_vips2ppm", _( "write error ... disc full?" ) ); - return( -1 ); - } - - return( 0 ); -} - -static int -write_ppm_line_binary( IMAGE *in, FILE *fp, PEL *p ) -{ - const int sk = IM_IMAGE_SIZEOF_PEL( in ); - const int nb = IM_MIN( 3, in->Bands ); - int x; - - for( x = 0; x < in->Xsize; x++ ) { - if( !fwrite( p, 1, nb, fp ) ) { - im_error( "im_vips2ppm", - _( "write error ... disc full?" ) ); - return( -1 ); - } - - p += sk; - } - - return( 0 ); -} - -static int -write_ppm_block( REGION *region, Rect *area, void *a, void *b ) -{ - Write *write = (Write *) a; - write_fn fn = (write_fn) b; - int i; - - for( i = 0; i < area->height; i++ ) { - PEL *p = (PEL *) IM_REGION_ADDR( region, 0, area->top + i ); - - if( fn( write->in, write->fp, p ) ) - return( -1 ); - } - - return( 0 ); -} - -static int -write_ppm( Write *write, int ascii ) -{ - IMAGE *in = write->in; - write_fn fn = ascii ? write_ppm_line_ascii : write_ppm_line_binary; - - int max_value; - char *magic; - time_t timebuf; - - switch( in->BandFmt ) { - case IM_BANDFMT_UCHAR: - max_value = UCHAR_MAX; - break; - - case IM_BANDFMT_USHORT: - max_value = USHRT_MAX; - break; - - case IM_BANDFMT_UINT: - max_value = UINT_MAX; - break; - - default: - assert( 0 ); - } - - if( in->Bands == 1 && ascii ) - magic = "P2"; - else if( in->Bands == 1 && !ascii ) - magic = "P5"; - else if( in->Bands == 3 && ascii ) - magic = "P3"; - else if( in->Bands == 3 && !ascii ) - magic = "P6"; - else - assert( 0 ); - - fprintf( write->fp, "%s\n", magic ); - time( &timebuf ); - fprintf( write->fp, "#im_vips2ppm - %s\n", ctime( &timebuf ) ); - fprintf( write->fp, "%d %d\n", in->Xsize, in->Ysize ); - fprintf( write->fp, "%d\n", max_value ); - - if( im_wbuffer( write->tg, write_ppm_block, write, fn ) ) - return( -1 ); - - return( 0 ); -} - -int -im_vips2ppm( IMAGE *in, const char *filename ) -{ - Write *write; - int ascii; - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - - /* Default to binary output ... much smaller. - */ - ascii = 0; - - /* Extract write mode from filename. - */ - im_filename_split( filename, name, mode ); - if( strcmp( mode, "" ) != 0 ) { - if( im_isprefix( "binary", mode ) ) - ascii = 0; - else if( im_isprefix( "ascii", mode ) ) - ascii = 1; - else { - im_error( "im_vips2ppm", - _( "bad mode string, " - "should be \"binary\" or \"ascii\"" ) ); - return( -1 ); - } - } - - if( in->Bbits > 8 && !ascii ) { - im_error( "im_vips2ppm", - _( "can't write binary >8 bit images" ) ); - return( -1 ); - } - if( !im_isuint( in ) ) { - im_error( "im_vips2ppm", _( "unsigned int formats only" ) ); - return( -1 ); - } - if( in->Coding != IM_CODING_NONE && in->Coding != IM_CODING_LABQ ) { - im_error( "im_vips2ppm", - _( "uncoded or IM_CODING_LABQ only" ) ); - return( -1 ); - } - if( in->Bands != 1 && in->Bands != 3 ) { - im_error( "im_vips2ppm", _( "1 or 3 band images only" ) ); - return( -1 ); - } - - if( im_pincheck( in ) || !(write = write_new( in, name )) ) - return( -1 ); - - if( write_ppm( write, ascii ) ) { - write_destroy( write ); - return( -1 ); - } - write_destroy( write ); - - return( 0 ); -} diff --git a/libsrc/conversion/im_vips2tiff.c b/libsrc/conversion/im_vips2tiff.c deleted file mode 100644 index d13ae714..00000000 --- a/libsrc/conversion/im_vips2tiff.c +++ /dev/null @@ -1,1653 +0,0 @@ -/* TIFF PARTS: - * Copyright (c) 1988, 1990 by Sam Leffler. - * All rights reserved. - * - * This file is provided for unrestricted use provided that this - * legend is included on all tape media and as a part of the - * software program in whole or part. Users may copy, modify or - * distribute this file at will. - - MODIFICATION FOR VIPS Copyright 1991, K.Martinez - * software may be distributed FREE, with these copyright notices - * no responsibility/warantee is implied or given - * - * - * Modified and added im_LabQ2LabC() function. It can write IM_TYPE_LABQ image - * in vips format to LAB in tiff format. - * Copyright 1994 Ahmed Abbood. - * - * 19/9/95 JC - * - calls TIFFClose() more reliably - * - tidied up - * 12/4/97 JC - * - thrown away and rewritten for TIFF 6 lib - * 22/4/97 JC - * - writes a pyramid! - * - to separate TIFF files tho' - * 23/4/97 JC - * - does 2nd gather pass to put pyramid into a single TIFF file - * - ... and shrinks IM_CODING_LABQ too - * 26/10/98 JC - * - binary open for stupid systems - * 7/6/99 JC - * - 16bit TIFF write too - * 9/7/99 JC - * - ZIP tiff added - * 11/5/00 JC - * - removed TIFFmalloc/TIFFfree - * 5/8/00 JC - * - mode string now part of filename - * 23/4/01 JC - * - HAVE_TIFF turns on TIFFness - * 19/3/02 ruven - * - pyramid stops at tile size, not 64x64 - * 29/4/02 JC - * - write any number of bands (but still with photometric RGB, so not - * very useful) - * 10/9/02 JC - * - oops, handle TIFF errors better - * - now writes CMYK correctly - * 13/2/03 JC - * - tries not to write mad resolutions - * 7/5/03 JC - * - only write CMYK if Type == CMYK - * - writes EXTRASAMPLES ALPHA for bands == 2 or 4 (if we're writing RGB) - * 17/11/03 JC - * - write float too - * 28/11/03 JC - * - read via a "p" so we work from mmap window images - * - uses threadgroups for speedup - * 9/3/04 JC - * - 1 bit write mode added - * 5/4/04 - * - better handling of edge tiles (thanks Ruven) - * 18/5/04 Andrey Kiselev - * - added res_inch/res_cm option - * 20/5/04 JC - * - allow single res number too - * 19/7/04 - * - write several scanlines at once, good speed up for some cases - * 22/9/04 - * - got rid of wrapper image so nip gets progress feedback - * - fixed tiny read-beyond-buffer issue for edge tiles - * 7/10/04 - * - added ICC profile embedding - * 13/12/04 - * - can now pyramid any non-complex type (thanks Ruven) - * 27/1/05 - * - added ccittfax4 as a compression option - * 9/3/05 - * - set PHOTOMETRIC_CIELAB for vips TYPE_LAB images ... so we can write - * float LAB as well as float RGB - * - also LABS images - * 22/6/05 - * - 16 bit LAB write was broken - * 9/9/05 - * - write any icc profile from meta - * 3/3/06 - * - raise tile buffer limit (thanks Ruven) - * 11/11/06 - * - set ORIENTATION_TOPLEFT (thanks Josef) - * 18/7/07 Andrey Kiselev - * - remove "b" option on TIFFOpen() - * - support TIFFTAG_PREDICTOR types for lzw and deflate compression - * 3/11/07 - * - use im_wbuffer() for background writes - * 15/2/08 - * - set TIFFTAG_JPEGQUALITY explicitly when we copy TIFF files, since - * libtiff doesn't keep this in the header (thanks Joe) - * 20/2/08 - * - use tiff error handler from im_tiff2vips.c - * 27/2/08 - * - don't try to copy icc profiles when building pyramids (thanks Joe) - * 9/4/08 - * - use IM_META_RESOLUTION_UNIT to set default resunit - * 17/4/08 - * - allow CMYKA (thanks Doron) - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* Turn on IM_REGION_ADDR() range checks, don't delete intermediates. -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#ifndef HAVE_TIFF - -#include - -int -im_vips2tiff( IMAGE *im, const char *filename ) -{ - im_error( "im_vips2tiff", _( "TIFF support disabled" ) ); - - return( -1 ); -} - -#else /*HAVE_TIFF*/ - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif /*HAVE_UNISTD_H*/ -#include -#include - -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Max no of tiles we buffer in a layer. Enough to buffer a line of 64x64 - * tiles on a 100k pixel across image. - */ -#define IM_MAX_LAYER_BUFFER (1000) - -/* Bits we OR together for quadrants in a tile. - */ -typedef enum pyramid_bits { - PYR_TL = 1, /* Top-left etc. */ - PYR_TR = 2, - PYR_BL = 4, - PYR_BR = 8, - PYR_ALL = 15, - PYR_NONE = 0 -} PyramidBits; - -/* A tile in our pyramid. - */ -typedef struct pyramid_tile { - REGION *tile; - PyramidBits bits; -} PyramidTile; - -/* A layer in the pyramid. - */ -typedef struct pyramid_layer { - /* Parameters. - */ - struct tiff_write *tw; /* Main TIFF write struct */ - int width, height; /* Layer size */ - int sub; /* Subsample factor for this layer */ - - char *lname; /* Name of this TIFF file */ - TIFF *tif; /* TIFF file we write this layer to */ - PEL *tbuf; /* TIFF output buffer */ - PyramidTile tiles[IM_MAX_LAYER_BUFFER]; - - struct pyramid_layer *below; /* Tiles go to here */ - struct pyramid_layer *above; /* Tiles come from here */ -} PyramidLayer; - -/* A TIFF image in the process of being written. - */ -typedef struct tiff_write { - IMAGE *im; /* Original input image */ - char *name; /* Final name we write to */ - char *mode; /* Mode string */ - - /* Read from im with these. - */ - REGION *reg; - im_threadgroup_t *tg; - - char *bname; /* Name for base layer */ - TIFF *tif; /* Image we write to */ - - PyramidLayer *layer; /* Top of pyramid, if in use */ - PEL *tbuf; /* TIFF output buffer */ - int tls; /* Tile line size */ - - int compression; /* Compression type */ - int jpqual; /* JPEG q-factor */ - int predictor; /* Predictor value */ - int tile; /* Tile or not */ - int tilew, tileh; /* Tile size */ - int pyramid; /* Write pyramid */ - int onebit; /* Write as 1-bit TIFF */ - int resunit; /* Resolution unit (inches or cm) */ - float xres; /* Resolution in X */ - float yres; /* Resolution in Y */ - int embed; /* Embed ICC profile */ - char *icc_profile; /* Profile to embed */ -} TiffWrite; - -/* Use these from im_tiff2vips(). - */ -void im__thandler_error( char *module, char *fmt, va_list ap ); -void im__thandler_warning( char *module, char *fmt, va_list ap ); - -/* Open TIFF for output. - */ -static TIFF * -tiff_openout( const char *name ) -{ - TIFF *tif; - - if( !(tif = TIFFOpen( name, "w" )) ) { - im_error( "im_vips2tiff", - _( "unable to open \"%s\" for output" ), name ); - return( NULL ); - } - - return( tif ); -} - -/* Open TIFF for input. - */ -static TIFF * -tiff_openin( const char *name ) -{ - TIFF *tif; - - if( !(tif = TIFFOpen( name, "r" )) ) { - im_error( "im_vips2tiff", - _( "unable to open \"%s\" for input" ), name ); - return( NULL ); - } - - return( tif ); -} - -/* Convert VIPS LabQ to TIFF LAB. Just take the first three bands. - */ -static void -LabQ2LabC( PEL *q, PEL *p, int n ) -{ - int x; - - for( x = 0; x < n; x++ ) { - /* Get most significant 8 bits of lab. - */ - q[0] = p[0]; - q[1] = p[1]; - q[2] = p[2]; - - p += 4; - q += 3; - } -} - -/* Pack 8 bit VIPS to 1 bit TIFF. - */ -static void -eightbit2onebit( PEL *q, PEL *p, int n ) -{ - int x; - PEL bits; - - bits = 0; - for( x = 0; x < n; x++ ) { - bits <<= 1; - if( p[x] ) - bits |= 1; - - if( (x & 0x7) == 0x7 ) { - *q++ = bits; - bits = 0; - } - } - - /* Any left-over bits? Need to be left-aligned. - */ - if( (x & 0x7) != 0 ) - *q++ = bits << (8 - (x & 0x7)); -} - -/* Convert VIPS LABS to TIFF 16 bit LAB. - */ -static void -LabS2Lab16( PEL *q, PEL *p, int n ) -{ - int x; - short *p1 = (short *) p; - unsigned short *q1 = (unsigned short *) q; - - for( x = 0; x < n; x++ ) { - /* TIFF uses unsigned 16 bit ... move zero, scale up L. - */ - q1[0] = (int) p1[0] << 1; - q1[1] = p1[1]; - q1[2] = p1[2]; - - p1 += 3; - q1 += 3; - } -} - -/* Pack a VIPS region into a TIFF tile buffer. - */ -static void -pack2tiff( TiffWrite *tw, REGION *in, PEL *q, Rect *area ) -{ - int y; - - for( y = area->top; y < IM_RECT_BOTTOM( area ); y++ ) { - PEL *p = (PEL *) IM_REGION_ADDR( in, area->left, y ); - - if( in->im->Coding == IM_CODING_LABQ ) - LabQ2LabC( q, p, area->width ); - else if( tw->onebit ) - eightbit2onebit( q, p, area->width ); - else if( in->im->BandFmt == IM_BANDFMT_SHORT && - in->im->Type == IM_TYPE_LABS ) - LabS2Lab16( q, p, area->width ); - else - memcpy( q, p, - area->width * IM_IMAGE_SIZEOF_PEL( in->im ) ); - - q += tw->tls; - } -} - -/* Embed an ICC profile from a file. - */ -static int -embed_profile_file( TIFF *tif, const char *profile ) -{ - char *buffer; - unsigned int length; - - if( !(buffer = im__file_read_name( profile, &length )) ) - return( -1 ); - TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, buffer ); - im_free( buffer ); - -#ifdef DEBUG - printf( "im_vips2tiff: attached profile \"%s\"\n", profile ); -#endif /*DEBUG*/ - - return( 0 ); -} - -/* Embed an ICC profile from IMAGE metadata. - */ -static int -embed_profile_meta( TIFF *tif, IMAGE *im ) -{ - void *data; - size_t data_length; - - if( im_meta_get_blob( im, IM_META_ICC_NAME, &data, &data_length ) ) - return( -1 ); - TIFFSetField( tif, TIFFTAG_ICCPROFILE, data_length, data ); - -#ifdef DEBUG - printf( "im_vips2tiff: attached profile from meta\n" ); -#endif /*DEBUG*/ - - return( 0 ); -} - -static int -embed_profile( TiffWrite *tw, TIFF *tif ) -{ - if( tw->embed && embed_profile_file( tif, tw->icc_profile ) ) - return( -1 ); - if( !tw->embed && im_header_get_type( tw->im, IM_META_ICC_NAME ) && - embed_profile_meta( tif, tw->im ) ) - return( -1 ); - - return( 0 ); -} - -/* Write a TIFF header. width and height are the size of the IMAGE we are - * writing (may have been shrunk!). - */ -static int -write_tiff_header( TiffWrite *tw, TIFF *tif, int width, int height ) -{ - uint16 v[1]; - - /* Output base header fields. - */ - TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, width ); - TIFFSetField( tif, TIFFTAG_IMAGELENGTH, height ); - TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); - TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ); - TIFFSetField( tif, TIFFTAG_COMPRESSION, tw->compression ); - - /* Don't write mad resolutions (eg. zero), it confuses some programs. - */ - TIFFSetField( tif, TIFFTAG_RESOLUTIONUNIT, tw->resunit ); - TIFFSetField( tif, TIFFTAG_XRESOLUTION, - IM_CLIP( 0.01, tw->xres, 10000 ) ); - TIFFSetField( tif, TIFFTAG_YRESOLUTION, - IM_CLIP( 0.01, tw->yres, 10000 ) ); - - if( tw->compression == COMPRESSION_JPEG ) - TIFFSetField( tif, TIFFTAG_JPEGQUALITY, tw->jpqual ); - - if( tw->predictor != -1 ) - TIFFSetField( tif, TIFFTAG_PREDICTOR, tw->predictor ); - - /* Attach ICC profile. - */ - if( embed_profile( tw, tif ) ) - return( -1 ); - - /* And colour fields. - */ - if( tw->im->Coding == IM_CODING_LABQ ) { - TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 ); - TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 ); - TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB ); - } - else if( tw->onebit ) { - TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 ); - TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 ); - TIFFSetField( tif, - TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK ); - } - else { - int photometric; - - TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, tw->im->Bands ); - TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, tw->im->Bbits ); - - switch( tw->im->Bands ) { - case 1: - case 2: - photometric = PHOTOMETRIC_MINISBLACK; - if( tw->im->Bands == 2 ) { - v[0] = EXTRASAMPLE_ASSOCALPHA; - TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v ); - } - break; - - case 3: - case 4: - if( tw->im->Type == IM_TYPE_LAB || - tw->im->Type == IM_TYPE_LABS ) - photometric = PHOTOMETRIC_CIELAB; - else if( tw->im->Type == IM_TYPE_CMYK ) { - photometric = PHOTOMETRIC_SEPARATED; - TIFFSetField( tif, - TIFFTAG_INKSET, INKSET_CMYK ); - } - else - photometric = PHOTOMETRIC_RGB; - - if( tw->im->Type != IM_TYPE_CMYK && - tw->im->Bands == 4 ) { - v[0] = EXTRASAMPLE_ASSOCALPHA; - TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v ); - } - break; - - case 5: - if( tw->im->Type == IM_TYPE_CMYK ) { - photometric = PHOTOMETRIC_SEPARATED; - TIFFSetField( tif, - TIFFTAG_INKSET, INKSET_CMYK ); - } - break; - - default: - assert( 0 ); - } - - TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric ); - } - - /* Layout. - */ - if( tw->tile ) { - TIFFSetField( tif, TIFFTAG_TILEWIDTH, tw->tilew ); - TIFFSetField( tif, TIFFTAG_TILELENGTH, tw->tileh ); - } - else - TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, 16 ); - - /* Sample format ... for float, we write IEEE. - */ - if( tw->im->BandFmt == IM_BANDFMT_FLOAT ) - TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP ); - - return( 0 ); -} - -/* Free a pyramid layer. - */ -static void -free_layer( PyramidLayer *layer ) -{ - int i; - - for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) - if( layer->tiles[i].tile ) { - im_region_free( layer->tiles[i].tile ); - layer->tiles[i].tile = NULL; - } - - /* And close the TIFF file we are writing to. - */ - if( layer->tbuf ) { - im_free( layer->tbuf ); - layer->tbuf = NULL; - } - if( layer->tif ) { - TIFFClose( layer->tif ); - layer->tif = NULL; - } -} - -/* Free an entire pyramid. - */ -static void -free_pyramid( PyramidLayer *layer ) -{ - if( layer->below ) - free_pyramid( layer->below ); - - free_layer( layer ); -} - -/* Make a name for a new TIFF layer. Base it on sub factor. - */ -static char * -new_tiff_name( TiffWrite *tw, char *name, int sub ) -{ - char buf[FILENAME_MAX]; - char buf2[FILENAME_MAX]; - - /* Remove existing .tif/.tiff suffix, if any. - */ - strcpy( buf, name ); - if( im_ispostfix( buf, ".tif" ) ) - buf[strlen( buf ) - 4] = '\0'; - if( im_ispostfix( buf, ".tiff" ) ) - buf[strlen( buf ) - 5] = '\0'; - - im_snprintf( buf2, FILENAME_MAX, "%s.%d.tif", buf, sub ); - - return( im_strdup( tw->im, buf2 ) ); -} - -/* Build a pyramid. w & h are size of layer above this layer. Write new layer - * struct into *zap, return 0/-1 for success/fail. - */ -static int -build_pyramid( TiffWrite *tw, PyramidLayer *above, - PyramidLayer **zap, int w, int h ) -{ - PyramidLayer *layer = IM_NEW( tw->im, PyramidLayer ); - int i; - - if( !layer ) - return( -1 ); - layer->tw = tw; - layer->width = w / 2; - layer->height = h / 2; - - if( !above ) - /* Top of pyramid. - */ - layer->sub = 2; - else - layer->sub = above->sub * 2; - - layer->lname = NULL; - layer->tif = NULL; - layer->tbuf = NULL; - - for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) { - layer->tiles[i].tile = NULL; - layer->tiles[i].bits = PYR_NONE; - } - - layer->below = NULL; - layer->above = above; - - /* Save layer, to make sure it gets freed properly. - */ - *zap = layer; - - if( layer->width > tw->tilew || layer->height > tw->tileh ) - if( build_pyramid( tw, layer, - &layer->below, layer->width, layer->height ) ) - return( -1 ); - - if( !(layer->lname = new_tiff_name( tw, tw->name, layer->sub )) ) - return( -1 ); - - /* Make output image. - */ - if( !(layer->tif = tiff_openout( layer->lname )) ) - return( -1 ); - - /* Write the TIFF header for this layer. - */ - if( write_tiff_header( tw, layer->tif, layer->width, layer->height ) ) - return( -1 ); - - if( !(layer->tbuf = im_malloc( NULL, TIFFTileSize( layer->tif ) )) ) - return( -1 ); - - return( 0 ); -} - -/* Pick a new tile to write to in this layer. Either reuse a tile we have - * previously filled, or make a new one. - */ -static int -find_new_tile( PyramidLayer *layer ) -{ - int i; - - /* Exisiting buffer we have finished with? - */ - for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) - if( layer->tiles[i].bits == PYR_ALL ) - return( i ); - - /* Have to make a new one. - */ - for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) - if( !layer->tiles[i].tile ) { - if( !(layer->tiles[i].tile = - im_region_create( layer->tw->im )) ) - return( -1 ); - return( i ); - } - - /* Out of space! - */ - im_error( "im_vips2tiff", _( "layer buffer exhausted -- " - "try making TIFF output tiles smaller" ) ); - - return( -1 ); -} - -/* Find a tile in the layer buffer - if it's not there, make a new one. - */ -static int -find_tile( PyramidLayer *layer, Rect *pos ) -{ - int i; - Rect quad; - Rect image; - Rect inter; - - /* Do we have a REGION for this position? - */ - for( i = 0; i < IM_MAX_LAYER_BUFFER; i++ ) { - REGION *reg = layer->tiles[i].tile; - - if( reg && reg->valid.left == pos->left && - reg->valid.top == pos->top ) - return( i ); - } - - /* Make a new one. - */ - if( (i = find_new_tile( layer )) < 0 ) - return( -1 ); - if( im_region_buffer( layer->tiles[i].tile, pos ) ) - return( -1 ); - layer->tiles[i].bits = PYR_NONE; - - /* Do any quadrants of this tile fall entirely outside the image? - * If they do, set their bits now. - */ - quad.width = layer->tw->tilew / 2; - quad.height = layer->tw->tileh / 2; - image.left = 0; - image.top = 0; - image.width = layer->width; - image.height = layer->height; - - quad.left = pos->left; - quad.top = pos->top; - im_rect_intersectrect( &quad, &image, &inter ); - if( im_rect_isempty( &inter ) ) - layer->tiles[i].bits |= PYR_TL; - - quad.left = pos->left + quad.width; - quad.top = pos->top; - im_rect_intersectrect( &quad, &image, &inter ); - if( im_rect_isempty( &inter ) ) - layer->tiles[i].bits |= PYR_TR; - - quad.left = pos->left; - quad.top = pos->top + quad.height; - im_rect_intersectrect( &quad, &image, &inter ); - if( im_rect_isempty( &inter ) ) - layer->tiles[i].bits |= PYR_BL; - - quad.left = pos->left + quad.width; - quad.top = pos->top + quad.height; - im_rect_intersectrect( &quad, &image, &inter ); - if( im_rect_isempty( &inter ) ) - layer->tiles[i].bits |= PYR_BR; - - return( i ); -} - -/* Shrink a region by a factor of two, writing the result to a specified - * offset in another region. IM_CODING_LABQ only. - */ -static void -shrink_region_labpack( REGION *from, Rect *area, - REGION *to, int xoff, int yoff ) -{ - int ls = IM_REGION_LSKIP( from ); - Rect *t = &to->valid; - - int x, y; - Rect out; - - /* Calculate output size and position. - */ - out.left = t->left + xoff; - out.top = t->top + yoff; - out.width = area->width / 2; - out.height = area->height / 2; - - /* Shrink ... ignore the extension byte for speed. - */ - for( y = 0; y < out.height; y++ ) { - PEL *p = (PEL *) - IM_REGION_ADDR( from, area->left, area->top + y * 2 ); - PEL *q = (PEL *) - IM_REGION_ADDR( to, out.left, out.top + y ); - - for( x = 0; x < out.width; x++ ) { - signed char *sp = (signed char *) p; - unsigned char *up = (unsigned char *) p; - - int l = up[0] + up[4] + - up[ls] + up[ls + 4]; - int a = sp[1] + sp[5] + - sp[ls + 1] + sp[ls + 5]; - int b = sp[2] + sp[6] + - sp[ls + 2] + sp[ls + 6]; - - q[0] = l >> 2; - q[1] = a >> 2; - q[2] = b >> 2; - q[3] = 0; - - q += 4; - p += 8; - } - } -} - -#define SHRINK_TYPE_INT( TYPE ) \ - for( x = 0; x < out.width; x++ ) { \ - TYPE *tp = (TYPE *) p; \ - TYPE *tp1 = (TYPE *) (p + ls); \ - TYPE *tq = (TYPE *) q; \ - \ - for( z = 0; z < nb; z++ ) { \ - int tot = tp[z] + tp[z + nb] + \ - tp1[z] + tp1[z + nb]; \ - \ - tq[z] = tot >> 2; \ - } \ - \ - /* Move on two pels in input. \ - */ \ - p += ps << 1; \ - q += ps; \ - } - -#define SHRINK_TYPE_FLOAT( TYPE ) \ - for( x = 0; x < out.width; x++ ) { \ - TYPE *tp = (TYPE *) p; \ - TYPE *tp1 = (TYPE *) (p + ls); \ - TYPE *tq = (TYPE *) q; \ - \ - for( z = 0; z < nb; z++ ) { \ - double tot = (double) tp[z] + tp[z + nb] + \ - tp1[z] + tp1[z + nb]; \ - \ - tq[z] = tot / 4; \ - } \ - \ - /* Move on two pels in input. \ - */ \ - p += ps << 1; \ - q += ps; \ - } - -/* Shrink a region by a factor of two, writing the result to a specified - * offset in another region. n-band, non-complex. - */ -static void -shrink_region( REGION *from, Rect *area, - REGION *to, int xoff, int yoff ) -{ - int ls = IM_REGION_LSKIP( from ); - int ps = IM_IMAGE_SIZEOF_PEL( from->im ); - int nb = from->im->Bands; - Rect *t = &to->valid; - - int x, y, z; - Rect out; - - /* Calculate output size and position. - */ - out.left = t->left + xoff; - out.top = t->top + yoff; - out.width = area->width / 2; - out.height = area->height / 2; - - for( y = 0; y < out.height; y++ ) { - PEL *p = (PEL *) - IM_REGION_ADDR( from, area->left, area->top + y * 2 ); - PEL *q = (PEL *) - IM_REGION_ADDR( to, out.left, out.top + y ); - - /* Process this line of pels. - */ - switch( from->im->BandFmt ) { - case IM_BANDFMT_UCHAR: - SHRINK_TYPE_INT( unsigned char ); break; - case IM_BANDFMT_CHAR: - SHRINK_TYPE_INT( signed char ); break; - case IM_BANDFMT_USHORT: - SHRINK_TYPE_INT( unsigned short ); break; - case IM_BANDFMT_SHORT: - SHRINK_TYPE_INT( signed short ); break; - case IM_BANDFMT_UINT: - SHRINK_TYPE_INT( unsigned int ); break; - case IM_BANDFMT_INT: - SHRINK_TYPE_INT( signed int ); break; - case IM_BANDFMT_FLOAT: - SHRINK_TYPE_FLOAT( float ); break; - case IM_BANDFMT_DOUBLE: - SHRINK_TYPE_FLOAT( double ); break; - - default: - assert( 0 ); - } - } -} - -/* Write a tile from a layer. - */ -static int -save_tile( TiffWrite *tw, TIFF *tif, PEL *tbuf, REGION *reg, Rect *area ) -{ - /* Have to repack pixels. - */ - pack2tiff( tw, reg, tbuf, area ); - -#ifdef DEBUG - printf( "Writing %dx%d pixels at position %dx%d to image %s\n", - tw->tilew, tw->tileh, area->left, area->top, - TIFFFileName( tif ) ); -#endif /*DEBUG*/ - - /* Write to TIFF! easy. - */ - if( TIFFWriteTile( tif, tbuf, area->left, area->top, 0, 0 ) < 0 ) { - im_error( "im_vips2tiff", _( "TIFF write tile failed" ) ); - return( -1 ); - } - - return( 0 ); -} - -/* A new tile has arrived! Shrink into this layer, if we fill a region, write - * it and recurse. - */ -static int -new_tile( PyramidLayer *layer, REGION *tile, Rect *area ) -{ - TiffWrite *tw = layer->tw; - int xoff, yoff; - - int t, ri, bo; - Rect out, new; - PyramidBits bit; - - /* Calculate pos and size of new pixels we make inside this layer. - */ - new.left = area->left / 2; - new.top = area->top / 2; - new.width = area->width / 2; - new.height = area->height / 2; - - /* Has size fallen to zero? Can happen if this is a one-pixel-wide - * strip. - */ - if( im_rect_isempty( &new ) ) - return( 0 ); - - /* Offset into this tile ... ie. which quadrant we are writing. - */ - xoff = new.left % layer->tw->tilew; - yoff = new.top % layer->tw->tileh; - - /* Calculate pos for tile we shrink into in this layer. - */ - out.left = new.left - xoff; - out.top = new.top - yoff; - - /* Clip against edge of image. - */ - ri = IM_MIN( layer->width, out.left + layer->tw->tilew ); - bo = IM_MIN( layer->height, out.top + layer->tw->tileh ); - out.width = ri - out.left; - out.height = bo - out.top; - - if( (t = find_tile( layer, &out )) < 0 ) - return( -1 ); - - /* Shrink into place. - */ - if( tw->im->Coding == IM_CODING_NONE ) - shrink_region( tile, area, - layer->tiles[t].tile, xoff, yoff ); - else - shrink_region_labpack( tile, area, - layer->tiles[t].tile, xoff, yoff ); - - /* Set that bit. - */ - if( xoff ) - if( yoff ) - bit = PYR_BR; - else - bit = PYR_TR; - else - if( yoff ) - bit = PYR_BL; - else - bit = PYR_TL; - if( layer->tiles[t].bits & bit ) { - im_error( "im_vips2tiff", _( "internal error #9876345" ) ); - return( -1 ); - } - layer->tiles[t].bits |= bit; - - if( layer->tiles[t].bits == PYR_ALL ) { - /* Save this complete tile. - */ - if( save_tile( tw, layer->tif, layer->tbuf, - layer->tiles[t].tile, &layer->tiles[t].tile->valid ) ) - return( -1 ); - - /* And recurse down the pyramid! - */ - if( layer->below && - new_tile( layer->below, - layer->tiles[t].tile, - &layer->tiles[t].tile->valid ) ) - return( -1 ); - } - - return( 0 ); -} - -/* Write as tiles. - */ -static int -write_tif_tile( TiffWrite *tw ) -{ - IMAGE *im = tw->im; - Rect area; - int x, y; - - if( !(tw->tbuf = im_malloc( NULL, TIFFTileSize( tw->tif ) )) ) - return( -1 ); - - /* Write pyramid too? Only bother if bigger than tile size. - */ - if( tw->pyramid && - (im->Xsize > tw->tilew || im->Ysize > tw->tileh) && - build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) ) - return( -1 ); - - for( y = 0; y < im->Ysize; y += tw->tileh ) - for( x = 0; x < im->Xsize; x += tw->tilew ) { - /* Set up rect we write. - */ - area.left = x; - area.top = y; - area.width = IM_MIN( tw->tilew, im->Xsize - x ); - area.height = IM_MIN( tw->tileh, im->Ysize - y ); - - if( im_prepare_thread( tw->tg, tw->reg, &area ) ) - return( -1 ); - - /* Write to TIFF. - */ - if( save_tile( tw, tw->tif, tw->tbuf, tw->reg, &area ) ) - return( -1 ); - - /* Is there a pyramid? Write to that too. - */ - if( tw->layer && new_tile( tw->layer, tw->reg, &area ) ) - return( -1 ); - } - - return( 0 ); -} - -static int -write_tif_block( REGION *region, Rect *area, void *a, void *b ) -{ - TiffWrite *tw = (TiffWrite *) a; - IMAGE *im = tw->im; - - int y; - - for( y = 0; y < area->height; y++ ) { - PEL *p = (PEL *) IM_REGION_ADDR( region, 0, area->top + y ); - - /* Any repacking necessary. - */ - if( im->Coding == IM_CODING_LABQ ) { - LabQ2LabC( tw->tbuf, p, im->Xsize ); - p = tw->tbuf; - } - else if( im->BandFmt == IM_BANDFMT_SHORT && - im->Type == IM_TYPE_LABS ) { - LabS2Lab16( tw->tbuf, p, im->Xsize ); - p = tw->tbuf; - } - else if( tw->onebit ) { - eightbit2onebit( tw->tbuf, p, im->Xsize ); - p = tw->tbuf; - } - - if( TIFFWriteScanline( tw->tif, p, area->top + y, 0 ) < 0 ) - return( -1 ); - } - - return( 0 ); -} - -/* Write as scan-lines. - */ -static int -write_tif_strip( TiffWrite *tw ) -{ - g_assert( !tw->tbuf ); - - if( !(tw->tbuf = im_malloc( NULL, TIFFScanlineSize( tw->tif ) )) ) - return( -1 ); - - if( im_wbuffer( tw->tg, write_tif_block, tw, NULL ) ) - return( -1 ); - - return( 0 ); -} - -/* Delete any temp files we wrote. - */ -static void -delete_files( TiffWrite *tw ) -{ - PyramidLayer *layer = tw->layer; - - if( tw->bname ) { - unlink( tw->bname ); - tw->bname = NULL; - } - - for( layer = tw->layer; layer; layer = layer->below ) - if( layer->lname ) { - unlink( layer->lname ); - layer->lname = NULL; - } -} - -/* Free a TiffWrite. - */ -static void -free_tiff_write( TiffWrite *tw ) -{ -#ifndef DEBUG - delete_files( tw ); -#endif /*DEBUG*/ - - if( tw->tg ) { - im_threadgroup_free( tw->tg ); - tw->tg = NULL; - } - if( tw->reg ) { - im_region_free( tw->reg ); - tw->reg = NULL; - } - if( tw->tif ) { - TIFFClose( tw->tif ); - tw->tif = NULL; - } - if( tw->tbuf ) { - im_free( tw->tbuf ); - tw->tbuf = NULL; - } - if( tw->layer ) - free_pyramid( tw->layer ); - if( tw->icc_profile ) { - im_free( tw->icc_profile ); - tw->icc_profile = NULL; - } -} - -/* Round N down to P boundary. - */ -#define ROUND_DOWN(N,P) ((N) - ((N) % P)) - -/* Round N up to P boundary. - */ -#define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) )) - -/* Make and init a TiffWrite. - */ -static TiffWrite * -make_tiff_write( IMAGE *im, const char *filename ) -{ - TiffWrite *tw; - char *p, *q, *r; - char name[FILENAME_MAX]; - char mode[FILENAME_MAX]; - char buf[FILENAME_MAX]; - - if( !(tw = IM_NEW( im, TiffWrite )) ) - return( NULL ); - tw->im = im; - im_filename_split( filename, name, mode ); - tw->name = im_strdup( im, name ); - tw->mode = im_strdup( im, mode ); - tw->tg = NULL; - tw->reg = NULL; - tw->bname = NULL; - tw->tif = NULL; - tw->layer = NULL; - tw->tbuf = NULL; - tw->compression = COMPRESSION_NONE; - tw->jpqual = 75; - tw->predictor = -1; - tw->tile = 0; - tw->tilew = 128; - tw->tileh = 128; - tw->pyramid = 0; - tw->onebit = 0; - tw->embed = 0; - tw->icc_profile = NULL; - - /* Output resolution settings ... default to VIPS-alike. - */ - tw->resunit = RESUNIT_CENTIMETER; - tw->xres = im->Xres * 10; - tw->yres = im->Yres * 10; - if( !im_meta_get_string( im, IM_META_RESOLUTION_UNIT, &p ) && - strcmp( p, "in" ) == 0 ) { - tw->resunit = RESUNIT_INCH; - tw->xres *= 2.54; - tw->yres *= 2.54; - } - - /* Parse mode string. - */ - strcpy( buf, mode ); - p = &buf[0]; - if( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "none", q ) ) - tw->compression = COMPRESSION_NONE; - else if( im_isprefix( "packbits", q ) ) - tw->compression = COMPRESSION_PACKBITS; - else if( im_isprefix( "ccittfax4", q ) ) - tw->compression = COMPRESSION_CCITTFAX4; - else if( im_isprefix( "lzw", q ) ) { - tw->compression = COMPRESSION_LZW; - - if( (r = im_getsuboption( q )) ) - if( sscanf( r, "%d", &tw->predictor ) != 1 ) { - im_error( "im_vips2tiff", - _( "bad predictor " - "parameter" ) ); - return( NULL ); - } - } - else if( im_isprefix( "deflate", q ) ) { - tw->compression = COMPRESSION_ADOBE_DEFLATE; - - if( (r = im_getsuboption( q )) ) - if( sscanf( r, "%d", &tw->predictor ) != 1 ) { - im_error( "im_vips2tiff", - _( "bad predictor " - "parameter" ) ); - return( NULL ); - } - } - else if( im_isprefix( "jpeg", q ) ) { - tw->compression = COMPRESSION_JPEG; - - if( (r = im_getsuboption( q )) ) - if( sscanf( r, "%d", &tw->jpqual ) != 1 ) { - im_error( "im_vips2tiff", - _( "bad JPEG quality " - "parameter" ) ); - return( NULL ); - } - } - else { - im_error( "im_vips2tiff", _( "unknown compression mode " - "\"%s\"\nshould be one of \"none\", " - "\"packbits\", \"ccittfax4\", \"lzw\", " - "\"deflate\" or \"jpeg\"" ), q ); - return( NULL ); - } - } - if( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "tile", q ) ) { - tw->tile = 1; - - if( (r = im_getsuboption( q )) ) { - if( sscanf( r, "%dx%d", - &tw->tilew, &tw->tileh ) != 2 ) { - im_error( "im_vips2tiff", _( "bad tile " - "sizes" ) ); - return( NULL ); - } - - if( tw->tilew < 10 || tw->tileh < 10 || - tw->tilew > 1000 || tw->tileh > 1000 ) { - im_error( "im_vips2tiff", _( "bad tile " - "size %dx%d" ), - tw->tilew, tw->tileh ); - return( NULL ); - } - - if( (tw->tilew & 0xf) != 0 || - (tw->tileh & 0xf) != 0 ) { - im_error( "im_vips2tiff", _( "tile " - "size not a multiple of 16" ) ); - return( NULL ); - } - } - } - else if( im_isprefix( "strip", q ) ) - tw->tile = 0; - else { - im_error( "im_vips2tiff", _( "unknown layout mode " - "\"%s\"\nshould be one of \"tile\" or " - "\"strip\"" ), q ); - return( NULL ); - } - } - if( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "pyramid", q ) ) - tw->pyramid = 1; - else if( im_isprefix( "flat", q ) ) - tw->pyramid = 0; - else { - im_error( "im_vips2tiff", _( "unknown multi-res mode " - "\"%s\"\nshould be one of \"flat\" or " - "\"pyramid\"" ), q ); - return( NULL ); - } - } - if( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "onebit", q ) ) - tw->onebit = 1; - else if( im_isprefix( "manybit", q ) ) - tw->onebit = 0; - else { - im_error( "im_vips2tiff", _( "unknown format " - "\"%s\"\nshould be one of \"onebit\" or " - "\"manybit\"" ), q ); - return( NULL ); - } - } - if( (q = im_getnextoption( &p )) ) { - if( im_isprefix( "res_cm", q ) ) { - if( tw->resunit == RESUNIT_INCH ) { - tw->xres /= 2.54; - tw->yres /= 2.54; - } - tw->resunit = RESUNIT_CENTIMETER; - } - else if( im_isprefix( "res_inch", q ) ) { - if( tw->resunit == RESUNIT_CENTIMETER ) { - tw->xres *= 2.54; - tw->yres *= 2.54; - } - tw->resunit = RESUNIT_INCH; - } - else { - im_error( "im_vips2tiff", _( "unknown resolution unit " - "\"%s\"\nshould be one of \"res_cm\" or " - "\"res_inch\"" ), q ); - return( NULL ); - } - - if( (r = im_getsuboption( q )) ) { - if( sscanf( r, "%fx%f", &tw->xres, &tw->yres ) != 2 ) { - if( sscanf( r, "%f", &tw->xres ) != 1 ) { - im_error( "im_vips2tiff", _( "bad " - "resolution values" ) ); - return( NULL ); - } - - tw->yres = tw->xres; - } - } - } - if( (q = im_getnextoption( &p )) && strcmp( q, "" ) != 0 ) { - tw->embed = 1; - tw->icc_profile = im_strdup( NULL, q ); - } - if( (q = im_getnextoption( &p )) ) { - im_error( "im_vips2tiff", - _( "unknown extra options \"%s\"" ), q ); - return( NULL ); - } - if( !tw->tile && tw->pyramid ) { - im_warn( "im_vips2tiff", _( "can't have strip pyramid -- " - "enabling tiling" ) ); - tw->tile = 1; - } - - /* We can only pyramid LABQ and non-complex images. - */ - if( tw->pyramid ) { - if( im->Coding == IM_CODING_NONE && im_iscomplex( im ) ) { - im_error( "im_vips2tiff", - _( "can only pyramid LABQ and " - "non-complex images" ) ); - return( NULL ); - } - } - - /* Only 1-bit-ize 8 bit mono images. - */ - if( tw->onebit ) { - if( im->Coding != IM_CODING_NONE || - im->BandFmt != IM_BANDFMT_UCHAR || - im->Bands != 1 ) - tw->onebit = 0; - } - - if( tw->onebit && tw->compression == COMPRESSION_JPEG ) { - im_warn( "im_vips2tiff", _( "can't have 1-bit JPEG -- " - "disabling JPEG" ) ); - tw->compression = COMPRESSION_NONE; - } - - /* Make region and threadgroup. - */ - if( !(tw->reg = im_region_create( tw->im )) || - !(tw->tg = im_threadgroup_create( tw->im )) ) { - free_tiff_write( tw ); - return( NULL ); - } - - /* Sizeof a line of bytes in the TIFF tile. - */ - if( im->Coding == IM_CODING_LABQ ) - tw->tls = tw->tilew * 3; - else if( tw->onebit ) - tw->tls = ROUND_UP( tw->tilew, 8 ) / 8; - else - tw->tls = IM_IMAGE_SIZEOF_PEL( im ) * tw->tilew; - - return( tw ); -} - -/* Copy fields. - */ -#define CopyField( tag, v ) \ - if( TIFFGetField( in, tag, &v ) ) TIFFSetField( out, tag, v ) - -/* Copy a TIFF file ... we know we wrote it, so just copy the tags we know - * we might have set. - */ -static int -tiff_copy( TiffWrite *tw, TIFF *out, TIFF *in ) -{ - uint32 i32; - uint16 i16; - float f; - tdata_t buf; - ttile_t tile; - ttile_t n; - - /* All the fields we might have set. - */ - CopyField( TIFFTAG_IMAGEWIDTH, i32 ); - CopyField( TIFFTAG_IMAGELENGTH, i32 ); - CopyField( TIFFTAG_PLANARCONFIG, i16 ); - CopyField( TIFFTAG_ORIENTATION, i16 ); - CopyField( TIFFTAG_XRESOLUTION, f ); - CopyField( TIFFTAG_YRESOLUTION, f ); - CopyField( TIFFTAG_RESOLUTIONUNIT, i16 ); - CopyField( TIFFTAG_COMPRESSION, i16 ); - CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 ); - CopyField( TIFFTAG_BITSPERSAMPLE, i16 ); - CopyField( TIFFTAG_PHOTOMETRIC, i16 ); - CopyField( TIFFTAG_TILEWIDTH, i32 ); - CopyField( TIFFTAG_TILELENGTH, i32 ); - CopyField( TIFFTAG_ROWSPERSTRIP, i32 ); - - if( tw->predictor != -1 ) - TIFFSetField( out, TIFFTAG_PREDICTOR, tw->predictor ); - - /* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it. - * Set explicitly from TiffWrite. - */ - if( tw->compression == COMPRESSION_JPEG ) - TIFFSetField( out, TIFFTAG_JPEGQUALITY, tw->jpqual ); - - /* We can't copy profiles :( Set again from TiffWrite. - */ - if( embed_profile( tw, out ) ) - return( -1 ); - - buf = im_malloc( NULL, TIFFTileSize( in ) ); - n = TIFFNumberOfTiles( in ); - for( tile = 0; tile < n; tile++ ) { - tsize_t len; - - /* It'd be good to use TIFFReadRawTile()/TIFFWriteRawTile() - * here to save compression/decompression, but sadly it seems - * not to work :-( investigate at some point. - */ - len = TIFFReadEncodedTile( in, tile, buf, (tsize_t) -1 ); - if( len < 0 || - TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) { - im_free( buf ); - return( -1 ); - } - } - im_free( buf ); - - return( 0 ); -} - -/* Append a file to a TIFF file. - */ -static int -tiff_append( TiffWrite *tw, TIFF *out, const char *name ) -{ - TIFF *in; - - if( !(in = tiff_openin( name )) ) - return( -1 ); - - if( tiff_copy( tw, out, in ) ) { - TIFFClose( in ); - return( -1 ); - } - TIFFClose( in ); - - if( !TIFFWriteDirectory( out ) ) - return( -1 ); - - return( 0 ); -} - -/* Gather all of the files we wrote into single output file. - */ -static int -gather_pyramid( TiffWrite *tw ) -{ - PyramidLayer *layer; - TIFF *out; - -#ifdef DEBUG - printf( "Starting pyramid gather ...\n" ); -#endif /*DEBUG*/ - - if( !(out = tiff_openout( tw->name )) ) - return( -1 ); - - if( tiff_append( tw, out, tw->bname ) ) { - TIFFClose( out ); - return( -1 ); - } - - for( layer = tw->layer; layer; layer = layer->below ) - if( tiff_append( tw, out, layer->lname ) ) { - TIFFClose( out ); - return( -1 ); - } - - TIFFClose( out ); - -#ifdef DEBUG - printf( "Pyramid built\n" ); -#endif /*DEBUG*/ - - return( 0 ); -} - -int -im_vips2tiff( IMAGE *im, const char *filename ) -{ - TiffWrite *tw; - int res; - -#ifdef DEBUG - printf( "im_tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() ); -#endif /*DEBUG*/ - - /* Override the default TIFF error handler. - */ - TIFFSetErrorHandler( (TIFFErrorHandler) im__thandler_error ); - TIFFSetWarningHandler( (TIFFErrorHandler) im__thandler_warning ); - - /* Check input image. - */ - if( im_pincheck( im ) ) - return( -1 ); - if( im->Coding != IM_CODING_LABQ && im->Coding != IM_CODING_NONE ) { - im_error( "im_vips2tiff", _( "unknown coding type" ) ); - return( -1 ); - } - if( im->BandFmt != IM_BANDFMT_UCHAR && - !(im->BandFmt == IM_BANDFMT_SHORT && - im->Type == IM_TYPE_LABS) && - im->BandFmt != IM_BANDFMT_USHORT && - im->BandFmt != IM_BANDFMT_FLOAT ) { - im_error( "im_vips2tiff", _( "unsigned 8-bit int, 16-bit int, " - "and 32-bit float only" ) ); - return( -1 ); - } - if( im->Coding == IM_CODING_NONE ) { - if( im->Bands < 1 || im->Bands > 5 ) { - im_error( "im_vips2tiff", _( "1 to 5 bands only" ) ); - return( -1 ); - } - } - - /* Make output image. If this is a pyramid, write the base image to - * fred.1.tif rather than fred.tif. - */ - if( !(tw = make_tiff_write( im, filename )) ) - return( -1 ); - if( tw->pyramid ) { - if( !(tw->bname = new_tiff_name( tw, tw->name, 1 )) || - !(tw->tif = tiff_openout( tw->bname )) ) { - free_tiff_write( tw ); - return( -1 ); - } - } - else { - /* No pyramid ... write straight to name. - */ - if( !(tw->tif = tiff_openout( tw->name )) ) { - free_tiff_write( tw ); - return( -1 ); - } - } - - /* Write the TIFF header for the full-res file. - */ - if( write_tiff_header( tw, tw->tif, im->Xsize, im->Ysize ) ) { - free_tiff_write( tw ); - return( -1 ); - } - - if( tw->tile ) - res = write_tif_tile( tw ); - else - res = write_tif_strip( tw ); - if( res ) { - free_tiff_write( tw ); - return( -1 ); - } - - /* Free pyramid resources ... this will TIFFClose() the intermediates, - * ready for us to read from them again. - */ - if( tw->layer ) - free_pyramid( tw->layer ); - if( tw->tif ) { - TIFFClose( tw->tif ); - tw->tif = NULL; - } - - /* Gather layers together into final pyramid file. - */ - if( tw->pyramid && gather_pyramid( tw ) ) { - free_tiff_write( tw ); - return( -1 ); - } - - free_tiff_write( tw ); - - return( 0 ); -} - -#endif /*HAVE_TIFF*/ diff --git a/libsrc/format/Makefile.am b/libsrc/format/Makefile.am index 86aadbbd..a80a6d17 100644 --- a/libsrc/format/Makefile.am +++ b/libsrc/format/Makefile.am @@ -18,6 +18,7 @@ libformat_la_SOURCES = \ im_vips2jpeg.c \ im_vips2png.c \ im_vips2ppm.c \ - im_vips2tiff.c + im_vips2tiff.c \ + im_vips2raw.c INCLUDES = -I${top_srcdir}/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libsrc/format/format_dispatch.c b/libsrc/format/format_dispatch.c index a48ee804..c19207c0 100644 --- a/libsrc/format/format_dispatch.c +++ b/libsrc/format/format_dispatch.c @@ -1,6 +1,4 @@ -/* VIPS function dispatch tables for conversion. - * - * J. Cupitt, 8/4/93. +/* VIPS function dispatch tables for image format load/save. */ /* @@ -418,6 +416,56 @@ im_package im__format = { list }; +/* TIFF flags function. + */ +static im_format_flags +tiff_flags( const char *filename ) +{ + im_format_flags flags; + + flags = 0; + if( im_istifftiled( filename ) ) + flags |= IM_FORMAT_FLAG_PARTIAL; + + return( flags ); +} + +/* OpenEXR flags function. + */ +static im_format_flags +exr_flags( const char *filename ) +{ + im_format_flags flags; + + flags = 0; + if( im_isexrtiled( filename ) ) + flags |= IM_FORMAT_FLAG_PARTIAL; + + return( flags ); +} + +/* ppm flags function. + */ +static im_format_flags +ppm_flags( const char *filename ) +{ + im_format_flags flags; + + flags = 0; + if( im_isppmmmap( filename ) ) + flags |= IM_FORMAT_FLAG_PARTIAL; + + return( flags ); +} + +/* Analyze flags function. + */ +static im_format_flags +analyze_flags( const char *filename ) +{ + return( IM_FORMAT_FLAG_PARTIAL ); +} + /* Suffix sets. */ static const char *tiff_suffs[] = { ".tif", ".tiff", NULL }; @@ -439,7 +487,8 @@ static im_format jpeg_desc = { im_isjpeg, /* is_a */ im_jpeg2vips_header, /* Load header only */ im_jpeg2vips, /* Load */ - im_vips2jpeg /* Save */ + im_vips2jpeg, /* Save */ + NULL /* Flags */ }; static im_format tiff_desc = { @@ -450,7 +499,8 @@ static im_format tiff_desc = { im_istiff, /* is_a */ im_tiff2vips_header, /* Load header only */ im_tiff2vips, /* Load */ - im_vips2tiff /* Save */ + im_vips2tiff, /* Save */ + tiff_flags /* Flags */ }; static im_format png_desc = { @@ -461,7 +511,8 @@ static im_format png_desc = { im_ispng, /* is_a */ im_png2vips_header, /* Load header only */ im_png2vips, /* Load */ - im_vips2png /* Save */ + im_vips2png, /* Save */ + NULL /* Flags */ }; static im_format csv_desc = { @@ -472,7 +523,8 @@ static im_format csv_desc = { NULL, /* is_a */ im_csv2vips_header, /* Load header only */ im_csv2vips, /* Load */ - im_vips2csv /* Save */ + im_vips2csv, /* Save */ + NULL /* Flags */ }; static im_format ppm_desc = { @@ -483,7 +535,8 @@ static im_format ppm_desc = { im_isppm, /* is_a */ im_ppm2vips_header, /* Load header only */ im_ppm2vips, /* Load */ - im_vips2ppm /* Save */ + im_vips2ppm, /* Save */ + ppm_flags /* Flags */ }; static im_format analyze_desc = { @@ -494,7 +547,8 @@ static im_format analyze_desc = { im_isanalyze, /* is_a */ im_analyze2vips_header, /* Load header only */ im_analyze2vips, /* Load */ - NULL /* Save */ + NULL, /* Save */ + analyze_flags /* Flags */ }; static im_format exr_desc = { @@ -505,31 +559,43 @@ static im_format exr_desc = { im_isexr, /* is_a */ im_exr2vips_header, /* Load header only */ im_exr2vips, /* Load */ - NULL /* Save */ + NULL, /* Save */ + exr_flags /* Flags */ }; static im_format magick_desc = { "magick", /* internal name */ - N_( "ImageMagick-supported format" ), /* i18n'd visible name */ + N_( "libMagick-supported" ), /* i18n'd visible name */ -1000, /* Priority */ magick_suffs, /* Allowed suffixes */ im_ismagick, /* is_a */ im_magick2vips_header, /* Load header only */ im_magick2vips, /* Load */ - NULL /* Save */ + NULL, /* Save */ + NULL /* Flags */ }; /* Package up all these formats. */ static im_format *format_list[] = { - &csv_desc, +#ifdef HAVE_JPEG &jpeg_desc, - &magick_desc, +#endif /*HAVE_JPEG*/ +#ifdef HAVE_TIFF + &tiff_desc, +#endif /*HAVE_TIFF*/ +#ifdef HAVE_PNG &png_desc, +#endif /*HAVE_PNG*/ +#ifdef HAVE_OPENEXR &exr_desc, +#endif /*HAVE_OPENEXR*/ &ppm_desc, &analyze_desc, - &tiff_desc + &csv_desc, +#ifdef HAVE_MAGICK + &magick_desc +#endif /*HAVE_MAGICK*/ }; /* Package of format. diff --git a/libsrc/format/im_exr2vips.c b/libsrc/format/im_exr2vips.c index c5e58686..f5188c60 100644 --- a/libsrc/format/im_exr2vips.c +++ b/libsrc/format/im_exr2vips.c @@ -76,6 +76,13 @@ im_exr2vips_header( const char *name, IMAGE *out ) return( -1 ); } +int +im_isexrtiled( const char *name ) +{ + im_error( "im_isexrtiled", _( "OpenEXR support disabled" ) ); + return( -1 ); +} + #else /*HAVE_OPENEXR*/ #include @@ -166,7 +173,7 @@ read_new( const char *name, IMAGE *out ) #ifdef DEBUG if( read->tiles ) - printf( "im_exr2vips: opening in tiles mode\n" ); + printf( "im_exr2vips: opening in tiled mode\n" ); else printf( "im_exr2vips: opening in scanline mode\n" ); #endif /*DEBUG*/ @@ -223,6 +230,22 @@ im_exr2vips_header( const char *name, IMAGE *out ) return( 0 ); } +/* Test for tiled EXR. + */ +int +im_isexrtiled( const char *name ) +{ + Read *read; + int tiled; + + if( !(read = read_new( name, NULL )) ) + return( -1 ); + tiled = read->tiles != NULL; + read_destroy( read ); + + return( tiled ); +} + static int fill_region( REGION *out, void *seq, void *a, void *b ) { diff --git a/libsrc/format/im_ppm2vips.c b/libsrc/format/im_ppm2vips.c index 2e188dc8..e8490fc6 100644 --- a/libsrc/format/im_ppm2vips.c +++ b/libsrc/format/im_ppm2vips.c @@ -414,6 +414,41 @@ im_ppm2vips_header( const char *filename, IMAGE *out ) return( 0 ); } +/* Can this PPM file be read with a mmap? + */ +int +im_isppmmmap( const char *filename ) +{ + IMAGE *im; + FILE *fp; + int bits; + int ascii; + +#ifdef BINARY_OPEN + if( !(fp = fopen( filename, "rb" )) ) { +#else /*BINARY_OPEN*/ + if( !(fp = fopen( filename, "r" )) ) { +#endif /*BINARY_OPEN*/ + im_error( "im_ppm2vips_header", + _( "unable to open \"%s\"" ), filename ); + return( -1 ); + } + + if( !(im = im_open( "temp", "p" )) ) { + fclose( fp ); + return( 0 ); + } + if( read_header( fp, im, &bits, &ascii ) ) { + im_close( im ); + fclose( fp ); + return( 0 ); + } + im_close( im ); + fclose( fp ); + + return( !ascii && bits >= 8 ); +} + int im_ppm2vips( const char *filename, IMAGE *out ) { diff --git a/libsrc/format/im_vips2raw.c b/libsrc/format/im_vips2raw.c new file mode 100644 index 00000000..cdcf7a8c --- /dev/null +++ b/libsrc/format/im_vips2raw.c @@ -0,0 +1,127 @@ +/* Write raw image data to file. Usefull when defining new formats... + * + * Jesper Friis + * + * 10/06/08 JF + * - initial code based on im_vips2ppm() + * + * 04/07/08 JF + * - replaced FILE with plain file handlers for reducing + * confusion about binary vs. non-binary file modes. + */ + + +/* + This file is part of the QED plugin to 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + + + +/* What we track during a write + */ +typedef struct { + IMAGE *in; + im_threadgroup_t *tg; + int fd; +} Write; + + + +static void +write_destroy( Write *write ) +{ + IM_FREEF( im_threadgroup_free, write->tg ); + im_free( write ); +} + + +static Write * +write_new( IMAGE *in, int fd ) +{ + Write *write; + + if( !(write = IM_NEW( NULL, Write )) ) + return( NULL ); + + write->in = in; + write->tg = im_threadgroup_create( write->in ); + write->fd = fd; + + if( !write->tg || !write->fd ) { + write_destroy( write ); + return( NULL ); + } + + return( write ); +} + + +static int +write_block( REGION *region, Rect *area, void *a, void *b ) +{ + Write *write = (Write *) a; + int i; + + for( i = 0; i < area->height; i++ ) { + PEL *p = (PEL *) IM_REGION_ADDR( region, area->left, area->top + i ); + if( im__write( write->fd, p, IM_IMAGE_SIZEOF_PEL(write->in)*area->width ) ) + return( -1 ); + } + + return( 0 ); +} + + +int +im_vips2raw( IMAGE *in, int fd ) +{ + Write *write; + + if( im_pincheck( in ) || !(write = write_new( in, fd )) ) + return( -1 ); + + if( im_wbuffer( write->tg, write_block, write, NULL ) ) { + write_destroy( write ); + return( -1 ); + } + + write_destroy( write ); + return( 0 ); +} + diff --git a/libsrc/format/is_a.c b/libsrc/format/is_a.c index d5d7c0e6..69934b8a 100644 --- a/libsrc/format/is_a.c +++ b/libsrc/format/is_a.c @@ -59,6 +59,9 @@ #endif /*HAVE_CONFIG_H*/ #include +#ifdef HAVE_UNISTD_H +#include +#endif /*HAVE_UNISTD_H*/ #include #include #include diff --git a/libsrc/iofuncs/Makefile.am b/libsrc/iofuncs/Makefile.am index 2d819af7..b20c096c 100644 --- a/libsrc/iofuncs/Makefile.am +++ b/libsrc/iofuncs/Makefile.am @@ -15,7 +15,6 @@ libiofuncs_la_SOURCES = \ im_cp_desc.c \ im_debugim.c \ im_demand_hint.c \ - im_desc_hd.c \ im_generate.c \ im_header.c \ im_histlin.c \ @@ -26,15 +25,13 @@ libiofuncs_la_SOURCES = \ im_iterate.c \ im_makerw.c \ im_mapfile.c \ - im_openin.c \ im_open.c \ - im_openout.c \ + im_open_vips.c \ im_partial.c \ im_piocheck.c \ im_prepare.c \ im_printdesc.c \ im_printlines.c \ - im_readhist.c \ im_render.c \ im_setbox.c \ im_setbuf.c \ @@ -58,6 +55,6 @@ libiofuncs_la_SOURCES = \ vbuf.c \ window.c \ buffer.c \ - time.c + time.c INCLUDES = -I${top_srcdir}/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libsrc/iofuncs/dispatch_types.c b/libsrc/iofuncs/dispatch_types.c index 14771972..692cd4d0 100644 --- a/libsrc/iofuncs/dispatch_types.c +++ b/libsrc/iofuncs/dispatch_types.c @@ -119,8 +119,8 @@ im_type_desc im__input_image = { IM_TYPE_IMAGE, /* Its an image */ 0, /* No storage needed */ IM_TYPE_ARG, /* It requires a command-line arg */ - (im_init_obj_fn) input_image_init, /* Init function */ - (im_dest_obj_fn) im_close /* Destroy function */ + (im_init_obj_fn) input_image_init,/* Init function */ + (im_dest_obj_fn) im_close/* Destroy function */ }; /* Init function for output images. @@ -347,7 +347,7 @@ im_type_desc im__output_dmask = { sizeof( im_mask_object ),/* Storage for mask object */ IM_TYPE_OUTPUT | IM_TYPE_ARG, /* Flags */ mask_init, /* Init function */ - save_dmask_dest /* Save and destroy function */ + save_dmask_dest /* Save and destroy function */ }; /* Input dmask type. @@ -367,7 +367,7 @@ im_type_desc im__output_imask = { sizeof( im_mask_object ),/* Storage for mask object */ IM_TYPE_OUTPUT | IM_TYPE_ARG, /* Flags */ mask_init, /* Init function */ - save_imask_dest /* Save and destroy function */ + save_imask_dest /* Save and destroy function */ }; /* Input imask type. @@ -585,8 +585,8 @@ im_type_desc im__output_intvec = { IM_TYPE_INTVEC, /* It's an array of int */ sizeof( im_intvec_object ), /* Memory to allocate in vec build */ IM_TYPE_OUTPUT, /* Output arg */ - NULL, /* Init function */ - intvec_dest /* Destroy function */ + (im_init_obj_fn)NULL, /* Init function */ + (im_dest_obj_fn)intvec_dest /* Destroy function */ }; /* Init function for int input. @@ -632,7 +632,7 @@ im_type_desc im__input_string = { 0, /* Memory to allocate */ IM_TYPE_ARG, /* It requires a command-line arg */ input_string_init, /* Init function */ - im_free /* Destroy function */ + im_free /* Destroy function */ }; /* Output string type. @@ -642,7 +642,7 @@ im_type_desc im__output_string = { 0, /* Memory to allocate */ IM_TYPE_OUTPUT, /* Its an output argument */ NULL, /* Init function */ - im_free /* Destroy function */ + im_free /* Destroy function */ }; /* Output double type. @@ -877,3 +877,4 @@ im_type_desc im__output_gvalue = { (im_init_obj_fn) output_gvalue_init, /* Init function */ (im_dest_obj_fn) gvalue_free /* Destroy function */ }; + diff --git a/libsrc/iofuncs/im_desc_hd.c b/libsrc/iofuncs/im_desc_hd.c deleted file mode 100644 index 34499fa4..00000000 --- a/libsrc/iofuncs/im_desc_hd.c +++ /dev/null @@ -1,209 +0,0 @@ -/* @(#) im_desc_hd: Copies vips file header to an IMAGE descriptor. - * @(#) - * @(#) int - * @(#) im__read_header_bytes( IMAGE *im, unsigned char *from ) - * @(#) - * @(#) int - * @(#) im__write_header_bytes( IMAGE *im, unsigned char *to ) - * @(#) - * @(#) Returns 0 on success and -1 on error - * - * Copyright: Nicos Dessipris - * Written on: 13/02/1990 - * Modified on : 22/2/92 v6.3 Kirk Martinez - * 17/11/94 JC - * - read compression fields too - * 28/10/98 JC - * - byteswap stuff added - * 21/8/02 JC - * - oops, was truncating float - * 22/8/05 - * - slightly less stupid - * 30/12/06 - * - use gunit32/16 for 2 and 4 byte quantities - * 12/1/07 - * - override bbits in the file ... it's now deprecated - * 7/3/08 - * - write MAGIC correctly on sparc/powerpc machines - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Read short/int/float LSB and MSB first. - */ -void -im__read_4byte( int msb_first, unsigned char *to, unsigned char **from ) -{ - unsigned char *p = *from; - int out; - - if( msb_first ) - out = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; - else - out = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; - - *from += 4; - *((guint32 *) to) = out; -} - -void -im__read_2byte( int msb_first, unsigned char *to, unsigned char **from ) -{ - int out; - unsigned char *p = *from; - - if( msb_first ) - out = p[0] << 8 | p[1]; - else - out = p[1] << 8 | p[0]; - - *from += 2; - *((guint16 *) to) = out; -} - -/* We always write in native byte order. - */ -void -im__write_4byte( unsigned char **to, unsigned char *from ) -{ - *((guint32 *) *to) = *((guint32 *) from); - *to += 4; -} - -void -im__write_2byte( unsigned char **to, unsigned char *from ) -{ - *((guint16 *) *to) = *((guint16 *) from); - *to += 2; -} - -/* offset, read, write functions. - */ -typedef struct _FieldIO { - glong offset; - void (*read)( int msb_first, unsigned char *to, unsigned char **from ); - void (*write)( unsigned char **to, unsigned char *from ); -} FieldIO; - -static FieldIO fields[] = { - { G_STRUCT_OFFSET( IMAGE, Xsize ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Ysize ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Bands ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Bbits ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, BandFmt ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Coding ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Type ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Xres ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Yres ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Length ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Compression ), - im__read_2byte, im__write_2byte }, - { G_STRUCT_OFFSET( IMAGE, Level ), - im__read_2byte, im__write_2byte }, - { G_STRUCT_OFFSET( IMAGE, Xoffset ), - im__read_4byte, im__write_4byte }, - { G_STRUCT_OFFSET( IMAGE, Yoffset ), - im__read_4byte, im__write_4byte } -}; - -int -im__read_header_bytes( IMAGE *im, unsigned char *from ) -{ - int msb_first; - int i; - - im__read_4byte( 1, (unsigned char *) &im->magic, &from ); - if( im->magic != IM_MAGIC_INTEL && im->magic != IM_MAGIC_SPARC ) { - im_error( "im_open", _( "\"%s\" is not a VIPS image" ), - im->filename ); - return( -1 ); - } - msb_first = im->magic == IM_MAGIC_SPARC; - - for( i = 0; i < IM_NUMBER( fields ); i++ ) - fields[i].read( msb_first, - &G_STRUCT_MEMBER( unsigned char, im, fields[i].offset ), - &from ); - - /* Set this ourselves ... bbits is deprecated in the file format. - */ - im->Bbits = im_bits_of_fmt( im->BandFmt ); - - return( 0 ); -} - -int -im__write_header_bytes( IMAGE *im, unsigned char *to ) -{ - guint32 magic; - int i; - unsigned char *q; - - /* Always write the magic number MSB first. - */ - magic = im_amiMSBfirst() ? IM_MAGIC_SPARC : IM_MAGIC_INTEL; - to[0] = magic >> 24; - to[1] = magic >> 16; - to[2] = magic >> 8; - to[3] = magic; - q = to + 4; - - for( i = 0; i < IM_NUMBER( fields ); i++ ) - fields[i].write( &q, - &G_STRUCT_MEMBER( unsigned char, im, - fields[i].offset ) ); - - /* Pad spares with zeros. - */ - while( q - to < im->sizeof_header ) - *q++ = 0; - - return( 0 ); -} diff --git a/libsrc/iofuncs/im_init_world.c b/libsrc/iofuncs/im_init_world.c index 3b2186e8..06be52bd 100644 --- a/libsrc/iofuncs/im_init_world.c +++ b/libsrc/iofuncs/im_init_world.c @@ -135,6 +135,10 @@ im_init_world( const char *argv0 ) */ im__meta_init_types(); + /* Add the base format load/save operations. + */ + im__format_init(); + /* Load up any plugins in the vips libdir. We don't error on failure, * it's too annoying to have VIPS refuse to start because of a broken * plugin. diff --git a/libsrc/iofuncs/im_open.c b/libsrc/iofuncs/im_open.c index 946c0032..4dc6a4cf 100644 --- a/libsrc/iofuncs/im_open.c +++ b/libsrc/iofuncs/im_open.c @@ -92,6 +92,8 @@ Modified: * - add simple cmd-line progress feedback * 9/8/08 * - lock global image list (thanks lee) + * 25/5/08 + * - break file format stuff out to the new pluggable image format system */ /* @@ -142,33 +144,6 @@ Modified: #include #endif /*WITH_DMALLOC*/ -/* Suffix sets. - */ -static const char *im_suffix_vips[] = { - "v", "", - NULL -}; -static const char *im_suffix_tiff[] = { - "tif", "tiff", - NULL -}; -static const char *im_suffix_jpeg[] = { - "jpeg", "jpg", "jfif", "jpe", - NULL -}; -static const char *im_suffix_ppm[] = { - "ppm", "pbm", "pgm", - NULL -}; -static const char *im_suffix_png[] = { - "png", - NULL -}; -static const char *im_suffix_csv[] = { - "csv", - NULL -}; - /* Progress feedback. Only really useful for testing, tbh. */ int im__progress = 0; @@ -179,55 +154,6 @@ im_progress_set( int progress ) im__progress = progress; } -/* Open a VIPS image and byte-swap the image data if necessary. - */ -static IMAGE * -read_vips( const char *filename ) -{ - IMAGE *im, *im2; - - if( !(im = im_init( filename )) ) - return( NULL ); - if( im_openin( im ) ) { - im_close( im ); - return( NULL ); - } - - /* Already in native format? - */ - if( im_isMSBfirst( im ) == im_amiMSBfirst() ) - return( im ); - - /* Not native ... but maybe does not need swapping? - */ - if( im->Coding == IM_CODING_LABQ ) - return( im ); - if( im->Coding != IM_CODING_NONE ) { - im_close( im ); - im_error( "im_open", _( "unknown coding type" ) ); - return( NULL ); - } - if( im->BandFmt == IM_BANDFMT_CHAR || im->BandFmt == IM_BANDFMT_UCHAR ) - return( im ); - - /* Needs swapping :( make a little pipeline up to do this for us. - */ - if( !(im2 = im_open( filename, "p" )) ) - return( NULL ); - if( im_add_close_callback( im2, - (im_callback_fn) im_close, im, NULL ) ) { - im_close( im ); - im_close( im2 ); - return( NULL ); - } - if( im_copy_swap( im, im2 ) ) { - im_close( im2 ); - return( NULL ); - } - - return( im2 ); -} - /* Delayed save: if we write to TIFF or to JPEG format, actually do the write * to a "p" and on preclose do im_vips2tiff() or whatever. Track save * parameters here. @@ -419,6 +345,9 @@ IMAGE * im_open( const char *filename, const char *mode ) { IMAGE *im; + im_format *format; + char name[FILENAME_MAX]; + char mode2[FILENAME_MAX]; /* Pass in a nonsense name for argv0 ... this init world is only here * for old programs which are missing an im_init_world() call. We must @@ -432,173 +361,43 @@ im_open( const char *filename, const char *mode ) return( NULL ); } + /* + + FIXME ... we have to split the filename here because + im_isvips() needs a filename without a mode extension + + can we fold the vips open code into the format system somehow? + we need to consider large file and pipeline support carefully + + */ + im_filename_split( filename, name, mode2 ); + switch( mode[0] ) { case 'r': -{ - char name[FILENAME_MAX]; - char options[FILENAME_MAX]; - - /* Break any options off the name ... eg. "fred.tif:jpeg,tile" - * etc. - */ - im_filename_split( filename, name, options ); - - /* Check for other formats. - - FIXME ... should have a table to avoid all this - repetition - - */ - if( !im_existsf( "%s", name ) ) { - im_error( "im_open", - _( "\"%s\" is not readable" ), name ); + if( im_isvips( name ) ) { + if( !(im = im_open_vips( filename )) ) + return( NULL ); + } + else if( (format = im_format_for_file( filename )) ) { + if( !(im = open_sub( + format->header, format->load, filename )) ) + return( NULL ); + } + else return( NULL ); - } - else if( im_istiff( name ) ) { - /* If TIFF open fails, try going through libmagick. - */ - if( !(im = open_sub( - im_tiff2vips_header, im_tiff2vips, - filename )) && - !(im = open_sub( - im_magick2vips_header, im_magick2vips, - filename )) ) - return( NULL ); - } - else if( im_isjpeg( name ) ) { - if( !(im = open_sub( - im_jpeg2vips_header, im_jpeg2vips, filename )) ) - return( NULL ); - } - else if( im_isexr( name ) ) { - if( !(im = open_sub( - im_exr2vips_header, im_exr2vips, filename )) ) - return( NULL ); - } - else if( im_isppm( name ) ) { - if( !(im = open_sub( - im_ppm2vips_header, im_ppm2vips, filename )) ) - return( NULL ); - } - else if( im_ispng( name ) ) { - if( !(im = open_sub( - im_png2vips_header, im_png2vips, filename )) ) - return( NULL ); - } - else if( im_filename_suffix_match( name, im_suffix_csv ) ) { - if( !(im = open_sub( - im_csv2vips_header, im_csv2vips, filename )) ) - return( NULL ); - } - else if( im_isvips( name ) ) { - if( mode[1] == 'w' ) { - /* Has to be native format for >8 bits. - */ - if( !(im = im_init( filename )) ) - return( NULL ); - if( im_openinrw( im ) ) { - im_close( im ); - return( NULL ); - } - if( im->Bbits != IM_BBITS_BYTE && - im_isMSBfirst( im ) != - im_amiMSBfirst() ) { - im_close( im ); - im_error( "im_open", _( "open for read-" - "write for native format " - "images only" ) ); - return( NULL ); - } - } - else - im = read_vips( filename ); - } - else if( im_isanalyze( name ) ) { - if( !(im = open_sub( - im_analyze2vips_header, im_analyze2vips, - filename )) ) - return( NULL ); - } - else if( im_ismagick( name ) ) { - /* Have this last as it can be very slow to detect - * failure. - */ - if( !(im = open_sub( - im_magick2vips_header, im_magick2vips, - filename )) ) - return( NULL ); - } - else { - im_error( "im_open", _( "\"%s\" is not " - "a supported format" ), filename ); - return( NULL ); - } -} - break; case 'w': - /* Look at the suffix for format write. - */ - if( im_filename_suffix_match( filename, im_suffix_vips ) ) + if( (format = im_format_for_name( filename )) ) { + if( !(im = im_open( "im_open:lazy_write:1", "p" )) ) + return( NULL ); + if( attach_sb( im, format->save, filename ) ) { + im_close( im ); + return( NULL ); + } + } + else im = im_openout( filename ); - else if( im_filename_suffix_match( filename, - im_suffix_tiff ) ) { - /* TIFF write. Save to a partial, and on preclose - * im_vips2tiff from that. - */ - if( !(im = im_open( "im_open:vips2tiff:1", "p" )) ) - return( NULL ); - if( attach_sb( im, im_vips2tiff, filename ) ) { - im_close( im ); - return( NULL ); - } - } - else if( im_filename_suffix_match( filename, - im_suffix_jpeg ) ) { - /* JPEG write. - */ - if( !(im = im_open( "im_open:vips2jpeg:1", "p" )) ) - return( NULL ); - if( attach_sb( im, im_vips2jpeg, filename ) ) { - im_close( im ); - return( NULL ); - } - } - else if( im_filename_suffix_match( filename, im_suffix_ppm ) ) { - /* ppm write. - */ - if( !(im = im_open( "im_open:vips2ppm:1", "p" )) ) - return( NULL ); - if( attach_sb( im, im_vips2ppm, filename ) ) { - im_close( im ); - return( NULL ); - } - } - else if( im_filename_suffix_match( filename, im_suffix_png ) ) { - /* png write. - */ - if( !(im = im_open( "im_open:vips2png:1", "p" )) ) - return( NULL ); - if( attach_sb( im, im_vips2png, filename ) ) { - im_close( im ); - return( NULL ); - } - } - else if( im_filename_suffix_match( filename, im_suffix_csv ) ) { - /* csv write. - */ - if( !(im = im_open( "im_open:vips2csv:1", "p" )) ) - return( NULL ); - if( attach_sb( im, im_vips2csv, filename ) ) { - im_close( im ); - return( NULL ); - } - } - else { - im_error( "im_open", _( "unknown suffix for save" ) ); - return( NULL ); - } break; case 't': @@ -610,8 +409,6 @@ im_open( const char *filename, const char *mode ) break; default: - /* Getting here means bad mode - */ im_error( "im_open", _( "bad mode \"%s\"" ), mode ); return( NULL ); } diff --git a/libsrc/iofuncs/im_readhist.c b/libsrc/iofuncs/im_open_vips.c similarity index 60% rename from libsrc/iofuncs/im_readhist.c rename to libsrc/iofuncs/im_open_vips.c index 4e29c985..6faa2045 100644 --- a/libsrc/iofuncs/im_readhist.c +++ b/libsrc/iofuncs/im_open_vips.c @@ -1,39 +1,8 @@ -/* @(#) Reads one line of description and the history of the filename - * @(#) This is done by replacing the ending .v of the filename with .desc - * @(#) and trying to read the new file. If the file ending in .desc - * @(#) does exist it is read and put into the Hist pointer of the - * @(#) image descriptor - * @(#) If the .desc file does not exist or if the input file is not - * @(#) ending with .v the Hist pointer in initialised to "filename\n" - * @(#) and history is kept from the current processing stage. - * @(#) - * @(#) int im_readhist(image) - * @(#) IMAGE *image; - * @(#) - * @(#) Returns either 0 (success) or -1 (fail) - * Copyright: Nicos Dessipris - * Written on: 15/01/1990 - * Modified on : - * 28/10/92 JC - * - no more wild freeing! - * - behaves itself, thank you - * 13/1/94 JC - * - array-bounds write found and fixed - * 26/10/98 JC - * - binary open for stupid systems - * 24/9/01 JC - * - slight clean up - * 6/8/02 JC - * - another cleanup - * 11/7/05 - * - now read XML from after the image data rather than a separate - * annoying file - * - added im__writehist() to write XML to the image - * 5/10/05 - * - added wrappers for seek/truncate with native win32 calls for long - * file support - * 3/1/07 - * - set history_list instead +/* Read and write a VIPS file into an IMAGE * + * + * 22/5/08 + * - from im_open.c, im_openin.c, im_desc_hd.c, im_readhist.c, + * im_openout.c */ /* @@ -71,6 +40,11 @@ #endif /*HAVE_CONFIG_H*/ #include +#include +#include +#include +#include + #include #include #include @@ -96,73 +70,229 @@ #include #include +#include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ +/* Try to make an O_BINARY ... sometimes need the leading '_'. + */ +#ifdef BINARY_OPEN +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#endif /*_O_BINARY*/ +#endif /*!O_BINARY*/ +#endif /*BINARY_OPEN*/ + /* Our XML namespace. */ #define NAMESPACE "http://www.vips.ecs.soton.ac.uk/vips" -/* Need our own seek(), since lseek() on win32 can't do long files. +/* mmap() whole vs. window threshold ... an int, so we can tune easily from a + * debugger. */ -static int -im__seek( int fd, gint64 pos ) -{ -#ifdef OS_WIN32 -{ - HANDLE hFile = (HANDLE) _get_osfhandle( fd ); - LARGE_INTEGER p; +#ifdef DEBUG +int im__mmap_limit = 1; +#else +int im__mmap_limit = IM__MMAP_LIMIT; +#endif /*DEBUG*/ - p.QuadPart = pos; - if( !SetFilePointerEx( hFile, p, NULL, FILE_BEGIN ) ) { - im_error_system( GetLastError(), "im__seek", - _( "unable to seek" ) ); - return( -1 ); +/* Sort of open for read for image files. Shared with im_binfile(). + */ +int +im__open_image_file( const char *filename ) +{ + int fd; + + /* Try to open read-write, so that calls to im_makerw() will work. + * When we later mmap this file, we set read-only, so there + * is little danger of scrubbing over files we own. + */ +#ifdef BINARY_OPEN + if( (fd = open( filename, O_RDWR | O_BINARY )) == -1 ) { +#else /*BINARY_OPEN*/ + if( (fd = open( filename, O_RDWR )) == -1 ) { +#endif /*BINARY_OPEN*/ + /* Open read-write failed. Fall back to open read-only. + */ +#ifdef BINARY_OPEN + if( (fd = open( filename, O_RDONLY | O_BINARY )) == -1 ) { +#else /*BINARY_OPEN*/ + if( (fd = open( filename, O_RDONLY )) == -1 ) { +#endif /*BINARY_OPEN*/ + im_error( "im__open_image_file", + _( "unable to open \"%s\", %s" ), + filename, strerror( errno ) ); + return( -1 ); + } } + + return( fd ); } -#else /*!OS_WIN32*/ - if( lseek( fd, pos, SEEK_SET ) == (off_t) -1 ) { - im_error( "im__seek", _( "unable to seek" ) ); + +/* Predict the size of the header plus pixel data. Don't use off_t, + * it's sometimes only 32 bits (eg. on many windows build environments) and we + * want to always be 64 bit. + */ +static gint64 +im__image_pixel_length( IMAGE *im ) +{ + gint64 psize; + + switch( im->Coding ) { + case IM_CODING_LABQ: + case IM_CODING_NONE: + psize = (gint64) IM_IMAGE_SIZEOF_LINE( im ) * im->Ysize; + break; + + default: + psize = im->Length; + break; + } + + return( psize + im->sizeof_header ); +} + +/* Read short/int/float LSB and MSB first. + */ +void +im__read_4byte( int msb_first, unsigned char *to, unsigned char **from ) +{ + unsigned char *p = *from; + int out; + + if( msb_first ) + out = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + else + out = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; + + *from += 4; + *((guint32 *) to) = out; +} + +void +im__read_2byte( int msb_first, unsigned char *to, unsigned char **from ) +{ + int out; + unsigned char *p = *from; + + if( msb_first ) + out = p[0] << 8 | p[1]; + else + out = p[1] << 8 | p[0]; + + *from += 2; + *((guint16 *) to) = out; +} + +/* We always write in native byte order. + */ +void +im__write_4byte( unsigned char **to, unsigned char *from ) +{ + *((guint32 *) *to) = *((guint32 *) from); + *to += 4; +} + +void +im__write_2byte( unsigned char **to, unsigned char *from ) +{ + *((guint16 *) *to) = *((guint16 *) from); + *to += 2; +} + +/* offset, read, write functions. + */ +typedef struct _FieldIO { + glong offset; + void (*read)( int msb_first, unsigned char *to, unsigned char **from ); + void (*write)( unsigned char **to, unsigned char *from ); +} FieldIO; + +static FieldIO fields[] = { + { G_STRUCT_OFFSET( IMAGE, Xsize ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Ysize ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Bands ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Bbits ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, BandFmt ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Coding ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Type ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Xres ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Yres ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Length ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Compression ), + im__read_2byte, im__write_2byte }, + { G_STRUCT_OFFSET( IMAGE, Level ), + im__read_2byte, im__write_2byte }, + { G_STRUCT_OFFSET( IMAGE, Xoffset ), + im__read_4byte, im__write_4byte }, + { G_STRUCT_OFFSET( IMAGE, Yoffset ), + im__read_4byte, im__write_4byte } +}; + +int +im__read_header_bytes( IMAGE *im, unsigned char *from ) +{ + int msb_first; + int i; + + im__read_4byte( 1, (unsigned char *) &im->magic, &from ); + if( im->magic != IM_MAGIC_INTEL && im->magic != IM_MAGIC_SPARC ) { + im_error( "im_open", _( "\"%s\" is not a VIPS image" ), + im->filename ); return( -1 ); } -#endif /*OS_WIN32*/ + msb_first = im->magic == IM_MAGIC_SPARC; + + for( i = 0; i < IM_NUMBER( fields ); i++ ) + fields[i].read( msb_first, + &G_STRUCT_MEMBER( unsigned char, im, fields[i].offset ), + &from ); + + /* Set this ourselves ... bbits is deprecated in the file format. + */ + im->Bbits = im_bits_of_fmt( im->BandFmt ); return( 0 ); } -/* Need our own ftruncate(), since ftruncate() on win32 can't do long files. - - DANGER ... this moves the file pointer to the end of file on win32, - but not on *nix; don't make any assumptions about the file pointer - position after calling this - - */ -static int -im__ftruncate( int fd, gint64 pos ) +int +im__write_header_bytes( IMAGE *im, unsigned char *to ) { -#ifdef OS_WIN32 -{ - HANDLE hFile = (HANDLE) _get_osfhandle( fd ); - LARGE_INTEGER p; + guint32 magic; + int i; + unsigned char *q; - p.QuadPart = pos; - if( im__seek( fd, pos ) ) - return( -1 ); - if( !SetEndOfFile( hFile ) ) { - im_error_system( GetLastError(), "im__ftruncate", - _( "unable to truncate" ) ); - return( -1 ); - } -} -#else /*!OS_WIN32*/ - if( ftruncate( fd, pos ) ) { - im_error_system( errno, "im__ftruncate", - _( "unable to truncate" ) ); - return( -1 ); - } -#endif /*OS_WIN32*/ + /* Always write the magic number MSB first. + */ + magic = im_amiMSBfirst() ? IM_MAGIC_SPARC : IM_MAGIC_INTEL; + to[0] = magic >> 24; + to[1] = magic >> 16; + to[2] = magic >> 8; + to[3] = magic; + q = to + 4; + + for( i = 0; i < IM_NUMBER( fields ); i++ ) + fields[i].write( &q, + &G_STRUCT_MEMBER( unsigned char, im, + fields[i].offset ) ); + + /* Pad spares with zeros. + */ + while( q - to < im->sizeof_header ) + *q++ = 0; return( 0 ); } @@ -454,7 +584,7 @@ rebuild_header( IMAGE *im ) /* Called at the end of im__read_header ... get any XML after the pixel data * and read it in. */ -int +static int im__readhist( IMAGE *im ) { /* Junk any old xml meta. @@ -751,3 +881,213 @@ im__writehist( IMAGE *im ) return( 0 ); } + +/* Open the filename, read the header, some sanity checking. + */ +static int +im__read_header( IMAGE *image ) +{ + /* We don't use im->sizeof_header here, but we know we're reading a + * VIPS image anyway. + */ + unsigned char header[IM_SIZEOF_HEADER]; + + gint64 length; + gint64 psize; + + image->dtype = IM_OPENIN; + if( (image->fd = im__open_image_file( image->filename )) == -1 ) + return( -1 ); + if( read( image->fd, header, IM_SIZEOF_HEADER ) != IM_SIZEOF_HEADER || + im__read_header_bytes( image, header ) ) { + im_error( "im_openin", + _( "unable to read header for \"%s\", %s" ), + image->filename, strerror( errno ) ); + return( -1 ); + } + + /* Predict and check the file size. + */ + psize = im__image_pixel_length( image ); + if( (length = im_file_length( image->fd )) == -1 ) + return( -1 ); + if( psize > length ) { + im_error( "im_openin", _( "unable to open \"%s\", %s" ), + image->filename, _( "file has been truncated" ) ); + return( -1 ); + } + + /* Set demand style. Allow the most permissive sort. + */ + image->dhint = IM_THINSTRIP; + + /* Set the history part of im descriptor. Don't return an error if this + * fails (due to eg. corrupted XML) because it's probably mostly + * harmless. + */ + if( im__readhist( image ) ) { + im_warn( "im_openin", _( "error reading XML: %s" ), + im_error_buffer() ); + im_error_clear(); + } + + return( 0 ); +} + +/* Open, then mmap() small images, leave large images to have a rolling mmap() + * window for each region. This is old and deprecated API, use im_vips_open() + * in preference. + */ +int +im_openin( IMAGE *image ) +{ + gint64 size; + +#ifdef DEBUG + char *str; + + if( (str = g_getenv( "IM_MMAP_LIMIT" )) ) { + im__mmap_limit = atoi( str ); + printf( "im_openin: setting maplimit to %d from environment\n", + im__mmap_limit ); + } +#endif /*DEBUG*/ + + if( im__read_header( image ) ) + return( -1 ); + + size = (gint64) IM_IMAGE_SIZEOF_LINE( image ) * image->Ysize + + image->sizeof_header; + if( size < im__mmap_limit ) { + if( im_mapfile( image ) ) + return( -1 ); + image->data = image->baseaddr + image->sizeof_header; + image->dtype = IM_MMAPIN; + +#ifdef DEBUG + printf( "im_openin: completely mmap()ing \"%s\": it's small\n", + image->filename ); +#endif /*DEBUG*/ + } + else { +#ifdef DEBUG + printf( "im_openin: delaying mmap() of \"%s\": it's big!\n", + image->filename ); +#endif /*DEBUG*/ + } + + return( 0 ); +} + +/* Open, then mmap() read/write. This is old and deprecated API, uuse + * im_vips_open() in preference. + */ +int +im_openinrw( IMAGE *image ) +{ + if( im__read_header( image ) ) + return( -1 ); + if( im_mapfilerw( image ) ) + return( -1 ); + image->data = image->baseaddr + image->sizeof_header; + image->dtype = IM_MMAPINRW; + +#ifdef DEBUG + printf( "im_openin: completely mmap()ing \"%s\" read-write\n", + image->filename ); +#endif /*DEBUG*/ + + return( 0 ); +} + +/* Open a VIPS image for reading and byte-swap the image data if necessary. A + * ":w" at the end of the filename means we open read-write. + */ +IMAGE * +im_open_vips( const char *filename ) +{ + char name[FILENAME_MAX]; + char mode[FILENAME_MAX]; + IMAGE *im; + + im_filename_split( filename, name, mode ); + + if( !(im = im_init( name )) ) + return( NULL ); + if( mode[0] == 'w' ) { + if( im_openinrw( im ) ) { + im_close( im ); + return( NULL ); + } + if( im->Bbits != IM_BBITS_BYTE && + im_isMSBfirst( im ) != im_amiMSBfirst() ) { + im_close( im ); + im_error( "im_open_vips", _( "open for read-write for " + "native format images only" ) ); + return( NULL ); + } + } + else { + if( im_openin( im ) ) { + im_close( im ); + return( NULL ); + } + } + + /* Not in native format? + */ + if( im_isMSBfirst( im ) != im_amiMSBfirst() ) { + /* Does it need swapping? + */ + switch( im->Coding ) { + case IM_CODING_LABQ: + break; + + case IM_CODING_NONE: + if( im->BandFmt != IM_BANDFMT_CHAR && + im->BandFmt != IM_BANDFMT_UCHAR ) { + IMAGE *im2; + + /* Needs swapping :( make a little pipeline up + * to do this for us. + */ + if( !(im2 = im_open( filename, "p" )) ) { + im_close( im ); + return( NULL ); + } + if( im_add_close_callback( im2, + (im_callback_fn)im_close, im, NULL ) ) { + im_close( im ); + im_close( im2 ); + return( NULL ); + } + if( im_copy_swap( im, im2 ) ) { + im_close( im2 ); + return( NULL ); + } + im = im2; + } + break; + + default: + im_close( im ); + im_error( "im_open", _( "unknown coding type" ) ); + return( NULL ); + } + } + + return( im ); +} + +IMAGE * +im_openout( const char *filename ) +{ + IMAGE *image; + + if( !(image = im_init( filename )) ) + return( NULL ); + image->dtype = IM_OPENOUT; + + return( image ); +} + diff --git a/libsrc/iofuncs/im_openin.c b/libsrc/iofuncs/im_openin.c deleted file mode 100644 index 1a948015..00000000 --- a/libsrc/iofuncs/im_openin.c +++ /dev/null @@ -1,293 +0,0 @@ -/* @(#) Open a VIPS image file for reading. The IMAGE should be as made by - * @(#) im_init(), or after im__close. - * @(#) - * @(#) If the file is small, we mmap() it - * @(#) and make an image of type IM_MMAP. If the file is large, we don't - * @(#) mmap(); instead we just open a file descriptor and wait for any regions - * @(#) defined on the image to make small mmap() windows. Also read the - * @(#) history. - * @(#) - * @(#) int - * @(#) im_openin( IMAGE *image ) - * @(#) - * @(#) As above, but always mmap() the whole file, and do it read/write. - * @(#) - * @(#) int - * @(#) im_openinrw( IMAGE *image ) - * - * Copyright: Nicos Dessipris - * Written on: 13/02/1990 - * Modified on : 27/02/1991 - * 17/6/92 J.Cupitt - * - Now opens read-write if possible. This allows later calls to - * im_makerw. We mmap with PROT_READ, so there is no danger of - * scribbling over owned images. - * 16/4/93 J.Cupitt - * - adapted to use type field - * 10/5/93 J.Cupitt - * - split into im__mmapin() and im_mmapin() for im_openout() convenience - * - functions of im_mmapin.c and im_mmapinrw.c combined - * 7/9/93 JC - * - now sets dhint field - * 17/11/94 JC - * - checks length of compressed files too - * 19/8/98 JC - * - uses strerror() to print system error messages - * 28/10/98 JC - * - _INTEL and _SPARC auto byte-swap added - * 6/8/02 JC - * - redone for mmap() window stuff - * 13/3/06 JC - * - don't abort load if we can't get the XML - * 16/8/06 - * - more O_BINARY nonsense to help cygwin - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif /*HAVE_UNISTD_H*/ -#include -#ifdef HAVE_IO_H -#include -#endif - -/* Try to make an O_BINARY ... sometimes need the leading '_'. - */ -#ifdef BINARY_OPEN -#ifndef O_BINARY -#ifdef _O_BINARY -#define O_BINARY _O_BINARY -#endif /*_O_BINARY*/ -#endif /*!O_BINARY*/ -#endif /*BINARY_OPEN*/ - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* mmap() whole vs. window threshold ... an int, so we can tune easily from a - * debugger. - */ -#ifdef DEBUG -int im__mmap_limit = 1; -#else -int im__mmap_limit = IM__MMAP_LIMIT; -#endif /*DEBUG*/ - -/* Sort of open for read for image files. - */ -int -im__open_image_file( const char *filename ) -{ - int fd; - - /* Try to open read-write, so that calls to im_makerw() will work. - * When we later mmap this file, we set read-only, so there - * is little danger of scrubbing over files we own. - */ -#ifdef BINARY_OPEN - if( (fd = open( filename, O_RDWR | O_BINARY )) == -1 ) { -#else /*BINARY_OPEN*/ - if( (fd = open( filename, O_RDWR )) == -1 ) { -#endif /*BINARY_OPEN*/ - /* Open read-write failed. Fall back to open read-only. - */ -#ifdef BINARY_OPEN - if( (fd = open( filename, O_RDONLY | O_BINARY )) == -1 ) { -#else /*BINARY_OPEN*/ - if( (fd = open( filename, O_RDONLY )) == -1 ) { -#endif /*BINARY_OPEN*/ - im_error( "im__open_image_file", - _( "unable to open \"%s\", %s" ), - filename, strerror( errno ) ); - return( -1 ); - } - } - - return( fd ); -} - -/* Predict the size of the header plus pixel data. Don't use off_t, - * it's sometimes only 32 bits (eg. on many windows build environments) and we - * want to always be 64 bit. - */ -gint64 -im__image_pixel_length( IMAGE *im ) -{ - gint64 psize; - - switch( im->Coding ) { - case IM_CODING_LABQ: - case IM_CODING_NONE: - psize = (gint64) IM_IMAGE_SIZEOF_LINE( im ) * im->Ysize; - break; - - default: - psize = im->Length; - break; - } - - return( psize + im->sizeof_header ); -} - -/* Open the filename, read the header, some sanity checking. - */ -int -im__read_header( IMAGE *image ) -{ - /* We don't use im->sizeof_header here, but we know we're reading a - * VIPS image anyway. - */ - unsigned char header[IM_SIZEOF_HEADER]; - - gint64 length; - gint64 psize; - - image->dtype = IM_OPENIN; - if( (image->fd = im__open_image_file( image->filename )) == -1 ) - return( -1 ); - if( read( image->fd, header, IM_SIZEOF_HEADER ) != IM_SIZEOF_HEADER || - im__read_header_bytes( image, header ) ) { - im_error( "im_openin", - _( "unable to read header for \"%s\", %s" ), - image->filename, strerror( errno ) ); - return( -1 ); - } - - /* Predict and check the file size. - */ - psize = im__image_pixel_length( image ); - if( (length = im_file_length( image->fd )) == -1 ) - return( -1 ); - if( psize > length ) { - im_error( "im_openin", _( "unable to open \"%s\", %s" ), - image->filename, _( "file has been truncated" ) ); - return( -1 ); - } - - /* Set demand style. Allow the most permissive sort. - */ - image->dhint = IM_THINSTRIP; - - /* Set the history part of im descriptor. Don't return an error if this - * fails (due to eg. corrupted XML) because it's probably mostly - * harmless. - */ - if( im__readhist( image ) ) { - im_warn( "im_openin", _( "error reading XML: %s" ), - im_error_buffer() ); - im_error_clear(); - } - - return( 0 ); -} - -/* Open, then mmap() small images, leave large images to have a rolling mmap() - * window for each region. - */ -int -im_openin( IMAGE *image ) -{ - gint64 size; - -#ifdef DEBUG - char *str; - - if( (str = g_getenv( "IM_MMAP_LIMIT" )) ) { - im__mmap_limit = atoi( str ); - printf( "im_openin: setting maplimit to %d from environment\n", - im__mmap_limit ); - } -#endif /*DEBUG*/ - - if( im__read_header( image ) ) - return( -1 ); - - size = (gint64) IM_IMAGE_SIZEOF_LINE( image ) * image->Ysize + - image->sizeof_header; - if( size < im__mmap_limit ) { - if( im_mapfile( image ) ) - return( -1 ); - image->data = image->baseaddr + image->sizeof_header; - image->dtype = IM_MMAPIN; - -#ifdef DEBUG - printf( "im_openin: completely mmap()ing \"%s\": it's small\n", - image->filename ); -#endif /*DEBUG*/ - } - else { -#ifdef DEBUG - printf( "im_openin: delaying mmap() of \"%s\": it's big!\n", - image->filename ); -#endif /*DEBUG*/ - } - - return( 0 ); -} - -/* Open, then mmap() read/write. - */ -int -im_openinrw( IMAGE *image ) -{ - if( im__read_header( image ) ) - return( -1 ); - - if( im_mapfilerw( image ) ) - return( -1 ); - image->data = image->baseaddr + image->sizeof_header; - image->dtype = IM_MMAPINRW; - -#ifdef DEBUG - printf( "im_openin: completely mmap()ing \"%s\" read-write\n", - image->filename ); -#endif /*DEBUG*/ - - return( 0 ); -} diff --git a/libsrc/iofuncs/im_openout.c b/libsrc/iofuncs/im_openout.c deleted file mode 100644 index ba646e35..00000000 --- a/libsrc/iofuncs/im_openout.c +++ /dev/null @@ -1,75 +0,0 @@ -/* @(#) im_openout: associates an IMAGE with an image file for output - * @(#) IMAGE should be closed with im_close() - * @(#) Usage: - * @(#) IMAGE *im_openout(file_name) - * @(#) char *file_name; - * @(#) - * @(#) Returns *IMAGE or NULL on error. - * - * Copyright: Nicos Dessipris - * Written on: 13/02/1990 - * Modified on : 26/04/1990 by KM - * 16/4/93 JC - * - uses new init, type style - * - memory leak fixed - * 11/5/93 JC - * - newer im_init() style - * 23/10/98 JC - * - new BINARY_OPEN define - * 4/7/01 JC - * - delay open() until im_setupout() - */ - -/* - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -IMAGE * -im_openout( const char *file_name ) -{ - IMAGE *image; - - if( !(image = im_init( file_name )) ) - return( NULL ); - image->dtype = IM_OPENOUT; - - return( image ); -} diff --git a/libsrc/iofuncs/package.c b/libsrc/iofuncs/package.c index 9f19571b..8c5b1dbc 100644 --- a/libsrc/iofuncs/package.c +++ b/libsrc/iofuncs/package.c @@ -63,6 +63,7 @@ extern im_package im__boolean; extern im_package im__colour; extern im_package im__conversion; extern im_package im__convolution; +extern im_package im__format; extern im_package im__freq_filt; extern im_package im__histograms_lut; extern im_package im__inplace; @@ -73,6 +74,8 @@ extern im_package im__other; extern im_package im__relational; extern im_package im__video; +extern im_format_package im__format_format; + /* im_guess_prefix() args. */ static im_arg_desc guess_prefix_args[] = { @@ -444,6 +447,7 @@ static im_package *built_in[] = { &im__colour, &im__conversion, &im__convolution, + &im__format, &im__freq_filt, &im__histograms_lut, &im__inplace, @@ -456,12 +460,66 @@ static im_package *built_in[] = { &im__video }; +/* List of loaded formats. + */ +static GSList *format_list = NULL; + +static gint +format_compare( im_format *a, im_format *b ) +{ + return( b->priority - a->priority ); +} + +/* Sort the format list after a change. + */ +static void +format_sort( void ) +{ + format_list = g_slist_sort( format_list, + (GCompareFunc) format_compare ); +} + +/* Remove a package of formats. + */ +static void +format_remove( im_format_package *format ) +{ + int i; + + for( i = 0; i < format->nfuncs; i++ ) + format_list = g_slist_remove( format_list, format->table[i] ); + format_sort(); +} + +/* Add a package of formats. + */ +static void +format_add( im_format_package *format ) +{ + int i; + + for( i = 0; i < format->nfuncs; i++ ) + /* Append so we keep the ordering where possible. + */ + format_list = g_slist_append( format_list, format->table[i] ); + format_sort(); +} + +/* Called on startup: add the base vips formats. + */ +void +im__format_init( void ) +{ + format_add( &im__format_format ); +} + /* How we represent a loaded plugin. */ typedef struct _Plugin { GModule *module; /* As loaded by g_module_open() */ char *name; /* Name we loaded */ im_package *pack; /* Package table */ + im_format_package *format; /* Package format table */ } Plugin; /* List of loaded plugins. @@ -475,6 +533,8 @@ plugin_free( Plugin *plug ) { char *name = plug->name ? plug->name : ""; + if( plug->format ) + format_remove( plug->format ); if( plug->module ) { if( !g_module_close( plug->module ) ) { im_error( "plugin", @@ -514,6 +574,7 @@ im_load_plugin( const char *name ) plug->module = NULL; plug->name = NULL; plug->pack = NULL; + plug->format = NULL; plugin_list = g_slist_prepend( plugin_list, plug ); /* Attach name. @@ -548,22 +609,44 @@ im_load_plugin( const char *name ) return( NULL ); } + /* The format table is optional. + */ + if( !g_module_symbol( plug->module, + "format_table", (gpointer *) ((void *) &plug->format) ) ) + plug->format = NULL; + /* Sanity check. */ if( !plug->pack->name || plug->pack->nfuncs < 0 || plug->pack->nfuncs > 10000 ) { im_error( "plugin", - _( "corrupted package table in plugin \"%s\"" ), - name ); + _( "corrupted package table in plugin \"%s\"" ), name ); plugin_free( plug ); return( NULL ); } + if( plug->format ) { + if( !plug->format->name || plug->format->nfuncs < 0 || + plug->format->nfuncs > 10000 ) { + + im_error( "plugin", + _( "corrupted format table in plugin \"%s\"" ), + name ); + plugin_free( plug ); + + return( NULL ); + } + } #ifdef DEBUG printf( "added package \"%s\" ...\n", plug->pack->name ); #endif /*DEBUG*/ + /* Add any formats to our format list and sort again. + */ + if( plug->format ) + format_add( plug->format ); + return( plug->pack ); } @@ -736,6 +819,91 @@ im_package_of_function( const char *name ) return( pack ); } +/* Map a function over all formats. + */ +void * +im_map_formats( VSListMap2Fn fn, void *a, void *b ) +{ + return( im_slist_map2( format_list, fn, a, b ) ); +} + +/* Can this format open this file? + */ +static void * +format_for_file_sub( im_format *format, + const char *filename, const char *name ) +{ + if( format->is_a ) { + if( format->is_a( name ) ) + return( format ); + } + else if( im_filename_suffix_match( name, format->suffs ) ) + return( format ); + + return( NULL ); +} + +im_format * +im_format_for_file( const char *filename ) +{ + char name[FILENAME_MAX]; + char options[FILENAME_MAX]; + im_format *format; + + /* Break any options off the name ... eg. "fred.tif:jpeg,tile" + * etc. + */ + im_filename_split( filename, name, options ); + + if( !im_existsf( "%s", name ) ) { + im_error( "im_format_for_file", + _( "\"%s\" is not readable" ), name ); + return( NULL ); + } + + format = (im_format *) im_map_formats( + (VSListMap2Fn) format_for_file_sub, + (void *) filename, (void *) name ); + + if( !format ) { + im_error( "im_format_for_file", + _( "\"%s\" is not in a supported format" ), name ); + return( NULL ); + } + + return( format ); +} + +/* Can we write this filename with this format? Ignore formats without a save + * method. + */ +static void * +format_for_name_sub( im_format *format, + const char *filename, const char *name ) +{ + if( format->save && + im_filename_suffix_match( name, format->suffs ) ) + return( format ); + + return( NULL ); +} + +im_format * +im_format_for_name( const char *filename ) +{ + char name[FILENAME_MAX]; + char options[FILENAME_MAX]; + + /* Break any options off the name ... eg. "fred.tif:jpeg,tile" + * etc. + */ + im_filename_split( filename, name, options ); + + return( (im_format *) im_map_formats( + (VSListMap2Fn) format_for_name_sub, + (void *) filename, (void *) name ) ); +} + /* Free any store we allocated for the argument list. */ int diff --git a/libsrc/iofuncs/predicate.c b/libsrc/iofuncs/predicate.c index 45b273fa..287b9631 100644 --- a/libsrc/iofuncs/predicate.c +++ b/libsrc/iofuncs/predicate.c @@ -24,6 +24,8 @@ * - added exr * 3/8/07 * - cleanups + * 22/5/08 + * - image format stuff broken out */ /* @@ -74,14 +76,6 @@ #include -#ifdef HAVE_TIFF -#include -#endif /*HAVE_TIFF*/ - -#ifdef HAVE_PNG -#include -#endif /*HAVE_PNG*/ - #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -241,195 +235,6 @@ im_iscomplex( IMAGE *im ) } } -/* Read a few bytes from the start of a file. For sniffing file types. - */ -static int -get_bytes( const char *filename, unsigned char buf[], int len ) -{ - int fd; - - /* File may not even exist (for tmp images for example!) - * so no hasty messages. And the file might be truncated, so no error - * on read either. - */ -#ifdef BINARY_OPEN - if( (fd = open( filename, O_RDONLY | O_BINARY )) == -1 ) -#else /*BINARY_OPEN*/ - if( (fd = open( filename, O_RDONLY )) == -1 ) -#endif /*BINARY_OPEN*/ - return( 0 ); - if( read( fd, buf, len ) != len ) { - close( fd ); - return( 0 ); - } - close( fd ); - - return( 1 ); -} - -int -im_istiff( const char *filename ) -{ - unsigned char buf[2]; - - if( get_bytes( filename, buf, 2 ) ) - if( (buf[0] == 'M' && buf[1] == 'M') || - (buf[0] == 'I' && buf[1] == 'I') ) - return( 1 ); - - return( 0 ); -} - -#ifdef HAVE_PNG -int -im_ispng( const char *filename ) -{ - unsigned char buf[8]; - - return( get_bytes( filename, buf, 8 ) && - !png_sig_cmp( buf, 0, 8 ) ); -} -#else /*HAVE_PNG*/ -int -im_ispng( const char *filename ) -{ - return( 0 ); -} -#endif /*HAVE_PNG*/ - -#ifdef HAVE_MAGICK -int -im_ismagick( const char *filename ) -{ - IMAGE *im; - int result; - - if( !(im = im_open( "dummy", "p" )) ) - return( -1 ); - result = im_magick2vips_header( filename, im ); - im_clear_error_string(); - im_close( im ); - - return( result == 0 ); -} -#else /*HAVE_MAGICK*/ -int -im_ismagick( const char *filename ) -{ - return( 0 ); -} -#endif /*HAVE_MAGICK*/ - -int -im_isppm( const char *filename ) -{ - unsigned char buf[2]; - - if( get_bytes( filename, buf, 2 ) ) - if( buf[0] == 'P' && (buf[1] >= '1' || buf[1] <= '6') ) - return( 1 ); - - return( 0 ); -} - -#ifdef HAVE_TIFF - -/* Handle TIFF errors here. - */ -static void -vhandle( char *module, char *fmt, ... ) -{ - va_list ap; - - im_errormsg( "TIFF error in \"%s\": ", module ); - - va_start( ap, fmt ); - im_verrormsg( fmt, ap ); - va_end( ap ); -} - -int -im_istifftiled( const char *filename ) -{ - TIFF *tif; - int tiled; - - /* Override the default TIFF error handler. - */ - TIFFSetErrorHandler( (TIFFErrorHandler) vhandle ); - -#ifdef BINARY_OPEN - if( !(tif = TIFFOpen( filename, "rb" )) ) { -#else /*BINARY_OPEN*/ - if( !(tif = TIFFOpen( filename, "r" )) ) { -#endif /*BINARY_OPEN*/ - /* Not a TIFF file ... return False. - */ - im_clear_error_string(); - return( 0 ); - } - tiled = TIFFIsTiled( tif ); - TIFFClose( tif ); - - return( tiled ); -} - -#else /*HAVE_TIFF*/ - -int -im_istifftiled( const char *filename ) -{ - return( 0 ); -} - -#endif /*HAVE_TIFF*/ - -int -im_isjpeg( const char *filename ) -{ - unsigned char buf[2]; - - if( get_bytes( filename, buf, 2 ) ) - if( (int) buf[0] == 0xff && (int) buf[1] == 0xd8 ) - return( 1 ); - - return( 0 ); -} - -int -im_isvips( const char *filename ) -{ - unsigned char buf[4]; - - if( get_bytes( filename, buf, 4 ) ) { - if( buf[0] == 0x08 && buf[1] == 0xf2 && - buf[2] == 0xa6 && buf[3] == 0xb6 ) - /* SPARC-order VIPS image. - */ - return( 1 ); - else if( buf[3] == 0x08 && buf[2] == 0xf2 && - buf[1] == 0xa6 && buf[0] == 0xb6 ) - /* INTEL-order VIPS image. - */ - return( 1 ); - } - - return( 0 ); -} - -int -im_isexr( const char *filename ) -{ - unsigned char buf[4]; - - if( get_bytes( filename, buf, 4 ) ) - if( buf[0] == 0x76 && buf[1] == 0x2f && - buf[2] == 0x31 && buf[3] == 0x01 ) - return( 1 ); - - return( 0 ); -} - /* Test for file exists. */ int @@ -514,7 +319,7 @@ im_ispoweroftwo( int p ) /* Count set bits. Could use a LUT, I guess. */ for( i = 0, n = 0; p; i++, p >>= 1 ) - if( (p & 1) == 1 ) + if( p & 1 ) n++; /* Should be just one set bit. diff --git a/libsrc/iofuncs/util.c b/libsrc/iofuncs/util.c index eb0872eb..df5ca395 100644 --- a/libsrc/iofuncs/util.c +++ b/libsrc/iofuncs/util.c @@ -48,6 +48,10 @@ #include #endif /*HAVE_UNISTD_H*/ +#ifdef OS_WIN32 +#include +#endif /*OS_WIN32*/ + #include #include @@ -477,7 +481,7 @@ im_skip_dir( const char *path ) } /* Extract suffix from filename, ignoring any mode string. Suffix should be - * FILENAME_MAX chars. + * FILENAME_MAX chars. Include the "." character, if any. */ void im_filename_suffix( const char *path, char *suffix ) @@ -488,7 +492,7 @@ im_filename_suffix( const char *path, char *suffix ) im_filename_split( path, name, mode ); if( (p = strrchr( name, '.' )) ) - strcpy( suffix, p + 1 ); + strcpy( suffix, p ); else strcpy( suffix, "" ); } @@ -913,3 +917,99 @@ im__gslist_gvalue_get( const GSList *list ) return( all ); } + +/* Need our own seek(), since lseek() on win32 can't do long files. + */ +int +im__seek( int fd, gint64 pos ) +{ +#ifdef OS_WIN32 +{ + HANDLE hFile = (HANDLE) _get_osfhandle( fd ); + LARGE_INTEGER p; + + p.QuadPart = pos; + if( !SetFilePointerEx( hFile, p, NULL, FILE_BEGIN ) ) { + im_error_system( GetLastError(), "im__seek", + _( "unable to seek" ) ); + return( -1 ); + } +} +#else /*!OS_WIN32*/ + if( lseek( fd, pos, SEEK_SET ) == (off_t) -1 ) { + im_error( "im__seek", _( "unable to seek" ) ); + return( -1 ); + } +#endif /*OS_WIN32*/ + + return( 0 ); +} + +/* Need our own ftruncate(), since ftruncate() on win32 can't do long files. + + DANGER ... this moves the file pointer to the end of file on win32, + but not on *nix; don't make any assumptions about the file pointer + position after calling this + + */ +int +im__ftruncate( int fd, gint64 pos ) +{ +#ifdef OS_WIN32 +{ + HANDLE hFile = (HANDLE) _get_osfhandle( fd ); + LARGE_INTEGER p; + + p.QuadPart = pos; + if( im__seek( fd, pos ) ) + return( -1 ); + if( !SetEndOfFile( hFile ) ) { + im_error_system( GetLastError(), "im__ftruncate", + _( "unable to truncate" ) ); + return( -1 ); + } +} +#else /*!OS_WIN32*/ + if( ftruncate( fd, pos ) ) { + im_error_system( errno, "im__ftruncate", + _( "unable to truncate" ) ); + return( -1 ); + } +#endif /*OS_WIN32*/ + + return( 0 ); +} + + +/* Like fwrite(), but returns non-zero on error and sets error message. + */ +int +im__file_write( void *data, size_t size, size_t nmemb, FILE *stream ) +{ + int n; + if( !data ) return( 0 ); + if( (n = fwrite( data, size, nmemb, stream )) != nmemb ) { + im_error( "im__file_write", + _( "writing error (%d out of %d blocks written) ... disc full?" ), + n, nmemb ); + return( -1 ); + } + return( 0 ); +} + + +/* Check whether arch corresponds to native byte order. + */ +gboolean +im_isnative( im_arch_type arch ) +{ + switch ( arch ) { + case IM_ARCH_NATIVE: return( TRUE ); + case IM_ARCH_BYTE_SWAPPED: return( FALSE ); + case IM_ARCH_LSB_FIRST: return( !im_amiMSBfirst() ); + case IM_ARCH_MSB_FIRST: return( im_amiMSBfirst() ); + } + abort(); +} + + diff --git a/vips-7.15.spec.in b/vips-7.15.spec.in index 22c750c6..a471f97b 100644 --- a/vips-7.15.spec.in +++ b/vips-7.15.spec.in @@ -1,101 +1,206 @@ -%define name @PACKAGE@ -%define version @VERSION@ -%define release 1 -%define default_install_prefix /usr/local +%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} + +Name: @PACKAGE@ +Version: @VERSION@ +Release: 1%{?dist} +Summary: Library for processing large images + +Group: System Environment/Libraries +License: LGPLv2+ +URL: http://www.vips.ecs.soton.ac.uk/ +Source0: http://www.vips.ecs.soton.ac.uk/supported/7.14/%{name}-%{version}.tar.gz + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: libjpeg-devel libtiff-devel zlib-devel fftw-devel lcms-devel +BuildRequires: libpng-devel glib2-devel ImageMagick-devel pango-devel +BuildRequires: pkgconfig gettext perl(XML::Parser) +BuildRequires: libtool python-devel libxml2-devel liboil-devel +BuildRequires: OpenEXR-devel libexif-devel swig +#Requires: -Summary: an image processing library -Name: %{name} -Version: %{version} -Release: %{release} -License: LGPL -Group: Development/Libraries -Source: http://www.vips.ecs.soton.ac.uk/vips-7.12/%{name}-%{version}.tar.gz -URL: http://www.vips.ecs.soton.ac.uk/ -BuildRoot: %{_tmppath}/%{name}-buildroot -Provides: vips -Prefix: %{default_install_prefix} %description -VIPS is an image processing library. It is good for very large images (ie. -larger than the amount of RAM in your machine), and for working with colour. -It includes a C++ API, complete man pages, a command-line interface, automatic -threading and an operation database. There are several user interfaces -built on top of VIPS: for example "nip2". +VIPS is an image processing library. It is good for very large images +(even larger than the amount of RAM in your machine), and for working +with color. It includes a C++ API, complete man pages, a command-line +interface, automatic threading and an operation database. There are +several user interfaces built on top of VIPS: for example "nip2". + +This package should be installed if you want to use a program compiled +against VIPS. + %package devel -Summary: Headers and links to develop with vips -Requires: vips = %{version} +Summary: Development tools for programs for processing large images Group: Development/Libraries +Requires: %{name} = %{version}-%{release}, pkgconfig +Requires: libjpeg-devel libtiff-devel zlib-devel fftw-devel lcms-devel +Requires: libpng-devel glib2-devel ImageMagick-devel pango-devel +Requires: libxml2-devel liboil-devel OpenEXR-devel libexif-devel %description devel -These headers are needed to develop programs which want to use the vips -library. Programs already linked against it only need the vips package. +The %{name}-devel package contains the header files and +libraries necessary for developing programs using VIPS. It also +contains a C++ API and development man pages. + + +%package tools +Summary: Command-line tools for processing large images +Group: Applications/Multimedia +Requires: %{name} = %{version}-%{release} + +%description tools +The %{name}-tools package contains command-line tools for working with VIPS. + %package python -Summary: Python bindings to use vips -Requires: vips = %{version} -Group: Development/Libraries +Summary: Python support for the VIPS image processing library +Group: Development/Languages +Requires: %{name} = %{version}-%{release} %description python -Includes the necessary files to use and develop with vips and python +The %{name}-python package contains Python support for VIPS. + + +%package doc +Summary: Documentation for VIPS image processing library +Group: Documentation +Conflicts: %{name} < %{version}-%{release}, %{name} > %{version}-%{release} + +%description doc +The %{name}-doc package contains extensive documentation about VIPS in both +HTML and PDF formats. + %prep -rm -rf $RPM_BUILD_ROOT -%setup +%setup -q +find . -name 'CVS' -type d -print0 | xargs -0r rm -rf +find . -name '\.svn' -type d -print0 | xargs -0r rm -rf + +# make the version string consistent for multiarch +export FAKE_BUILD_DATE=$(date -r %{SOURCE0}) +sed -i "s/\\(IM_VERSION_STRING=\\)\$IM_VERSION-\`date\`/\\1\"\$IM_VERSION-$FAKE_BUILD_DATE\"/g" \ + configure +unset FAKE_BUILD_DATE + %build -# grr ... why do we have to set prefix by hand? if you don't do this, you get -# /usr, despite the "Prefix:" tag above -%define _prefix %{default_install_prefix} -%configure +%configure --disable-static +make %{?_smp_mflags} LIBTOOL=libtool + %install -%makeinstall +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT +find $RPM_BUILD_ROOT \( -name '*.la' -o -name '*.a' \) -exec rm -f {} ';' + +# delete doc (we will get it later with %doc) +rm -rf ${RPM_BUILD_ROOT}%{_datadir}/doc/vips + +# malkovich?? +rm -rf ${RPM_BUILD_ROOT}%{_datadir}/locale/malkovich + +# locale stuff +%find_lang vips7 + + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig -# paste in the non-GPL stuff as a binary plugin -# comment this out if you don't have it :-( -# cp ~john/develop/transform-7.9/src/resample.plg ${RPM_BUILD_ROOT}%{_libdir} %clean rm -rf $RPM_BUILD_ROOT -%post -ldconfig -%files -# don't list explicitly ... install to a private prefix and rely on naming the -# dirs to pick up the files -%attr(-, root, root) -%doc AUTHORS THANKS README TODO COPYING ChangeLog -%{_bindir} -%{_libdir}/libvips*.so.* -%doc %{_mandir} -%doc %{_datadir}/doc/vips +%files -f vips7.lang +%defattr(-,root,root,-) +%doc AUTHORS NEWS THANKS TODO COPYING ChangeLog +%{_libdir}/*.so.* %{_datadir}/vips -%{_datadir}/locale + %files devel +%defattr(-,root,root,-) %{_includedir}/vips -%{_libdir}/libvips*.so -%{_libdir}/libvips*.a -%{_libdir}/libvips*.la +%{_libdir}/*.so %{_libdir}/pkgconfig/* +%{_mandir}/man3/* + + +%files tools +%defattr(-,root,root,-) +%{_bindir}/* +%{_mandir}/man1/* + %files python -%{_libdir}/python* +%defattr(-,root,root,-) +%{python_sitearch}/* -%changelog -n vips -* Wed Aug 29 2007 John Cupitt 7.14 -- updated for 7.14 -* Fri Apr 27 2007 John Cupitt 7.12 -- updated for 7.12 +%files doc +%defattr(-,root,root,-) +%doc doc/html doc/pdf -* Fri Dec 29 2006 - plasmahh@projectiwear.org -- Split up into library and devel package -* Wed Jun 1 2005 John Cupitt 7.11 -- updated for 7.11 + +%changelog +* Sat Jul 19 2008 Jesper Friis - 7.15.0-1 +- Replaced the distributed spec file with the one in the source rpm + package from Fedora to fix issues with harcoding BuildRoot in the + installed files + +* Sat Mar 15 2008 Adam Goode - 7.14.1-1 +- New release + +* Mon Mar 10 2008 Adam Goode - 7.14.0-1 +- New release +- Remove GCC 4.3 patch (upstream) + +* Sat Feb 9 2008 Adam Goode - 7.12.5-5 +- Fix GCC 4.3 build + +* Sat Feb 9 2008 Adam Goode - 7.12.5-4 +- GCC 4.3 mass rebuild + +* Tue Oct 23 2007 Adam Goode - 7.12.5-3 +- Eliminate build differences in version.h to work on multiarch + +* Mon Oct 15 2007 Adam Goode - 7.12.5-2 +- Rebuild for OpenEXR update + +* Fri Sep 21 2007 Adam Goode - 7.12.5-1 +- New upstream release + +* Thu Aug 16 2007 Adam Goode - 7.12.4-2 +- Add Conflicts for doc +- Update doc package description + +* Thu Aug 16 2007 Adam Goode - 7.12.4-1 +- New upstream release +- Update License tag + +* Tue Jul 24 2007 Adam Goode - 7.12.2-1 +- New stable release 7.12 + +* Sat May 5 2007 Adam Goode - 7.12.0-1 +- New upstream release + +* Thu Aug 31 2006 Adam Goode - 7.10.21-1 +- New upstream release + +* Fri Jul 28 2006 Adam Goode - 7.10.20-3 +- Include results of running automake in the patch for undefined symbols +- No longer run automake or autoconf (autoconf was never actually necessary) + +* Mon Jul 24 2006 Adam Goode - 7.10.20-2 +- Eliminate undefined non-weak symbols in libvipsCC.so + +* Fri Jul 21 2006 Adam Goode - 7.10.20-1 +- New upstream release +- Updated for FC5 * Tue Dec 14 2004 John Cupitt 7.10.8 - updated for 7.10.8 @@ -104,7 +209,7 @@ ldconfig * Wed Jul 16 2003 John Cupitt 7.8.10 - updated for 7.8.10 -- updated %files +- updated %%files - copies formatted docs to install area * Wed Mar 12 2003 John Cupitt 7.8.8