merge loadable-format branch

This commit is contained in:
John Cupitt 2008-08-15 08:40:05 +00:00
parent 263397cce3
commit 0fb1fae5c7
45 changed files with 1307 additions and 10422 deletions

View File

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

36
TODO
View File

@ -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

View File

@ -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

View File

@ -36,6 +36,7 @@
extern "C" {
#endif /*__cplusplus*/
#include <glib-object.h>
#include <vips/vips.h>
#include <vips/util.h>
@ -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 );

View File

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

View File

@ -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
*/

View File

@ -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*/

View File

@ -492,6 +492,7 @@ typedef struct {
#include <vips/proto.h>
#include <vips/colour.h>
/* #include <vips/vector.h> */
#include <vips/dispatch.h>
#include <vips/region.h>
#include <vips/semaphore.h>

View File

@ -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 \

View File

@ -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

View File

@ -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[] = {
&copy_swap_desc,
&copy_set_desc,
&copy_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
};

View File

@ -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

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "dbh.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_OPENEXR
#include <vips/vips.h>
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 <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <vips/vips.h>
#include <vips/thread.h>
#include <ImfCRgbaFile.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 </libexif/ prefix if required
* 11/2/08
* - spot CMYK jpegs and set Type
* - spot Adobe CMYK JPEG and invert ink density
* 15/2/08
* - added "shrink" parameter
*/
/*
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
#define DEBUG_VERBOSE
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_JPEG
#include <vips/vips.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <assert.h>
#ifdef HAVE_EXIF
#ifdef UNTAGGED_EXIF
#include <exif-data.h>
#include <exif-loader.h>
#include <exif-ifd.h>
#include <exif-utils.h>
#else /*!UNTAGGED_EXIF*/
#include <libexif/exif-data.h>
#include <libexif/exif-loader.h>
#include <libexif/exif-ifd.h>
#include <libexif/exif-utils.h>
#endif /*UNTAGGED_EXIF*/
#endif /*HAVE_EXIF*/
#include <vips/vips.h>
#include <vips/vbuf.h>
/* 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 <jpeglib.h>
#include <jerror.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_MAGICK
#include <vips/vips.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <vips/vips.h>
#include <vips/vbuf.h>
#include <vips/thread.h>
#include <magick/api.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_PNG
#include <vips/vips.h>
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 <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <png.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <vips/vips.h>
#include <vips/thread.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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", <tab>)
* 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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <assert.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 </libexif/ prefix if required
* 19/1/07
* - oop, libexif confusion
* 2/11/07
* - use im_wbuffer() API for BG writes
* 15/2/08
* - write CMYK if Bands == 4 and Type == CMYK
*/
/*
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
#define DEBUG_VERBOSE
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_JPEG
#include <vips/vips.h>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <assert.h>
#ifdef HAVE_EXIF
#ifdef UNTAGGED_EXIF
#include <exif-data.h>
#include <exif-loader.h>
#include <exif-ifd.h>
#include <exif-utils.h>
#else /*!UNTAGGED_EXIF*/
#include <libexif/exif-data.h>
#include <libexif/exif-loader.h>
#include <libexif/exif-ifd.h>
#include <libexif/exif-utils.h>
#endif /*UNTAGGED_EXIF*/
#endif /*HAVE_EXIF*/
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/vbuf.h>
/* 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 <jpeglib.h>
#include <jerror.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifndef HAVE_PNG
#include <vips/vips.h>
int
im_vips2png( IMAGE *in, const char *filename )
{
im_error( "im_vips2png", _( "PNG support disabled" ) );
return( -1 );
}
#else /*HAVE_PNG*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <png.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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*/

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

File diff suppressed because it is too large Load Diff

View File

@ -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@

View File

@ -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.

View File

@ -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 <stdio.h>
@ -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 )
{

View File

@ -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 )
{

127
libsrc/format/im_vips2raw.c Normal file
View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <glib/gstring.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -59,6 +59,9 @@
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

View File

@ -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@

View File

@ -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 */
};

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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.

View File

@ -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 <dmalloc.h>
#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 );
}

View File

@ -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 <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
@ -96,73 +70,229 @@
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <assert.h>
#ifdef HAVE_IO_H
#include <io.h>
#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 <vips/vips.h>
#include <vips/internal.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <vips/vips.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}

View File

@ -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 : "<unknown>";
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

View File

@ -24,6 +24,8 @@
* - added exr
* 3/8/07
* - cleanups
* 22/5/08
* - image format stuff broken out
*/
/*
@ -74,14 +76,6 @@
#include <vips/vips.h>
#ifdef HAVE_TIFF
#include <tiffio.h>
#endif /*HAVE_TIFF*/
#ifdef HAVE_PNG
#include <png.h>
#endif /*HAVE_PNG*/
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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.

View File

@ -48,6 +48,10 @@
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#ifdef OS_WIN32
#include <windows.h>
#endif /*OS_WIN32*/
#include <assert.h>
#include <vips/vips.h>
@ -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();
}

View File

@ -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 <jcupitt@gmail.com> 7.14
- updated for 7.14
* Fri Apr 27 2007 John Cupitt <jcupitt@gmail.com> 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 <john.cupitt@ng-london.org.uk> 7.11
- updated for 7.11
%changelog
* Sat Jul 19 2008 Jesper Friis <jesper.friis(at)sintef.no> - 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 <adam@spicenitz.org> - 7.14.1-1
- New release
* Mon Mar 10 2008 Adam Goode <adam@spicenitz.org> - 7.14.0-1
- New release
- Remove GCC 4.3 patch (upstream)
* Sat Feb 9 2008 Adam Goode <adam@spicenitz.org> - 7.12.5-5
- Fix GCC 4.3 build
* Sat Feb 9 2008 Adam Goode <adam@spicenitz.org> - 7.12.5-4
- GCC 4.3 mass rebuild
* Tue Oct 23 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-3
- Eliminate build differences in version.h to work on multiarch
* Mon Oct 15 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-2
- Rebuild for OpenEXR update
* Fri Sep 21 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-1
- New upstream release
* Thu Aug 16 2007 Adam Goode <adam@spicenitz.org> - 7.12.4-2
- Add Conflicts for doc
- Update doc package description
* Thu Aug 16 2007 Adam Goode <adam@spicenitz.org> - 7.12.4-1
- New upstream release
- Update License tag
* Tue Jul 24 2007 Adam Goode <adam@spicenitz.org> - 7.12.2-1
- New stable release 7.12
* Sat May 5 2007 Adam Goode <adam@spicenitz.org> - 7.12.0-1
- New upstream release
* Thu Aug 31 2006 Adam Goode <adam@spicenitz.org> - 7.10.21-1
- New upstream release
* Fri Jul 28 2006 Adam Goode <adam@spicenitz.org> - 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 <adam@spicenitz.org> - 7.10.20-2
- Eliminate undefined non-weak symbols in libvipsCC.so
* Fri Jul 21 2006 Adam Goode <adam@spicenitz.org> - 7.10.20-1
- New upstream release
- Updated for FC5
* Tue Dec 14 2004 John Cupitt <john.cupitt@ng-london.org.uk> 7.10.8
- updated for 7.10.8
@ -104,7 +209,7 @@ ldconfig
* Wed Jul 16 2003 John Cupitt <john.cupitt@ng-london.org.uk> 7.8.10
- updated for 7.8.10
- updated %files
- updated %%files
- copies formatted docs to install area
* Wed Mar 12 2003 John Cupitt <john.cupitt@ng-london.org.uk> 7.8.8