merge loadable-format branch
This commit is contained in:
parent
263397cce3
commit
0fb1fae5c7
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
||||
25/5/08 fork for loadable image format branch
|
||||
- image load/save in non-vips format code moved to own dir
|
||||
- simple format searching added
|
||||
- some cleanups for vips load
|
||||
- im_open() simplified
|
||||
- add im_format_flags
|
||||
- only consider formats with a save method in im_format_for_name()
|
||||
- oops, format sort order was reversed
|
||||
- im_filename_suffix() includes "." in suffix
|
||||
- merge back into trunk for 7.15.1
|
||||
|
||||
7/3/08 started 7.15.0
|
||||
- MAGIC constants should be tagged as unsigned
|
||||
- write MAGIC correctly on sparc/powerpc machines (thanks Joe)
|
||||
|
36
TODO
36
TODO
@ -1,5 +1,37 @@
|
||||
- merge loadable format stuff, postpone new object parameter API to next
|
||||
version
|
||||
- is_a.c should be broken out into the respective loaders? that's how it
|
||||
wouldbe for plugns
|
||||
|
||||
- something in vips.c to list the available formats, like
|
||||
|
||||
vips --list packages
|
||||
|
||||
perhaps
|
||||
|
||||
vips --list formats
|
||||
|
||||
- add API to add operations and formats, can be used by plugins in module init
|
||||
to register stuff
|
||||
|
||||
- deprecate the current plugin init system
|
||||
|
||||
- more cleanups to the handling of vips format images, esp. we have vips write
|
||||
spread across many files atm
|
||||
|
||||
- could remove a lot of crappy old API
|
||||
|
||||
- it'd be nice to handle vips format images in the same im_format system, but
|
||||
it's not clear if this is possible
|
||||
|
||||
- we sometimes name types with a trailing _t, but only sometimes, argh
|
||||
|
||||
should im_format become im_format_t? what's the current naming convention?
|
||||
should be add _t variants for all types?
|
||||
|
||||
|
||||
|
||||
- when we open with a mmap window and later do im_incheck(), do we remap the
|
||||
whole file?
|
||||
|
||||
|
||||
- try
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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*/
|
||||
|
@ -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>
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
||||
|
@ -1444,355 +1444,6 @@ static im_function zoom_desc = {
|
||||
zoom_args /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
jpeg2vips_vec( im_object *argv )
|
||||
{
|
||||
char *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
|
||||
if( im_jpeg2vips( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static im_arg_desc jpeg2vips_args[] = {
|
||||
IM_INPUT_STRING( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
static im_function jpeg2vips_desc = {
|
||||
"im_jpeg2vips", /* Name */
|
||||
"convert from jpeg", /* Description */
|
||||
0, /* Flags */
|
||||
jpeg2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( jpeg2vips_args ), /* Size of arg list */
|
||||
jpeg2vips_args /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
vips2jpeg_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *in = argv[0];
|
||||
char *out = argv[1];
|
||||
|
||||
if( im_vips2jpeg( in, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static im_arg_desc vips2jpeg_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_INPUT_STRING( "out" )
|
||||
};
|
||||
|
||||
static im_function vips2jpeg_desc = {
|
||||
"im_vips2jpeg", /* Name */
|
||||
"convert to jpeg", /* Description */
|
||||
0, /* Flags */
|
||||
vips2jpeg_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2jpeg_args ), /* Size of arg list */
|
||||
vips2jpeg_args /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
vips2mimejpeg_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *in = argv[0];
|
||||
int qfac = *((int *) argv[1]);
|
||||
|
||||
if( im_vips2mimejpeg( in, qfac ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static im_arg_desc vips2mimejpeg_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_INPUT_INT( "qfac" )
|
||||
};
|
||||
|
||||
static im_function vips2mimejpeg_desc = {
|
||||
"im_vips2mimejpeg", /* Name */
|
||||
"convert to jpeg as mime type on stdout", /* Description */
|
||||
0, /* Flags */
|
||||
vips2mimejpeg_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2mimejpeg_args ), /* Size of arg list */
|
||||
vips2mimejpeg_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for vips2png.
|
||||
*/
|
||||
static im_arg_desc vips2png_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_INPUT_STRING( "out" )
|
||||
};
|
||||
|
||||
/* Call im_vips2png via arg vector.
|
||||
*/
|
||||
static int
|
||||
vips2png_vec( im_object *argv )
|
||||
{
|
||||
return( im_vips2png( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_vips2png.
|
||||
*/
|
||||
static im_function vips2png_desc = {
|
||||
"im_vips2png", /* Name */
|
||||
"convert VIPS image to PNG file", /* Description */
|
||||
0,
|
||||
vips2png_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2png_args ), /* Size of arg list */
|
||||
vips2png_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for png2vips.
|
||||
*/
|
||||
static im_arg_desc png2vips_args[] = {
|
||||
IM_INPUT_STRING( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_png2vips via arg vector.
|
||||
*/
|
||||
static int
|
||||
png2vips_vec( im_object *argv )
|
||||
{
|
||||
return( im_png2vips( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_png2vips.
|
||||
*/
|
||||
static im_function png2vips_desc = {
|
||||
"im_png2vips", /* Name */
|
||||
"convert PNG file to VIPS image", /* Description */
|
||||
0,
|
||||
png2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( png2vips_args ), /* Size of arg list */
|
||||
png2vips_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for exr2vips.
|
||||
*/
|
||||
static im_arg_desc exr2vips_args[] = {
|
||||
IM_INPUT_STRING( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_exr2vips via arg vector.
|
||||
*/
|
||||
static int
|
||||
exr2vips_vec( im_object *argv )
|
||||
{
|
||||
return( im_exr2vips( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_exr2vips.
|
||||
*/
|
||||
static im_function exr2vips_desc = {
|
||||
"im_exr2vips", /* Name */
|
||||
"convert an OpenEXR file to VIPS", /* Description */
|
||||
0,
|
||||
exr2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( exr2vips_args ), /* Size of arg list */
|
||||
exr2vips_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for vips2tiff.
|
||||
*/
|
||||
static im_arg_desc vips2tiff_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_INPUT_STRING( "out" )
|
||||
};
|
||||
|
||||
/* Call im_vips2tiff via arg vector.
|
||||
*/
|
||||
static int
|
||||
vips2tiff_vec( im_object *argv )
|
||||
{
|
||||
return( im_vips2tiff( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_vips2tiff.
|
||||
*/
|
||||
static im_function vips2tiff_desc = {
|
||||
"im_vips2tiff", /* Name */
|
||||
"convert VIPS image to TIFF file", /* Description */
|
||||
0,
|
||||
vips2tiff_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2tiff_args ), /* Size of arg list */
|
||||
vips2tiff_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for magick2vips.
|
||||
*/
|
||||
static im_arg_desc magick2vips_args[] = {
|
||||
IM_INPUT_STRING( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_magick2vips via arg vector.
|
||||
*/
|
||||
static int
|
||||
magick2vips_vec( im_object *argv )
|
||||
{
|
||||
return( im_magick2vips( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_magick2vips.
|
||||
*/
|
||||
static im_function magick2vips_desc = {
|
||||
"im_magick2vips", /* Name */
|
||||
"load file with libMagick", /* Description */
|
||||
0,
|
||||
magick2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( magick2vips_args ), /* Size of arg list */
|
||||
magick2vips_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for tiff2vips.
|
||||
*/
|
||||
static im_arg_desc tiff2vips_args[] = {
|
||||
IM_INPUT_STRING( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" )
|
||||
};
|
||||
|
||||
/* Call im_tiff2vips via arg vector.
|
||||
*/
|
||||
static int
|
||||
tiff2vips_vec( im_object *argv )
|
||||
{
|
||||
return( im_tiff2vips( argv[0], argv[1] ) );
|
||||
}
|
||||
|
||||
/* Description of im_tiff2vips.
|
||||
*/
|
||||
static im_function tiff2vips_desc = {
|
||||
"im_tiff2vips", /* Name */
|
||||
"convert TIFF file to VIPS image", /* Description */
|
||||
0,
|
||||
tiff2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( tiff2vips_args ), /* Size of arg list */
|
||||
tiff2vips_args /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
analyze2vips_vec( im_object *argv )
|
||||
{
|
||||
const char *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
|
||||
return( im_analyze2vips( in, out ) );
|
||||
}
|
||||
|
||||
static im_arg_desc analyze2vips_arg_types[] = {
|
||||
IM_INPUT_STRING( "filename" ),
|
||||
IM_OUTPUT_IMAGE( "im" )
|
||||
};
|
||||
|
||||
static im_function analyze2vips_desc = {
|
||||
"im_analyze2vips", /* Name */
|
||||
"read a file in analyze format",/* Description */
|
||||
0, /* Flags */
|
||||
analyze2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( analyze2vips_arg_types ),/* Size of arg list */
|
||||
analyze2vips_arg_types /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
csv2vips_vec( im_object *argv )
|
||||
{
|
||||
const char *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
|
||||
return( im_csv2vips( in, out ) );
|
||||
}
|
||||
|
||||
static im_arg_desc csv2vips_arg_types[] = {
|
||||
IM_INPUT_STRING( "filename" ),
|
||||
IM_OUTPUT_IMAGE( "im" )
|
||||
};
|
||||
|
||||
static im_function csv2vips_desc = {
|
||||
"im_csv2vips", /* Name */
|
||||
"read a file in csv format",/* Description */
|
||||
0, /* Flags */
|
||||
csv2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( csv2vips_arg_types ),/* Size of arg list */
|
||||
csv2vips_arg_types /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
vips2csv_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *in = argv[0];
|
||||
const char *filename = argv[1];
|
||||
|
||||
return( im_vips2csv( in, filename ) );
|
||||
}
|
||||
|
||||
static im_arg_desc vips2csv_arg_types[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_INPUT_STRING( "filename" )
|
||||
};
|
||||
|
||||
static im_function vips2csv_desc = {
|
||||
"im_vips2csv", /* Name */
|
||||
"write an image in csv format", /* Description */
|
||||
0, /* Flags */
|
||||
vips2csv_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2csv_arg_types ),/* Size of arg list */
|
||||
vips2csv_arg_types /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
ppm2vips_vec( im_object *argv )
|
||||
{
|
||||
const char *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
|
||||
return( im_ppm2vips( in, out ) );
|
||||
}
|
||||
|
||||
static im_arg_desc ppm2vips_arg_types[] = {
|
||||
IM_INPUT_STRING( "filename" ),
|
||||
IM_OUTPUT_IMAGE( "im" )
|
||||
};
|
||||
|
||||
static im_function ppm2vips_desc = {
|
||||
"im_ppm2vips", /* Name */
|
||||
"read a file in pbm/pgm/ppm format", /* Description */
|
||||
0, /* Flags */
|
||||
ppm2vips_vec, /* Dispatch function */
|
||||
IM_NUMBER( ppm2vips_arg_types ),/* Size of arg list */
|
||||
ppm2vips_arg_types /* Arg list */
|
||||
};
|
||||
|
||||
static int
|
||||
vips2ppm_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *im = argv[0];
|
||||
const char *filename = argv[1];
|
||||
|
||||
return( im_vips2ppm( im, filename ) );
|
||||
}
|
||||
|
||||
static im_arg_desc vips2ppm_arg_types[] = {
|
||||
IM_INPUT_IMAGE( "im" ),
|
||||
IM_INPUT_STRING( "filename" )
|
||||
};
|
||||
|
||||
static im_function vips2ppm_desc = {
|
||||
"im_vips2ppm", /* Name */
|
||||
"write a file in pbm/pgm/ppm format", /* Description */
|
||||
0, /* Flags */
|
||||
vips2ppm_vec, /* Dispatch function */
|
||||
IM_NUMBER( vips2ppm_arg_types ),/* Size of arg list */
|
||||
vips2ppm_arg_types /* Arg list */
|
||||
};
|
||||
|
||||
/* Call im_msb via arg vector.
|
||||
*/
|
||||
static int
|
||||
@ -1934,7 +1585,6 @@ static im_function *conv_list[] = {
|
||||
©_swap_desc,
|
||||
©_set_desc,
|
||||
©_set_meta_desc,
|
||||
&csv2vips_desc,
|
||||
&extract_area_desc,
|
||||
&extract_areabands_desc,
|
||||
&extract_band_desc,
|
||||
@ -1947,16 +1597,10 @@ static im_function *conv_list[] = {
|
||||
&grid_desc,
|
||||
&insert_desc,
|
||||
&insert_noexpand_desc,
|
||||
&jpeg2vips_desc,
|
||||
&lrjoin_desc,
|
||||
&magick2vips_desc,
|
||||
&mask2vips_desc,
|
||||
&msb_desc,
|
||||
&msb_band_desc,
|
||||
&png2vips_desc,
|
||||
&exr2vips_desc,
|
||||
&ppm2vips_desc,
|
||||
&analyze2vips_desc,
|
||||
&print_desc,
|
||||
&recomb_desc,
|
||||
&replicate_desc,
|
||||
@ -1973,14 +1617,7 @@ static im_function *conv_list[] = {
|
||||
&tbjoin_desc,
|
||||
&text_desc,
|
||||
&thresh_desc,
|
||||
&tiff2vips_desc,
|
||||
&vips2csv_desc,
|
||||
&vips2jpeg_desc,
|
||||
&vips2mask_desc,
|
||||
&vips2mimejpeg_desc,
|
||||
&vips2png_desc,
|
||||
&vips2ppm_desc,
|
||||
&vips2tiff_desc,
|
||||
&wrap_desc,
|
||||
&zoom_desc
|
||||
};
|
||||
|
@ -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
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
@ -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*/
|
@ -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*/
|
@ -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*/
|
@ -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*/
|
@ -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 );
|
||||
}
|
@ -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
@ -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 );
|
||||
}
|
@ -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 );
|
||||
}
|
@ -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*/
|
@ -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*/
|
@ -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
@ -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@
|
||||
|
@ -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.
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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
127
libsrc/format/im_vips2raw.c
Normal 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 );
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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@
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 );
|
||||
}
|
@ -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.
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
@ -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 );
|
||||
}
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user