This commit is contained in:
John Cupitt 2009-09-17 08:51:37 +00:00
parent 6a745c5264
commit c6418893eb
11 changed files with 232 additions and 341 deletions

View File

@ -35,6 +35,8 @@
- im_max()/im_min() are now convenience functions
- im_maxpos_avg() handles complex and multi-band images
- added im_point(), rewrite im_point_bilinear() in terms of this
- close callbacks now happen *after* images have closed resources (such as
open files) ... this lets them delete temps and stuff. Expect breakage :(
- added vips_interpolate_get_window_offset()
25/3/09 started 7.18.0

44
TODO
View File

@ -1,4 +1,48 @@
- look at im_remainderconst_vec()
put that functionality into something like im__cast_and_call(), then share
with im_andimage_const_vec()
working in im__arith_binary_const()
- experimenting with
png_set_shift( read->pPng, 2 );
in im_png2vips.c
test image in gmail
- Joe's new def
- we have im_andimage(), but im_and_vec(), argh
shouldn't it be im_andimageconst_vec()? won't we have C++ problems the way
things are?
Something like:
const char *im_system_image( IMAGE *in, const char *command, char **log );
Actions:
- create two empty temporary files
- write the image to the first
- call system() on the expanded command
- capture stdout/stderr into log
- delete the temp input file
- return the output filename, or NULL if the command failed (log is still
returned in this case)
The caller would open the output file, either with im_open(), or with it's
own system (nip2 has it's own open file thing to give progress feedback and
use disc for format conversion), and be responsible for deleting the temp
output file at some point.
- 1-bit PNG read is broken?

View File

@ -44,9 +44,7 @@
/**
* SECTION: arithmetic
* @short_description: operations which perform pixel arithmetic, trig, log,
* statistics
*
* @short_description: operations which perform pixel arithmetic, trig, log, statistics
* @see_also: <link linkend="VIPS-iofuncs">iofuncs</link>
* @stability: Stable
* @include: vips/vips.h

View File

@ -25,6 +25,9 @@
* - im__cast_and_call() no longer sets bbits for you
* - add gtkdoc comments
* - remove separate complex case, just double size
* 11/9/09
* - im__cast_and_call() becomes im__arith_binary()
* - more of operation scaffold moved inside
*/
/*
@ -151,7 +154,7 @@ static int bandfmt_largest[6][6] = {
/* For two formats, find one which can represent the full range of both.
*/
VipsBandFmt
static VipsBandFmt
im__format_common( IMAGE *in1, IMAGE *in2 )
{
if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) {
@ -206,16 +209,43 @@ im__bandup( IMAGE *in, IMAGE *out, int n )
return( im_gbandjoin( bands, out, n ) );
}
/* Cast in1 and in2 up to a common type and number of bands, then call the
* function. Also used by subtract, multiply, divide, etc.
/* The common part of most binary arithmetic, relational and boolean
* operators. We:
*
* - check in and out
* - cast in1 and in2 up to a common format
* - cast the common format to the output format with the supplied table
* - equalise bands
* - run the supplied buffer operation
*/
int
im__cast_and_call( IMAGE *in1, IMAGE *in2, IMAGE *out,
im__arith_binary( const char *name,
IMAGE *in1, IMAGE *in2, IMAGE *out,
int format_table[10],
im_wrapmany_fn fn, void *a )
{
VipsBandFmt fmt;
IMAGE *t[5];
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( name, in1, in2 ) ||
im_check_uncoded( name, in1 ) ||
im_check_uncoded( name, in2 ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? int, float or complex.
*/
out->BandFmt = format_table[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt );
if( im_open_local_array( out, t, 4, "type cast:1", "p" ) )
return( -1 );
@ -331,33 +361,9 @@ static int bandfmt_add[10] = {
*/
int
im_add( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( "im_add", in1, in2 ) ||
im_check_uncoded( "im_add", in1 ) ||
im_check_uncoded( "im_add", in2 ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? int, float or complex.
*/
out->BandFmt = bandfmt_add[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt );
/* And process!
*/
if( im__cast_and_call( in1, in2, out,
(im_wrapmany_fn) add_buffer, NULL ) )
return( -1 );
/* Success!
*/
return( 0 );
{
return( im__arith_binary( "im_add",
in1, in2, out,
bandfmt_add,
(im_wrapmany_fn) add_buffer, NULL ) );
}

View File

@ -271,32 +271,8 @@ static int bandfmt_divide[10] = {
int
im_divide( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( "im_divide", in1, in2 ) ||
im_check_uncoded( "im_divide", in1 ) ||
im_check_uncoded( "im_divide", in2 ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? int, float or complex.
*/
out->BandFmt = bandfmt_divide[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt );
/* And process!
*/
if( im__cast_and_call( in1, in2, out,
(im_wrapmany_fn) divide_buffer, NULL ) )
return( -1 );
/* Success!
*/
return( 0 );
return( im__arith_binary( "im_divide",
in1, in2, out,
bandfmt_divide,
(im_wrapmany_fn) divide_buffer, NULL ) );
}

View File

@ -246,32 +246,8 @@ static int bandfmt_multiply[10] = {
int
im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( "im_multiply", in1, in2 ) ||
im_check_uncoded( "im_multiply", in1 ) ||
im_check_uncoded( "im_multiply", in2 ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? int, float or complex.
*/
out->BandFmt = bandfmt_multiply[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt );
/* And process!
*/
if( im__cast_and_call( in1, in2, out,
(im_wrapmany_fn) multiply_buffer, NULL ) )
return( -1 );
/* Success!
*/
return( 0 );
return( im__arith_binary( "im_multiply",
in1, in2, out,
bandfmt_multiply,
(im_wrapmany_fn) multiply_buffer, NULL ) );
}

View File

@ -160,39 +160,85 @@ static int bandfmt_remainder[10] = {
*/
int
im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( "im_remainder", in1, in2 ) ||
im_check_uncoded( "im_remainder", in1 ) ||
im_check_uncoded( "im_remainder", in2 ) ||
im_check_noncomplex( "im_remainder", in1 ) ||
im_check_noncomplex( "im_remainder", in2 ) )
{
return( im__arith_binary( "im_remainder",
in1, in2, out,
bandfmt_remainder,
(im_wrapmany_fn) remainder_buffer, NULL ) );
}
/* Cast a vector of double to a vector of TYPE.
*/
#define CAST( TYPE ) { \
TYPE *tq = (TYPE *) q; \
\
for( i = 0; i < n; i++ ) \
tq[i] = (TYPE) p[i]; \
}
/* Make a pixel of output type from a realvec.
*/
static PEL *
make_pixel( IMAGE *out, int n, double *p )
{
PEL *q;
int i;
g_assert( n == out->Bands );
if( !(q = IM_ARRAY( out, IM_IMAGE_SIZEOF_PEL( out ), PEL )) )
return( NULL );
switch( out->BandFmt ) {
case IM_BANDFMT_CHAR: CAST( signed char ); break;
case IM_BANDFMT_UCHAR: CAST( unsigned char ); break;
case IM_BANDFMT_SHORT: CAST( signed short ); break;
case IM_BANDFMT_USHORT: CAST( unsigned short ); break;
case IM_BANDFMT_INT: CAST( signed int ); break;
case IM_BANDFMT_UINT: CAST( unsigned int ); break;
default:
g_assert( 0 );
}
return( q );
}
int
im__arith_binary_const( const char *name,
IMAGE *in, IMAGE *out, int n, double *c,
int format_table[10],
im_wrapone_fn fn, void *a )
{
int i;
PEL *vector;
if( im_piocheck( in, out ) ||
im_check_vector( name, n, in ) ||
im_check_uncoded( name, in ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
if( im_cp_desc( out, in ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? Same as LHS type.
*/
out->BandFmt = bandfmt_remainder[im__format_common( in1, in2 )];
out->BandFmt = format_table[in->BandFmt];
out->Bbits = im_bits_of_fmt( out->BandFmt );
/* And process!
/* Cast vector to output type.
*/
if( im__cast_and_call( in1, in2, out,
(im_wrapmany_fn) remainder_buffer, NULL ) )
/*
need to handle case where vector == 1 but bands == (eg.) 3
*/
if( !(vector = make_pixel( out, n, c )) )
return( -1 );
if( im_wrapone( in, out, fn, a, vector ) )
return( -1 );
/* Success!
*/
return( 0 );
}
/* Parameters saved here.
*/
typedef struct _Remainderconst {

View File

@ -238,32 +238,8 @@ static int bandfmt_subtract[10] = {
int
im_subtract( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
if( im_piocheck( in1, out ) ||
im_pincheck( in2 ) ||
im_check_bands_1orn( "im_subtract", in1, in2 ) ||
im_check_uncoded( "im_subtract", in1 ) ||
im_check_uncoded( "im_subtract", in2 ) )
return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) )
return( -1 );
/* What number of bands will we write?
*/
out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? int, float or complex.
*/
out->BandFmt = bandfmt_subtract[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt );
/* And process!
*/
if( im__cast_and_call( in1, in2, out,
(im_wrapmany_fn) subtract_buffer, NULL ) )
return( -1 );
/* Success!
*/
return( 0 );
return( im__arith_binary( "im_subtract",
in1, in2, out,
bandfmt_subtract,
(im_wrapmany_fn) subtract_buffer, NULL ) );
}

View File

@ -40,6 +40,9 @@
* layer if operator names are turned on
* 30/6/04
* - now cast float/complex args to int
* 11/9/09
* - use new im__cast_and__call()
* - therefore now supports 1-band $op n-band
*/
/*
@ -75,7 +78,6 @@
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <vips/vips.h>
@ -83,102 +85,13 @@
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Save a bit of typing.
*/
#define UC IM_BANDFMT_UCHAR
#define C IM_BANDFMT_CHAR
#define US IM_BANDFMT_USHORT
#define S IM_BANDFMT_SHORT
#define UI IM_BANDFMT_UINT
#define I IM_BANDFMT_INT
#define F IM_BANDFMT_FLOAT
#define M IM_BANDFMT_COMPLEX
#define D IM_BANDFMT_DOUBLE
#define DM IM_BANDFMT_DPCOMPLEX
/* Type conversions for boolean.
*/
static int iformat[10][10] = {
/* UC C US S UI I F M D DM */
/* UC */ { UC, C, US, S, UI, I, I, I, I, I },
/* C */ { C, C, S, S, I, I, I, I, I, I },
/* US */ { US, S, US, S, UI, I, I, I, I, I },
/* S */ { S, S, S, S, I, I, I, I, I, I },
/* UI */ { UI, I, UI, I, UI, I, I, I, I, I },
/* I */ { I, I, I, I, I, I, I, I, I, I },
/* F */ { I, I, I, I, I, I, I, I, I, I },
/* M */ { I, I, I, I, I, I, I, I, I, I },
/* D */ { I, I, I, I, I, I, I, I, I, I },
/* DM */ { I, I, I, I, I, I, I, I, I, I }
};
/* Check args. Cast inputs to matching integer format.
*/
static int
check( IMAGE **in, IMAGE *out )
{
int i, n;
int fmt;
/* Count args.
*/
for( n = 0; in[n]; n++ ) {
if( in[n]->Coding != IM_CODING_NONE ) {
im_error( "boolean",
"%s", _( "uncoded images only" ) );
return( -1 );
}
}
/* Check sizes match.
*/
for( i = 1; i < n; i++ )
if( in[0]->Bands != in[i]->Bands ||
in[0]->Xsize != in[i]->Xsize ||
in[0]->Ysize != in[i]->Ysize ) {
im_error( "boolean",
"%s", _( "images differ in size" ) );
return( -1 );
}
/* Calculate type conversion ... just 1ary and 2ary.
*/
switch( n ) {
case 1:
fmt = iformat[0][in[0]->BandFmt];
break;
case 2:
fmt = iformat[in[1]->BandFmt][in[0]->BandFmt];
break;
default:
assert( FALSE );
}
for( i = 0; i < n; i++ ) {
IMAGE *t = im_open_local( out, "check-1", "p" );
if( !t || im_clip2fmt( in[i], t, fmt ) )
return( -1 );
in[i] = t;
}
/* Prepare the output image.
*/
if( im_cp_desc_array( out, in ) )
return( -1 );
return( 0 );
}
/* A selection of main loops. As with im_add(), only implement monotype
* operations. TYPE is some integer type, signed or unsigned.
/* A selection of main loops. Only implement monotype operations, ie. input
* type == output type. Float types are cast to int before we come here.
*/
#define AND2( TYPE ) { \
TYPE *tq = (TYPE *) q; \
TYPE *tp1 = (TYPE *) p1; \
TYPE *tp2 = (TYPE *) p2; \
TYPE *tp1 = (TYPE *) p[0]; \
TYPE *tp2 = (TYPE *) p[1]; \
\
for( x = 0; x < ne; x++ ) \
tq[x] = tp1[x] & tp2[x]; \
@ -186,8 +99,8 @@ check( IMAGE **in, IMAGE *out )
#define OR2( TYPE ) { \
TYPE *tq = (TYPE *) q; \
TYPE *tp1 = (TYPE *) p1; \
TYPE *tp2 = (TYPE *) p2; \
TYPE *tp1 = (TYPE *) p[0]; \
TYPE *tp2 = (TYPE *) p[1]; \
\
for( x = 0; x < ne; x++ ) \
tq[x] = tp1[x] | tp2[x]; \
@ -195,8 +108,8 @@ check( IMAGE **in, IMAGE *out )
#define EOR2( TYPE ) { \
TYPE *tq = (TYPE *) q; \
TYPE *tp1 = (TYPE *) p1; \
TYPE *tp2 = (TYPE *) p2; \
TYPE *tp1 = (TYPE *) p[0]; \
TYPE *tp2 = (TYPE *) p[1]; \
\
for( x = 0; x < ne; x++ ) \
tq[x] = tp1[x] ^ tp2[x]; \
@ -237,11 +150,9 @@ check( IMAGE **in, IMAGE *out )
static void
and_buffer( PEL **p, PEL *q, int n, IMAGE *im )
{
const int ne = n * im->Bands;
int x;
int bands = im->Bands;
int ne = n * bands;
PEL *p1 = p[0];
PEL *p2 = p[1];
switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: AND2( signed char ); break;
@ -252,20 +163,18 @@ and_buffer( PEL **p, PEL *q, int n, IMAGE *im )
case IM_BANDFMT_UINT: AND2( unsigned int ); break;
default:
error_exit( "im_and: internal error" );
g_assert( 0 );
}
}
static void
or_buffer( PEL **p, PEL *q, int n, IMAGE *in1 )
or_buffer( PEL **p, PEL *q, int n, IMAGE *im )
{
int x;
int bands = in1->Bands;
int ne = n * bands;
PEL *p1 = p[0];
PEL *p2 = p[1];
const int ne = n * im->Bands;
switch( in1->BandFmt ) {
int x;
switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: OR2( signed char ); break;
case IM_BANDFMT_UCHAR: OR2( unsigned char ); break;
case IM_BANDFMT_SHORT: OR2( signed short ); break;
@ -274,20 +183,18 @@ or_buffer( PEL **p, PEL *q, int n, IMAGE *in1 )
case IM_BANDFMT_UINT: OR2( unsigned int ); break;
default:
error_exit( "im_or: internal error" );
g_assert( 0 );
}
}
static void
eor_buffer( PEL **p, PEL *q, int n, IMAGE *in1 )
{
int x;
int bands = in1->Bands;
int ne = n * bands;
PEL *p1 = p[0];
PEL *p2 = p[1];
const int ne = n * im->Bands;
switch( in1->BandFmt ) {
int x;
switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: EOR2( signed char ); break;
case IM_BANDFMT_UCHAR: EOR2( unsigned char ); break;
case IM_BANDFMT_SHORT: EOR2( signed short ); break;
@ -296,7 +203,7 @@ eor_buffer( PEL **p, PEL *q, int n, IMAGE *in1 )
case IM_BANDFMT_UINT: EOR2( unsigned int ); break;
default:
error_exit( "im_eor: internal error" );
g_assert( 0 );
}
}
@ -315,7 +222,7 @@ andconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c )
case IM_BANDFMT_UINT: ANDCONST( unsigned int ); break;
default:
error_exit( "im_andconst: internal error" );
g_assert( 0 );
}
}
@ -334,7 +241,7 @@ orconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c )
case IM_BANDFMT_UINT: ORCONST( unsigned int ); break;
default:
error_exit( "im_orconst: internal error" );
g_assert( 0 );
}
}
@ -353,94 +260,53 @@ eorconst_buffer( PEL *p, PEL *q, int n, IMAGE *in, PEL *c )
case IM_BANDFMT_UINT: EORCONST( unsigned int ); break;
default:
error_exit( "im_eorconst: internal error" );
g_assert( 0 );
}
}
/* Save a bit of typing.
*/
#define UC IM_BANDFMT_UCHAR
#define C IM_BANDFMT_CHAR
#define US IM_BANDFMT_USHORT
#define S IM_BANDFMT_SHORT
#define UI IM_BANDFMT_UINT
#define I IM_BANDFMT_INT
/* Type conversions for boolean.
*/
static int bandfmt_bool[10] = {
/* UC C US S UI I F X D DX */
UC, C, US, S, UI, I, I, I, I, I },
};
/* The above, wrapped up as im_*() functions.
*/
int
im_andimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
IMAGE *invec[3];
/* Check images.
*/
invec[0] = in1; invec[1] = in2; invec[2] = NULL;
if( check( invec, out ) )
return( -1 );
/* Process!
*/
if( im_wrapmany( invec, out, (im_wrapmany_fn) and_buffer, out, NULL ) )
return( -1 );
return( 0 );
return( im__arith_binary( "im_andimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) and_buffer, NULL ) );
}
int
im_orimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
IMAGE *invec[3];
invec[0] = in1; invec[1] = in2; invec[2] = NULL;
if( check( invec, out ) )
return( -1 );
if( im_wrapmany( invec, out, (im_wrapmany_fn) or_buffer, out, NULL ) )
return( -1 );
return( 0 );
{
return( im__arith_binary( "im_orimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) or_buffer, NULL ) );
}
int
im_eorimage( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
IMAGE *invec[3];
invec[0] = in1; invec[1] = in2; invec[2] = NULL;
if( check( invec, out ) )
return( -1 );
if( im_wrapmany( invec, out, (im_wrapmany_fn) eor_buffer, out, NULL ) )
return( -1 );
return( 0 );
}
/* Cast a vector of double to a vector of TYPE.
*/
#define CAST( TYPE ) { \
TYPE *tq = (TYPE *) q; \
\
for( i = 0; i < out->Bands; i++ ) \
tq[i] = (TYPE) p[i]; \
}
/* Make a pixel of output type from a realvec.
*/
static PEL *
make_pixel( IMAGE *out, int fmt, double *p )
{
PEL *q;
int i;
if( !(q = IM_ARRAY( out, IM_IMAGE_SIZEOF_PEL( out ), PEL )) )
return( NULL );
switch( fmt ) {
case IM_BANDFMT_CHAR: CAST( signed char ); break;
case IM_BANDFMT_UCHAR: CAST( unsigned char ); break;
case IM_BANDFMT_SHORT: CAST( signed short ); break;
case IM_BANDFMT_USHORT: CAST( unsigned short ); break;
case IM_BANDFMT_INT: CAST( signed int ); break;
case IM_BANDFMT_UINT: CAST( unsigned int ); break;
default:
error_exit( "make_pixel: internal error" );
}
return( q );
return( im__arith_binary( "im_eorimage",
in1, in2, out,
bandfmt_bool,
(im_wrapmany_fn) eor_buffer, NULL ) );
}
int
@ -594,8 +460,7 @@ shiftleft_buffer( PEL *p, PEL *q, int len, IMAGE *in, int n )
case IM_BANDFMT_INT: SHIFTL( signed int ); break;
default:
error_exit( "im_shiftleft: internal error" );
/*NOTREACHED*/
g_assert( 0 );
}
}
@ -641,8 +506,7 @@ shiftright_buffer( PEL *p, PEL *q, int len, IMAGE *in, int n )
case IM_BANDFMT_INT: SHIFTR( signed int ); break;
default:
error_exit( "im_shiftright: internal error" );
/*NOTREACHED*/
g_assert( 0 );
}
}

View File

@ -283,8 +283,10 @@ png2vips( Read *read, int header_only )
/* Expand <8 bit images to full bytes.
*/
if( read->pInfo->bit_depth < 8 )
if( read->pInfo->bit_depth < 8 ) {
png_set_packing( read->pPng );
png_set_shift( read->pPng, 2 );
}
/* If we're an INTEL byte order machine and this is 16bits, we need
* to swap bytes.

View File

@ -131,9 +131,10 @@ char *im__gslist_gvalue_get( const GSList *list );
void im__buffer_init( void );
int im__cast_and_call( IMAGE *in1, IMAGE *in2, IMAGE *out,
int im__arith_binary( const char *name,
IMAGE *in1, IMAGE *in2, IMAGE *out,
int format_table[10],
im_wrapmany_fn fn, void *a );
VipsBandFmt im__format_common( IMAGE *in1, IMAGE *in2 );
int im__math( const char *name, IMAGE *in, IMAGE *out, im_wrapone_fn gen );
int im__value( IMAGE *im, double *value );
typedef int (*im__wrapscan_fn)( void *p, int n, void *seq, void *a, void *b );