This commit is contained in:
John Cupitt 2008-04-23 12:17:26 +00:00
parent 8bb073cc72
commit 288161e420
6 changed files with 128 additions and 94 deletions

View File

@ -10,6 +10,8 @@
- use meta to preserve resunit between tiff load and save - use meta to preserve resunit between tiff load and save
- small doc improvements - small doc improvements
- read and write CMYKA tiff (thanks Doron) - read and write CMYKA tiff (thanks Doron)
- performance improvements for morphology ops, esp. when zooming out
- oop, im_render() was broken for mask == NULL
25/1/08 started 7.14.0 25/1/08 started 7.14.0
- bump all version numbers for new stable - bump all version numbers for new stable

2
TODO
View File

@ -34,7 +34,7 @@ https://sourceforge.net/tracker/index.php?func=detail&aid=1836080&group_id=10005
how big should the table be for 16 bits? 256 times larger? too big! how big should the table be for 16 bits? 256 times larger? too big!
we really just need a LUUT for pow() with the right exponent, eg. 2.4 for we really just need a LUT for pow() with the right exponent, eg. 2.4 for
sRGBs, and one for 1/2.4 ... see what calcul_tables does: sRGBs, and one for 1/2.4 ... see what calcul_tables does:
table->t_r2Yr[i] = yo + a * pow( i * table->ristep / f + c, ga ); table->t_r2Yr[i] = yo + a * pow( i * table->ristep / f + c, ga );

View File

@ -13,6 +13,9 @@
* - adapted from im_shrink() * - adapted from im_shrink()
* 3/8/02 JC * 3/8/02 JC
* - fall back to im_copy() for x/y factors == 1 * - fall back to im_copy() for x/y factors == 1
* 21/4/08
* - don't fall back to pixel-wise shrinks for smalltile, it kills
* performance, just bring IM_MAX_WIDTH down instead
*/ */
/* /*
@ -57,7 +60,7 @@
/* Maximum width of input we ask for. /* Maximum width of input we ask for.
*/ */
#define IM_MAX_WIDTH (1000) #define IM_MAX_WIDTH (100)
/* Our main parameter struct. /* Our main parameter struct.
*/ */
@ -133,8 +136,7 @@ line_shrink_gen( REGION *or, void *seq, void *a, void *b )
return( 0 ); return( 0 );
} }
/* Fetch one pixel at a time ... good for very large shrinks, or for SMALLTILE /* Fetch one pixel at a time ... good for very large shrinks.
* pipes.
*/ */
static int static int
point_shrink_gen( REGION *or, void *seq, void *a, void *b ) point_shrink_gen( REGION *or, void *seq, void *a, void *b )
@ -193,7 +195,7 @@ im_subsample( IMAGE *in, IMAGE *out, int xshrink, int yshrink )
/* Check parameters. /* Check parameters.
*/ */
if( xshrink < 1 || yshrink < 1 ) { if( xshrink < 1 || yshrink < 1 ) {
im_errormsg( "im_subsample: factors should both be >= 1" ); im_error( "im_subsample", _( "factors should both be >= 1" ) );
return( -1 ); return( -1 );
} }
if( xshrink == 1 && yshrink == 1 ) if( xshrink == 1 && yshrink == 1 )
@ -210,7 +212,7 @@ im_subsample( IMAGE *in, IMAGE *out, int xshrink, int yshrink )
out->Xres = in->Xres / xshrink; out->Xres = in->Xres / xshrink;
out->Yres = in->Yres / yshrink; out->Yres = in->Yres / yshrink;
if( out->Xsize <= 0 || out->Ysize <= 0 ) { if( out->Xsize <= 0 || out->Ysize <= 0 ) {
im_errormsg( "im_subsample: image has shrunk to nothing" ); im_error( "im_subsample", _( "image has shrunk to nothing" ) );
return( -1 ); return( -1 );
} }
@ -228,11 +230,9 @@ im_subsample( IMAGE *in, IMAGE *out, int xshrink, int yshrink )
return( -1 ); return( -1 );
/* Generate! If this is a very large shrink, then it's /* Generate! If this is a very large shrink, then it's
* probably faster to do it a pixel at a time. If this is SMALLTILE, * probably faster to do it a pixel at a time.
* then it will hate long lines and we should always do 1 pixel at a
* time.
*/ */
if( in->dhint == IM_SMALLTILE || xshrink > 10 ) { if( xshrink > 10 ) {
if( im_generate( out, if( im_generate( out,
im_start_one, point_shrink_gen, im_stop_one, in, st ) ) im_start_one, point_shrink_gen, im_stop_one, in, st ) )
return( -1 ); return( -1 );

View File

@ -31,6 +31,8 @@
* 14/3/08 * 14/3/08
* - oop, still making fade threads even when not fading * - oop, still making fade threads even when not fading
* - more instrumenting * - more instrumenting
* 23/4/08
* - oop, broken for mask == NULL
*/ */
/* /*
@ -1198,7 +1200,9 @@ im_render_fade( IMAGE *in, IMAGE *out, IMAGE *mask,
} }
if( im_cp_desc( out, in ) ) if( im_cp_desc( out, in ) )
return( -1 ); return( -1 );
if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) || if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) )
return( -1 );
if( mask &&
im_demand_hint( mask, IM_SMALLTILE, in, NULL ) ) im_demand_hint( mask, IM_SMALLTILE, in, NULL ) )
return( -1 ); return( -1 );

View File

@ -20,6 +20,9 @@
* - now uses im_embed() with edge stretching on the input, not * - now uses im_embed() with edge stretching on the input, not
* the output * the output
* - sets Xoffset / Yoffset * - sets Xoffset / Yoffset
* 21/4/08
* - only rebuild the buffer offsets if bpl changes
* - small cleanups
*/ */
/* /*
@ -48,6 +51,10 @@
*/ */
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
@ -71,6 +78,7 @@ typedef struct {
int ss; /* ... and number we check for set */ int ss; /* ... and number we check for set */
int *coff; /* Offsets we check for clear */ int *coff; /* Offsets we check for clear */
int cs; /* ... and number we check for clear */ int cs; /* ... and number we check for clear */
int last_bpl; /* Avoid recalcing offsets, if we can */
} SeqInfo; } SeqInfo;
/* Stop function. /* Stop function.
@ -105,6 +113,7 @@ dilate_start( IMAGE *out, void *a, void *b )
seq->ss = 0; seq->ss = 0;
seq->coff = NULL; seq->coff = NULL;
seq->cs = 0; seq->cs = 0;
seq->last_bpl = -1;
/* Attach region and arrays. /* Attach region and arrays.
*/ */
@ -141,7 +150,7 @@ dilate_gen( REGION *or, void *vseq, void *a, void *b )
int *t; int *t;
int x, y; int x, y;
int found, i; int result, i;
/* Prepare the section of the input image we need. A little larger /* Prepare the section of the input image we need. A little larger
* than the section of the output image we are producing. * than the section of the output image we are producing.
@ -152,8 +161,16 @@ dilate_gen( REGION *or, void *vseq, void *a, void *b )
if( im_prepare( ir, &s ) ) if( im_prepare( ir, &s ) )
return( -1 ); return( -1 );
/* Scan mask, building offsets we check when processing. #ifdef DEBUG
printf( "erode_gen: preparing %dx%d pixels\n", s.width, s.height );
#endif /*DEBUG*/
/* Scan mask, building offsets we check when processing. Only do this
* if the bpl has changed since the previous im_prepare().
*/ */
if( seq->last_bpl != IM_REGION_LSKIP( ir ) ) {
seq->last_bpl = IM_REGION_LSKIP( ir );
seq->ss = 0; seq->ss = 0;
seq->cs = 0; seq->cs = 0;
for( t = msk->coeff, y = 0; y < msk->ysize; y++ ) for( t = msk->coeff, y = 0; y < msk->ysize; y++ )
@ -161,7 +178,8 @@ dilate_gen( REGION *or, void *vseq, void *a, void *b )
switch( *t ) { switch( *t ) {
case 255: case 255:
soff[seq->ss++] = soff[seq->ss++] =
IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir,
x + le, y + to ) -
IM_REGION_ADDR( ir, le, to ); IM_REGION_ADDR( ir, le, to );
break; break;
@ -170,15 +188,19 @@ dilate_gen( REGION *or, void *vseq, void *a, void *b )
case 0: case 0:
coff[seq->cs++] = coff[seq->cs++] =
IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir,
x + le, y + to ) -
IM_REGION_ADDR( ir, le, to ); IM_REGION_ADDR( ir, le, to );
break; break;
default: default:
im_errormsg( "im_dilate: bad mask element " im_error( "im_dilate",
"(%d should be 0, 128 or 255)", *t ); _( "bad mask element (%d "
"should be 0, 128 or 255)" ),
*t );
return( -1 ); return( -1 );
} }
}
/* Dilate! /* Dilate!
*/ */
@ -191,35 +213,28 @@ dilate_gen( REGION *or, void *vseq, void *a, void *b )
for( x = 0; x < sz; x++, q++, p++ ) { for( x = 0; x < sz; x++, q++, p++ ) {
/* Search for a hit on the set list. /* Search for a hit on the set list.
*/ */
found = 0; result = 0;
for( i = 0; i < seq->ss; i++ ) for( i = 0; i < seq->ss; i++ )
if( p[soff[i]] ) { if( p[soff[i]] ) {
/* Found a match! Set this output /* Found a match!
* pixel and continue.
*/ */
*q = 255; result = 255;
found = 1;
break; break;
} }
/* No set pixels ... search for a hit in the clear /* No set pixels ... search for a hit in the clear
* pixels. * pixels.
*/ */
if( !found ) if( !result )
for( i = 0; i < seq->cs; i++ ) for( i = 0; i < seq->cs; i++ )
if( !p[coff[i]] ) { if( !p[coff[i]] ) {
/* Found a match! Set this /* Found a match!
* output pixel and continue.
*/ */
*q = 255; result = 255;
found = 1;
break; break;
} }
if( !found ) *q = result;
/* All matches failed. Clear this output pixel.
*/
*q = 0;
} }
} }
@ -238,7 +253,7 @@ im_dilate_raw( IMAGE *in, IMAGE *out, INTMASK *m )
*/ */
if( m->xsize < 1 || !(m->xsize & 0x1) || if( m->xsize < 1 || !(m->xsize & 0x1) ||
m->ysize < 1 || !(m->ysize & 0x1) ) { m->ysize < 1 || !(m->ysize & 0x1) ) {
im_errormsg( "im_dilate: mask size not odd" ); im_error( "im_dilate", _( "mask size not odd" ) );
return( -1 ); return( -1 );
} }
@ -248,7 +263,7 @@ im_dilate_raw( IMAGE *in, IMAGE *out, INTMASK *m )
return( -1 ); return( -1 );
if( in->Coding != IM_CODING_NONE || in->Bbits != 8 || if( in->Coding != IM_CODING_NONE || in->Bbits != 8 ||
in->BandFmt != IM_BANDFMT_UCHAR ) { in->BandFmt != IM_BANDFMT_UCHAR ) {
im_errormsg( "im_dilate: uchar uncoded only" ); im_error( "im_dilate", _( "uchar uncoded only" ) );
return( -1 ); return( -1 );
} }
if( im_cp_desc( out, in ) ) if( im_cp_desc( out, in ) )
@ -262,7 +277,7 @@ im_dilate_raw( IMAGE *in, IMAGE *out, INTMASK *m )
out->Xsize -= m->xsize - 1; out->Xsize -= m->xsize - 1;
out->Ysize -= m->ysize - 1; out->Ysize -= m->ysize - 1;
if( out->Xsize <= 0 || out->Ysize <= 0 ) { if( out->Xsize <= 0 || out->Ysize <= 0 ) {
im_errormsg( "im_dilate: image too small for mask" ); im_error( "im_dilate", _( "image too small for mask" ) );
return( -1 ); return( -1 );
} }

View File

@ -20,6 +20,9 @@
* - now uses im_embed() with edge stretching on the input, not * - now uses im_embed() with edge stretching on the input, not
* the output * the output
* - sets Xoffset / Yoffset * - sets Xoffset / Yoffset
* 21/4/08
* - only rebuild the buffer offsets if bpl changes
* - small cleanups
*/ */
/* /*
@ -48,6 +51,10 @@
*/ */
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
@ -71,6 +78,7 @@ typedef struct {
int ss; /* ... and number we check for set */ int ss; /* ... and number we check for set */
int *coff; /* Offsets we check for clear */ int *coff; /* Offsets we check for clear */
int cs; /* ... and number we check for clear */ int cs; /* ... and number we check for clear */
int last_bpl; /* Avoid recalcing offsets, if we can */
} SeqInfo; } SeqInfo;
/* Stop function. /* Stop function.
@ -105,6 +113,7 @@ erode_start( IMAGE *out, void *a, void *b )
seq->ss = 0; seq->ss = 0;
seq->coff = NULL; seq->coff = NULL;
seq->cs = 0; seq->cs = 0;
seq->last_bpl = -1;
/* Attach region and arrays. /* Attach region and arrays.
*/ */
@ -141,7 +150,7 @@ erode_gen( REGION *or, void *vseq, void *a, void *b )
int *t; int *t;
int x, y; int x, y;
int found, i; int result, i;
/* Prepare the section of the input image we need. A little larger /* Prepare the section of the input image we need. A little larger
* than the section of the output image we are producing. * than the section of the output image we are producing.
@ -152,8 +161,16 @@ erode_gen( REGION *or, void *vseq, void *a, void *b )
if( im_prepare( ir, &s ) ) if( im_prepare( ir, &s ) )
return( -1 ); return( -1 );
/* Scan mask, building offsets we check when processing. #ifdef DEBUG
printf( "erode_gen: preparing %dx%d pixels\n", s.width, s.height );
#endif /*DEBUG*/
/* Scan mask, building offsets we check when processing. Only do this
* if the bpl has changed since the previous im_prepare().
*/ */
if( seq->last_bpl != IM_REGION_LSKIP( ir ) ) {
seq->last_bpl = IM_REGION_LSKIP( ir );
seq->ss = 0; seq->ss = 0;
seq->cs = 0; seq->cs = 0;
for( t = msk->coeff, y = 0; y < msk->ysize; y++ ) for( t = msk->coeff, y = 0; y < msk->ysize; y++ )
@ -161,7 +178,8 @@ erode_gen( REGION *or, void *vseq, void *a, void *b )
switch( *t ) { switch( *t ) {
case 255: case 255:
soff[seq->ss++] = soff[seq->ss++] =
IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir,
x + le, y + to ) -
IM_REGION_ADDR( ir, le, to ); IM_REGION_ADDR( ir, le, to );
break; break;
@ -170,15 +188,19 @@ erode_gen( REGION *or, void *vseq, void *a, void *b )
case 0: case 0:
coff[seq->cs++] = coff[seq->cs++] =
IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir,
x + le, y + to ) -
IM_REGION_ADDR( ir, le, to ); IM_REGION_ADDR( ir, le, to );
break; break;
default: default:
im_errormsg( "im_erode: bad mask element " im_error( "im_erode",
"(%d should be 0, 128 or 255)", *t ); _( "bad mask element (%d "
"should be 0, 128 or 255)" ),
*t );
return( -1 ); return( -1 );
} }
}
/* Erode! /* Erode!
*/ */
@ -191,34 +213,25 @@ erode_gen( REGION *or, void *vseq, void *a, void *b )
for( x = 0; x < sz; x++, q++, p++ ) { for( x = 0; x < sz; x++, q++, p++ ) {
/* Check all set pixels are set. /* Check all set pixels are set.
*/ */
found = 0; result = 255;
for( i = 0; i < seq->ss; i++ ) for( i = 0; i < seq->ss; i++ )
if( !p[soff[i]] ) { if( !p[soff[i]] ) {
/* Found a mismatch! Clear this output /* Found a mismatch!
* pixel and continue.
*/ */
*q = 0; result = 0;
found = 1;
break; break;
} }
/* Check all clear pixels are clear. /* Check all clear pixels are clear.
*/ */
if( !found ) if( result )
for( i = 0; i < seq->cs; i++ ) for( i = 0; i < seq->cs; i++ )
if( p[coff[i]] ) { if( p[coff[i]] ) {
/* Found a mismatch! Clear this result = 0;
* output pixel and continue.
*/
*q = 0;
found = 1;
break; break;
} }
if( !found ) *q = result;
/* No mismatches found - set output pixel.
*/
*q = 255;
} }
} }
@ -236,7 +249,7 @@ im_erode_raw( IMAGE *in, IMAGE *out, INTMASK *m )
*/ */
if( m->xsize < 1 || !(m->xsize & 0x1) || if( m->xsize < 1 || !(m->xsize & 0x1) ||
m->ysize < 1 || !(m->ysize & 0x1) ) { m->ysize < 1 || !(m->ysize & 0x1) ) {
im_errormsg( "im_erode: mask size not odd" ); im_error( "im_erode", _( "mask size not odd" ) );
return( -1 ); return( -1 );
} }
@ -246,7 +259,7 @@ im_erode_raw( IMAGE *in, IMAGE *out, INTMASK *m )
return( -1 ); return( -1 );
if( in->Coding != IM_CODING_NONE || in->Bbits != 8 || if( in->Coding != IM_CODING_NONE || in->Bbits != 8 ||
in->BandFmt != IM_BANDFMT_UCHAR ) { in->BandFmt != IM_BANDFMT_UCHAR ) {
im_errormsg( "im_erode: 1-band uchar uncoded only" ); im_error( "im_erode", _( "1-band uchar uncoded only" ) );
return( -1 ); return( -1 );
} }
if( im_cp_desc( out, in ) ) if( im_cp_desc( out, in ) )
@ -260,7 +273,7 @@ im_erode_raw( IMAGE *in, IMAGE *out, INTMASK *m )
out->Xsize -= m->xsize - 1; out->Xsize -= m->xsize - 1;
out->Ysize -= m->ysize - 1; out->Ysize -= m->ysize - 1;
if( out->Xsize <= 0 || out->Ysize <= 0 ) { if( out->Xsize <= 0 || out->Ysize <= 0 ) {
im_errormsg( "im_erode: image too small for mask" ); im_error( "im_erode", _( "image too small for mask" ) );
return( -1 ); return( -1 );
} }