This commit is contained in:
John Cupitt 2009-08-27 13:07:58 +00:00
parent 876a7ff2af
commit f0bbbbaf77
6 changed files with 141 additions and 85 deletions

View File

@ -22,7 +22,8 @@
- matlab load handles column-major and plane-separated images (thanks Mikhail) - matlab load handles column-major and plane-separated images (thanks Mikhail)
- JPEG save allows "none" for profile, meaning don't attach a profile - JPEG save allows "none" for profile, meaning don't attach a profile
- saner, simpler, faster typecasting for im_add(), im_subtract(), - saner, simpler, faster typecasting for im_add(), im_subtract(),
im_multiply(), im_divide() im_multiply(), im_divide(), im_remainder()
- im_remainder() has a float result for float types
- im_measure() allows sel == NULL, meaning all patches - im_measure() allows sel == NULL, meaning all patches
25/3/09 started 7.18.0 25/3/09 started 7.18.0

30
README
View File

@ -9,24 +9,14 @@ colour. There's a GUI as well, see the VIPS website:
There are packages for most linuxes and OS X. There is a pre-compiled windows There are packages for most linuxes and OS X. There is a pre-compiled windows
binary on the vips website. binary on the vips website.
Getting VIPS from SVN
=====================
Enter:
svn co https://vips.svn.sourceforge.net/svnroot/vips/vips7
Building VIPS from source Building VIPS from source
========================= =========================
In the VIPS directory, you should just be able to do: In the VIPS directory, you should just be able to do:
user% ./configure $ ./configure
user% make $ make
$ sudo make install
then as root:
root% make install
By default this will install files to /usr/local. By default this will install files to /usr/local.
@ -49,6 +39,20 @@ There are packages in macports.
http://www.macports.org http://www.macports.org
Building VIPS from SVN
----------------------
Checkout the latest sources with:
svn co https://vips.svn.sourceforge.net/svnroot/vips/vips7
Then:
$ ./bootstrap.sh
$ CFLAGS="-g -Wall" CXXFLAGS="-g -Wall" ./configure --prefix=/home/john/vips --enable-gtk-doc
$ make
$ make install
Dependencies Dependencies
============ ============

View File

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

View File

@ -11,6 +11,9 @@
* - oop, broken for _vec case :-( * - oop, broken for _vec case :-(
* 14/5/08 * 14/5/08
* - better /0 test * - better /0 test
* 27/8/08
* - revise upcasting system
* - add gtkdoc comments
*/ */
/* /*
@ -56,7 +59,9 @@
#include <dmalloc.h> #include <dmalloc.h>
#endif /*WITH_DMALLOC*/ #endif /*WITH_DMALLOC*/
#define RLOOP( IN, OUT ) { \ /* Integer remainder-after-division.
*/
#define ILOOP( IN, OUT ) { \
IN *p1 = (IN *) in[0]; \ IN *p1 = (IN *) in[0]; \
IN *p2 = (IN *) in[1]; \ IN *p2 = (IN *) in[1]; \
OUT *q = (OUT *) out; \ OUT *q = (OUT *) out; \
@ -68,19 +73,21 @@
q[x] = -1; \ q[x] = -1; \
} }
#define CLOOP( IN ) { \ /* Float remainder-after-division.
*/
#define FLOOP( IN, OUT ) { \
IN *p1 = (IN *) in[0]; \ IN *p1 = (IN *) in[0]; \
IN *p2 = (IN *) in[1]; \ IN *p2 = (IN *) in[1]; \
signed int *q = (signed int *) out; \ OUT *q = (OUT *) out; \
\ \
for( x = 0; x < sz; x++ ) { \ for( x = 0; x < sz; x++ ) { \
if( p2[0] ) \ double a = p1[x]; \
q[x] = (int) p1[0] % (int) p2[0]; \ double b = p2[x]; \
\
if( b ) \
q[x] = a - b * floor (a / b); \
else \ else \
q[x] = -1; \ q[x] = -1; \
\
p1 += 2; \
p2 += 2; \
} \ } \
} }
@ -91,16 +98,14 @@ remainder_buffer( PEL **in, PEL *out, int width, IMAGE *im )
int sz = width * im->Bands; int sz = width * im->Bands;
switch( im->BandFmt ) { switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: RLOOP( signed char, signed char ); break; case IM_BANDFMT_CHAR: ILOOP( signed char, signed char ); break;
case IM_BANDFMT_UCHAR: RLOOP( unsigned char, unsigned char ); break; case IM_BANDFMT_UCHAR: ILOOP( unsigned char, unsigned char ); break;
case IM_BANDFMT_SHORT: RLOOP( signed short, signed short ); break; case IM_BANDFMT_SHORT: ILOOP( signed short, signed short ); break;
case IM_BANDFMT_USHORT: RLOOP( unsigned short, unsigned short ); break; case IM_BANDFMT_USHORT: ILOOP( unsigned short, unsigned short ); break;
case IM_BANDFMT_INT: RLOOP( signed int, signed int ); break; case IM_BANDFMT_INT: ILOOP( signed int, signed int ); break;
case IM_BANDFMT_UINT: RLOOP( unsigned int, unsigned int ); break; case IM_BANDFMT_UINT: ILOOP( unsigned int, unsigned int ); break;
case IM_BANDFMT_FLOAT: RLOOP( float, signed int ); break; case IM_BANDFMT_FLOAT: FLOOP( float, float ); break;
case IM_BANDFMT_COMPLEX:CLOOP( float ); break; case IM_BANDFMT_DOUBLE: FLOOP( double, double ); break;
case IM_BANDFMT_DOUBLE: RLOOP( double, signed int ); break;
case IM_BANDFMT_DPCOMPLEX: CLOOP( double ); break;
default: default:
assert( 0 ); assert( 0 );
@ -125,18 +130,33 @@ remainder_buffer( PEL **in, PEL *out, int width, IMAGE *im )
*/ */
static int bandfmt_remainder[10] = { static int bandfmt_remainder[10] = {
/* UC C US S UI I F X D DX */ /* UC C US S UI I F X D DX */
UC, C, US, S, UI, I, I, I, I, I UC, C, US, S, UI, I, F, X, D, DX
}; };
/* /**
.B im_remainder(3) * im_remainder:
calculates the remainder after integer division of two images. The output * @in1: input #IMAGE 1
type is the same as the type of * @in2: input #IMAGE 2
.B in1 * @out: output #IMAGE
unless *
.B in1 * This operation calculates @in1 % @in2 (remainder after division) and writes
is float or complex, in which * the result to @out. The images must be the same size. They may have any
case the output type is signed integer. * non-complex format. For float types, im_remainder() calculates a - b *
* floor (a / b).
*
* If the number of bands differs, one of the images
* must have one band. In this case, an n-band image is formed from the
* one-band image by joining n copies of the one-band image together, and then
* the two n-band images are operated upon.
*
* The two input images are cast up to the smallest common type (see table
* Smallest common format in
* <link linkend="VIPS-arithmetic">arithmetic</link>), and that format is the
* result type.
*
* See also: im_remainderconst(), im_divide().
*
* Returns: 0 on success, -1 on error
*/ */
int int
im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out ) im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out )
@ -145,7 +165,9 @@ im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out )
im_pincheck( in2 ) || im_pincheck( in2 ) ||
im_check_bands_1orn( "im_remainder", in1, in2 ) || im_check_bands_1orn( "im_remainder", in1, in2 ) ||
im_check_uncoded( "im_remainder", in1 ) || im_check_uncoded( "im_remainder", in1 ) ||
im_check_uncoded( "im_remainder", in2 ) ) im_check_uncoded( "im_remainder", in2 ) ||
im_check_noncomplex( "im_remainder", in1 ) ||
im_check_noncomplex( "im_remainder", in2 ) )
return( -1 ); return( -1 );
if( im_cp_descv( out, in1, in2, NULL ) ) if( im_cp_descv( out, in1, in2, NULL ) )
@ -155,8 +177,7 @@ im_remainder( IMAGE *in1, IMAGE *in2, IMAGE *out )
*/ */
out->Bands = IM_MAX( in1->Bands, in2->Bands ); out->Bands = IM_MAX( in1->Bands, in2->Bands );
/* What output type will we write? Same as LHS type, except float /* What output type will we write? Same as LHS type.
* and double become signed int.
*/ */
out->BandFmt = bandfmt_remainder[im__format_common( in1, in2 )]; out->BandFmt = bandfmt_remainder[im__format_common( in1, in2 )];
out->Bbits = im_bits_of_fmt( out->BandFmt ); out->Bbits = im_bits_of_fmt( out->BandFmt );
@ -181,7 +202,9 @@ typedef struct _Remainderconst {
int *c; int *c;
} Remainderconst; } Remainderconst;
#define const1_loop(TYPE) {\ /* Integer remainder-after-divide.
*/
#define ICONST1LOOP( TYPE ) { \
TYPE *p = (TYPE *) in; \ TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \ TYPE *q = (TYPE *) out; \
\ \
@ -198,19 +221,19 @@ remainderconst1_buffer( PEL *in, PEL *out, int width, Remainderconst *rc )
int x; int x;
switch( im->BandFmt ) { switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: const1_loop( signed char ); break; case IM_BANDFMT_CHAR: ICONST1LOOP( signed char ); break;
case IM_BANDFMT_UCHAR: const1_loop( unsigned char ); break; case IM_BANDFMT_UCHAR: ICONST1LOOP( unsigned char ); break;
case IM_BANDFMT_SHORT: const1_loop( signed short ); break; case IM_BANDFMT_SHORT: ICONST1LOOP( signed short ); break;
case IM_BANDFMT_USHORT: const1_loop( unsigned short ); break; case IM_BANDFMT_USHORT: ICONST1LOOP( unsigned short ); break;
case IM_BANDFMT_INT: const1_loop( signed int ); break; case IM_BANDFMT_INT: ICONST1LOOP( signed int ); break;
case IM_BANDFMT_UINT: const1_loop( unsigned int ); break; case IM_BANDFMT_UINT: ICONST1LOOP( unsigned int ); break;
default: default:
assert( 0 ); assert( 0 );
} }
} }
#define const_loop(TYPE) {\ #define ICONSTLOOP( TYPE ) { \
TYPE *p = (TYPE *) in; \ TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \ TYPE *q = (TYPE *) out; \
\ \
@ -228,18 +251,37 @@ remainderconst_buffer( PEL *in, PEL *out, int width, Remainderconst *rc )
int i, x, k; int i, x, k;
switch( im->BandFmt ) { switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: const_loop( signed char ); break; case IM_BANDFMT_CHAR: ICONSTLOOP( signed char ); break;
case IM_BANDFMT_UCHAR: const_loop( unsigned char ); break; case IM_BANDFMT_UCHAR: ICONSTLOOP( unsigned char ); break;
case IM_BANDFMT_SHORT: const_loop( signed short ); break; case IM_BANDFMT_SHORT: ICONSTLOOP( signed short ); break;
case IM_BANDFMT_USHORT: const_loop( unsigned short ); break; case IM_BANDFMT_USHORT: ICONSTLOOP( unsigned short ); break;
case IM_BANDFMT_INT: const_loop( signed int ); break; case IM_BANDFMT_INT: ICONSTLOOP( signed int ); break;
case IM_BANDFMT_UINT: const_loop( unsigned int ); break; case IM_BANDFMT_UINT: ICONSTLOOP( unsigned int ); break;
default: default:
assert( 0 ); assert( 0 );
} }
} }
/**
* im_remainderconst_vec:
* @in: input #IMAGE
* @out: output #IMAGE
* @n: number of elements in array
* @c: array of constants
*
* This operation calculates @in % @c (remainder after division by constant)
* and writes the result to @out. The image must be one of the integer types.
*
* If the array of constants has one element, that constant is used for each
* image band. If the array has more than one element, it must have the same
* number of elements as there are bands in the image, and one array element
* is used for each band.
*
* See also: im_remainder(), im_divide().
*
* Returns: 0 on success, -1 on error
*/
int int
im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c ) im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c )
{ {
@ -248,21 +290,15 @@ im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c )
/* Basic checks. /* Basic checks.
*/ */
if( im_piocheck( in, out ) ) if( im_piocheck( in, out ) ||
im_check_vector( "im_remainder", n, in ) ||
im_check_uncoded( "im_remainder", in ) ||
im_check_int( "im_remainder", in ) )
return( -1 ); return( -1 );
if( in->Coding != IM_CODING_NONE ) {
im_error( "im_remainderconst_vec", "%s", _( "not uncoded" ) );
return( -1 );
}
if( n != 1 && n != in->Bands ) {
im_error( "im_remainderconst_vec",
_( "not 1 or %d elements in vector" ), in->Bands );
return( -1 );
}
if( im_cp_desc( out, in ) ) if( im_cp_desc( out, in ) )
return( -1 ); return( -1 );
/* Make space for a little buffer. /* Take a copy of the parameters.
*/ */
if( !(rc = IM_NEW( out, Remainderconst )) || if( !(rc = IM_NEW( out, Remainderconst )) ||
!(rc->c = IM_ARRAY( out, n, int )) ) !(rc->c = IM_ARRAY( out, n, int )) )
@ -274,6 +310,10 @@ im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c )
/* Cast down to int ... we pass in double for consistency with /* Cast down to int ... we pass in double for consistency with
* the other _vec functions. * the other _vec functions.
*/ */
if( c[i] != (int) c[i] )
im_warn( "im_remainderconst_vec",
_( "float constant %g truncated to integer" ),
c[i] );
rc->c[i] = c[i]; rc->c[i] = c[i];
if( rc->c[i] == 0 ) { if( rc->c[i] == 0 ) {
@ -283,20 +323,6 @@ im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c )
} }
} }
/* What output type will we write? Same as input type, except float
* and double become signed int.
*/
if( im_isfloat( in ) || im_iscomplex( in ) ) {
IMAGE *t = im_open_local( out, "im_remainderconst:1", "p" );
out->BandFmt = IM_BANDFMT_INT;
out->Bbits = IM_BBITS_INT;
if( !t || im_clip2fmt( in, t, out->BandFmt ) )
return( -1 );
rc->in = in = t;
}
if( n == 1 ) { if( n == 1 ) {
if( im_wrapone( in, out, if( im_wrapone( in, out,
(im_wrapone_fn) remainderconst1_buffer, rc, NULL ) ) (im_wrapone_fn) remainderconst1_buffer, rc, NULL ) )
@ -311,6 +337,19 @@ im_remainderconst_vec( IMAGE *in, IMAGE *out, int n, double *c )
return( 0 ); return( 0 );
} }
/**
* im_remainderconst:
* @in: input #IMAGE
* @out: output #IMAGE
* @c: constant
*
* This operation calculates @in % @c (remainder after division by constant)
* and writes the result to @out. The image must be one of the integer types.
*
* See also: im_remainderconst_vec(), im_divide().
*
* Returns: 0 on success, -1 on error
*/
int int
im_remainderconst( IMAGE *in, IMAGE *out, double c ) im_remainderconst( IMAGE *in, IMAGE *out, double c )
{ {

View File

@ -140,6 +140,7 @@ int im_check_uncoded( const char *domain, IMAGE *im );
int im_check_bands_1orn( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_bands_1orn( const char *domain, IMAGE *im1, IMAGE *im2 );
int im_check_noncomplex( const char *domain, IMAGE *im ); int im_check_noncomplex( const char *domain, IMAGE *im );
int im_check_complex( const char *domain, IMAGE *im ); int im_check_complex( const char *domain, IMAGE *im );
int im_check_int( const char *domain, IMAGE *im );
int im_check_size( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_size( const char *domain, IMAGE *im1, IMAGE *im2 );
int im_check_bands( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_bands( const char *domain, IMAGE *im1, IMAGE *im2 );
int im_check_format( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_format( const char *domain, IMAGE *im1, IMAGE *im2 );

View File

@ -406,6 +406,17 @@ im_check_complex( const char *domain, IMAGE *im )
return( 0 ); return( 0 );
} }
int
im_check_int( const char *domain, IMAGE *im )
{
if( !im_isint( im ) ) {
im_error( domain, "%s", _( "image must be integer" ) );
return( -1 );
}
return( 0 );
}
int int
im_check_size( const char *domain, IMAGE *im1, IMAGE *im2 ) im_check_size( const char *domain, IMAGE *im1, IMAGE *im2 )
{ {