rewritten radiance load is much faster

the old rad code, from radiance.c, was using getc in a loop
This commit is contained in:
John Cupitt 2013-11-05 10:36:14 +00:00
parent b0f262091f
commit ae71229cf5
3 changed files with 146 additions and 76 deletions

View File

@ -13,6 +13,7 @@
- im_contrast_surface() deprecated: it was slower than calling conv a few - im_contrast_surface() deprecated: it was slower than calling conv a few
times times
- radiance load supports sequential read - radiance load supports sequential read
- rewritten radiance decode is much faster
18/10/13 started 7.36.3 18/10/13 started 7.36.3
- fix compiler warnings in ubuntu 13.10 - fix compiler warnings in ubuntu 13.10

1
TODO
View File

@ -1,3 +1,4 @@
- do conv and morph quickly as simple wrappers over the vips7 operations - do conv and morph quickly as simple wrappers over the vips7 operations
- add vips_gaussian_blur() with approx / int / float precision, maybe - add vips_gaussian_blur() with approx / int / float precision, maybe

View File

@ -10,6 +10,8 @@
* - tag RGB rad images as scRGB * - tag RGB rad images as scRGB
* 4/11/13 * 4/11/13
* - support sequential read * - support sequential read
* 5/11/13
* - rewritten read, now much faster
*/ */
/* /*
@ -582,96 +584,160 @@ char *buf;
#define MAXELEN 0x7fff /* maximum scanline length for encoding */ #define MAXELEN 0x7fff /* maximum scanline length for encoding */
#define MINRUN 4 /* minimum run length */ #define MINRUN 4 /* minimum run length */
#define BUFFER_SIZE (4096)
#define BUFFER_MARGIN (256)
static unsigned char buffer[BUFFER_SIZE + BUFFER_MARGIN];
static int buffer_length = 0;
static int buffer_position = 0;
static FILE *buffer_fp = NULL;
static void
buffer_init( FILE *fp )
{
buffer_length = 0;
buffer_position = 0;
buffer_fp = fp;
}
static int static int
oldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ buffer_need( int require )
register COLR *scanline;
int len;
register FILE *fp;
{ {
int rshift; int remaining;
register int i;
rshift = 0; g_assert( require < BUFFER_MARGIN );
while (len > 0) { remaining = buffer_length - buffer_position;
scanline[0][RED] = getc(fp); if( remaining < require ) {
scanline[0][GRN] = getc(fp); size_t len;
scanline[0][BLU] = getc(fp);
scanline[0][EXP] = getc(fp); memcpy( buffer, buffer + buffer_position, remaining );
if (feof(fp) || ferror(fp)) buffer_position = 0;
buffer_length = remaining;
len = fread( buffer + buffer_length, 1, BUFFER_SIZE,
buffer_fp );
buffer_length += len;
remaining = buffer_length - buffer_position;
if( remaining < require ) {
vips_error( "rad2vips", "%s", _( "end of file" ) );
return( -1 ); return( -1 );
if (scanline[0][RED] == 1 &&
scanline[0][GRN] == 1 &&
scanline[0][BLU] == 1) {
for (i = scanline[0][EXP] << rshift; i > 0; i--) {
copycolr(scanline[0], scanline[-1]);
scanline++;
len--;
}
rshift += 8;
} else {
scanline++;
len--;
rshift = 0;
} }
} }
return( 0 ); return( 0 );
} }
#define BUFFER_FETCH (buffer[buffer_position++])
#define BUFFER_PEEK (buffer[buffer_position])
/* Read a single scanlne, encoded in the old style.
*/
static int static int
freadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ scanline_read_old( COLR *scanline, int width )
register COLR *scanline;
int len;
register FILE *fp;
{ {
register int i, j; int rshift;
int code, val;
/* determine scanline type */ rshift = 0;
if ((len < MINELEN) | (len > MAXELEN))
return(oldreadcolrs(scanline, len, fp)); while( width > 0 ) {
if ((i = getc(fp)) == EOF) if( buffer_need( 4 ) )
return( -1 ); return( -1 );
if (i != 2) {
ungetc(i, fp); scanline[0][RED] = BUFFER_FETCH;
return(oldreadcolrs(scanline, len, fp)); scanline[0][GRN] = BUFFER_FETCH;
scanline[0][BLU] = BUFFER_FETCH;
scanline[0][EXP] = BUFFER_FETCH;
if( scanline[0][RED] == 1 &&
scanline[0][GRN] == 1 &&
scanline[0][BLU] == 1 ) {
int i;
for( i = scanline[0][EXP] << rshift; i > 0; i-- ) {
copycolr( scanline[0], scanline[-1] );
scanline += 1;
width -= 1;
} }
scanline[0][GRN] = getc(fp);
scanline[0][BLU] = getc(fp); rshift += 8;
if ((i = getc(fp)) == EOF)
return(-1);
if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) {
scanline[0][RED] = 2;
scanline[0][EXP] = i;
return(oldreadcolrs(scanline+1, len-1, fp));
} }
if ((scanline[0][BLU]<<8 | i) != len) else {
return(-1); /* length mismatch! */ scanline += 1;
/* read each component */ width -= 1;
for (i = 0; i < 4; i++) rshift = 0;
for (j = 0; j < len; ) { }
if ((code = getc(fp)) == EOF) }
return( 0 );
}
/* Read a single encoded scanline.
*/
static int
scanline_read( COLR *scanline, int width )
{
int i, j;
/* Detect old-style scanlines.
*/
if( width < MINELEN ||
width > MAXELEN )
return( scanline_read_old( scanline, width ) );
if( buffer_need( 4 ) )
return( -1 ); return( -1 );
if (code > 128) { /* run */
code &= 127; if( BUFFER_PEEK != 2 )
if ((val = getc(fp)) == EOF) return( scanline_read_old( scanline, width ) );
return -1;
if (j + code > len) scanline[0][RED] = BUFFER_FETCH;
return -1; /* overrun */ scanline[0][GRN] = BUFFER_FETCH;
while (code--) scanline[0][BLU] = BUFFER_FETCH;
scanline[j++][i] = val; scanline[0][EXP] = BUFFER_FETCH;
} else { /* non-run */ if( scanline[0][GRN] != 2 ||
if (j + code > len) scanline[0][BLU] & 128 )
return -1; /* overrun */ return( scanline_read_old( scanline + 1, width - 1 ) );
while (code--) {
if ((val = getc(fp)) == EOF) if( ((scanline[0][BLU] << 8) | scanline[0][EXP]) != width ) {
return -1; vips_error( "rad2vips", "%s", _( "scanline length mismatch" ) );
return( -1 );
}
for( i = 0; i < 4; i++ ) {
for( j = 0; j < width; ) {
int code, len;
gboolean run;
if( buffer_need( 2 ) )
return( -1 );
code = BUFFER_FETCH;
run = code > 128;
len = run ? code & 127 : code;
if( j + len > width ) {
vips_error( "rad2vips", "%s", _( "overrun" ) );
return( -1 );
}
if( run ) {
int val;
val = BUFFER_FETCH;
while( len-- )
scanline[j++][i] = val; scanline[j++][i] = val;
} }
else {
if( buffer_need( len ) )
return( -1 );
while( len-- )
scanline[j++][i] = BUFFER_FETCH;
} }
} }
}
return( 0 ); return( 0 );
} }
@ -834,6 +900,7 @@ read_new( const char *filename, VipsImage *out )
if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) ) if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) )
return( NULL ); return( NULL );
buffer_init( read->fin );
return( read ); return( read );
} }
@ -960,8 +1027,9 @@ rad2vips_generate( VipsRegion *or,
COLR *buf = (COLR *) COLR *buf = (COLR *)
VIPS_REGION_ADDR( or, 0, r->top + y ); VIPS_REGION_ADDR( or, 0, r->top + y );
if( freadcolrs( buf, or->im->Xsize, read->fin ) ) { if( scanline_read( buf, or->im->Xsize ) ) {
vips_error( "rad2vips", "%s", _( "read error" ) ); vips_error( "rad2vips",
_( "read error line %d" ), r->top + y );
return( -1 ); return( -1 );
} }
} }