revise streamo, ppm save uses it

streamo is simpler, and has a fast putc.
This commit is contained in:
John Cupitt 2019-11-13 17:50:02 +00:00
parent 7aec350f1c
commit 3bbadc0198
5 changed files with 101 additions and 85 deletions

View File

@ -149,8 +149,8 @@ int vips__ppm_isppm( const char *filename );
VipsForeignFlags vips__ppm_flags( const char *filename );
extern const char *vips__ppm_suffs[];
int vips__ppm_save( VipsImage *in, const char *filename,
gboolean ascii, gboolean squash );
int vips__ppm_save_stream( VipsImage *in, VipsStreamo *streamo,
gboolean ascii, gboolean squash );
int vips__rad_israd( VipsStreami *streami );
int vips__rad_header( VipsStreami *streami, VipsImage *out );

View File

@ -36,6 +36,8 @@
* linebreaks
* 29/7/19 Kyle-Kyle
* - fix a loop with malformed ppm
* 13/11/19
* - ppm save redone with streams
*/
/*
@ -555,22 +557,22 @@ typedef int (*write_fn)( struct _Write *write, VipsPel *p );
*/
typedef struct _Write {
VipsImage *in;
FILE *fp;
char *name;
VipsStreamo *streamo;
write_fn fn;
} Write;
static void
write_destroy( Write *write )
{
VIPS_FREEF( fclose, write->fp );
VIPS_FREE( write->name );
if( write->streamo )
vips_streamo_finish( write->streamo );
VIPS_UNREF( write->streamo );
vips_free( write );
}
static Write *
write_new( VipsImage *in, const char *name )
write_new( VipsImage *in, VipsStreamo *streamo )
{
Write *write;
@ -578,14 +580,10 @@ write_new( VipsImage *in, const char *name )
return( NULL );
write->in = in;
write->name = vips_strdup( NULL, name );
write->fp = vips__file_open_write( name, FALSE );
write->streamo = streamo;
g_object_ref( streamo );
write->fn = NULL;
if( !write->name || !write->fp ) {
write_destroy( write );
return( NULL );
}
return( write );
}
@ -599,17 +597,17 @@ write_ppm_line_ascii( Write *write, VipsPel *p )
for( k = 0; k < write->in->Bands; k++ ) {
switch( write->in->BandFmt ) {
case VIPS_FORMAT_UCHAR:
fprintf( write->fp,
vips_streamo_writef( write->streamo,
"%d ", p[k] );
break;
case VIPS_FORMAT_USHORT:
fprintf( write->fp,
vips_streamo_writef( write->streamo,
"%d ", ((unsigned short *) p)[k] );
break;
case VIPS_FORMAT_UINT:
fprintf( write->fp,
vips_streamo_writef( write->streamo,
"%d ", ((unsigned int *) p)[k] );
break;
@ -621,11 +619,8 @@ write_ppm_line_ascii( Write *write, VipsPel *p )
p += sk;
}
if( !fprintf( write->fp, "\n" ) ) {
vips_error_system( errno, "vips2ppm",
"%s", _( "write error" ) );
if( vips_streamo_writef( write->streamo, "\n" ) )
return( -1 );
}
return( 0 );
}
@ -636,13 +631,10 @@ write_ppm_line_ascii_squash( Write *write, VipsPel *p )
int x;
for( x = 0; x < write->in->Xsize; x++ )
fprintf( write->fp, "%d ", p[x] ? 0 : 1 );
vips_streamo_writef( write->streamo, "%d ", p[x] ? 0 : 1 );
if( !fprintf( write->fp, "\n" ) ) {
vips_error_system( errno, "vips2ppm",
"%s", _( "write error" ) );
if( vips_streamo_writef( write->streamo, "\n" ) )
return( -1 );
}
return( 0 );
}
@ -650,8 +642,8 @@ write_ppm_line_ascii_squash( Write *write, VipsPel *p )
static int
write_ppm_line_binary( Write *write, VipsPel *p )
{
if( vips__file_write( p, VIPS_IMAGE_SIZEOF_LINE( write->in ), 1,
write->fp ) )
if( vips_streamo_write( write->streamo,
p, VIPS_IMAGE_SIZEOF_LINE( write->in ) ) )
return( -1 );
return( 0 );
@ -672,11 +664,8 @@ write_ppm_line_binary_squash( Write *write, VipsPel *p )
bits |= p[x] ? 0 : 1;
if( n_bits == 8 ) {
if( fputc( bits, write->fp ) == EOF ) {
vips_error_system( errno, "vips2ppm",
"%s", _( "write error" ) );
if( VIPS_STREAMO_PUTC( write->streamo, bits ) )
return( -1 );
}
bits = 0;
n_bits = 0;
@ -685,13 +674,9 @@ write_ppm_line_binary_squash( Write *write, VipsPel *p )
/* Flush any remaining bits in this line.
*/
if( n_bits ) {
if( fputc( bits, write->fp ) == EOF ) {
vips_error_system( errno, "vips2ppm",
"%s", _( "write error" ) );
return( -1 );
}
}
if( n_bits &&
VIPS_STREAMO_PUTC( write->streamo, bits ) )
return( -1 );
return( 0 );
}
@ -740,23 +725,27 @@ write_ppm( Write *write, gboolean ascii, gboolean squash )
else
g_assert_not_reached();
fprintf( write->fp, "%s\n", magic );
vips_streamo_writef( write->streamo, "%s\n", magic );
time( &timebuf );
fprintf( write->fp, "#vips2ppm - %s\n", ctime( &timebuf ) );
fprintf( write->fp, "%d %d\n", in->Xsize, in->Ysize );
vips_streamo_writef( write->streamo,
"#vips2ppm - %s\n", ctime( &timebuf ) );
vips_streamo_writef( write->streamo, "%d %d\n", in->Xsize, in->Ysize );
if( !squash )
switch( in->BandFmt ) {
case VIPS_FORMAT_UCHAR:
fprintf( write->fp, "%d\n", UCHAR_MAX );
vips_streamo_writef( write->streamo,
"%d\n", UCHAR_MAX );
break;
case VIPS_FORMAT_USHORT:
fprintf( write->fp, "%d\n", USHRT_MAX );
vips_streamo_writef( write->streamo,
"%d\n", USHRT_MAX );
break;
case VIPS_FORMAT_UINT:
fprintf( write->fp, "%d\n", UINT_MAX );
vips_streamo_writef( write->streamo,
"%d\n", UINT_MAX );
break;
case VIPS_FORMAT_FLOAT:
@ -767,7 +756,8 @@ write_ppm( Write *write, gboolean ascii, gboolean squash )
scale = 1;
if( !vips_amiMSBfirst() )
scale *= -1;
fprintf( write->fp, "%g\n", scale );
vips_streamo_writef( write->streamo,
"%g\n", scale );
}
break;
@ -791,7 +781,7 @@ write_ppm( Write *write, gboolean ascii, gboolean squash )
}
int
vips__ppm_save( VipsImage *in, const char *filename,
vips__ppm_save_stream( VipsImage *in, VipsStreamo *streamo,
gboolean ascii, gboolean squash )
{
Write *write;
@ -820,7 +810,7 @@ vips__ppm_save( VipsImage *in, const char *filename,
squash = FALSE;
}
if( !(write = write_new( in, filename )) )
if( !(write = write_new( in, streamo )) )
return( -1 );
if( write_ppm( write, ascii, squash ) ) {

View File

@ -70,13 +70,20 @@ vips_foreign_save_ppm_build( VipsObject *object )
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object;
VipsStreamo *streamo;
if( VIPS_OBJECT_CLASS( vips_foreign_save_ppm_parent_class )->
build( object ) )
return( -1 );
if( vips__ppm_save( save->ready, ppm->filename,
ppm->ascii, ppm->squash ) )
if( !(streamo = vips_streamo_new_to_filename( ppm->filename )) )
return( -1 );
if( vips__ppm_save_stream( save->ready, streamo,
ppm->ascii, ppm->squash ) ) {
VIPS_UNREF( streamo );
return( -1 );
}
VIPS_UNREF( streamo );
return( 0 );
}

View File

@ -365,11 +365,11 @@ typedef struct _VipsStreamo {
*/
VipsBlob *blob;
/* Buffer small writes here.
/* Buffer small writes here. write_point is the index of the next
* character to write.
*/
unsigned char output_buffer[VIPS_STREAMO_BUFFER_SIZE];
unsigned char *write_point;
int bytes_remaining;
int write_point;
} VipsStreamo;
@ -395,6 +395,14 @@ VipsStreamo *vips_streamo_new_to_memory( void );
int vips_streamo_write( VipsStreamo *streamo, const void *data, size_t length );
void vips_streamo_finish( VipsStreamo *streamo );
int vips_streamo_putc( VipsStreamo *streamo, int ch );
#define VIPS_STREAMO_PUTC( S, C ) ( \
(S)->write_point <= VIPS_STREAMO_BUFFER_SIZE ? \
((S)->output_buffer[(S)->write_point++] = (C), 0) : \
vips_streamo_putc( (S), (C) ) \
)
int vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... )
__attribute__((format(printf, 2, 3)));

View File

@ -198,8 +198,7 @@ static void
vips_streamo_init( VipsStreamo *streamo )
{
streamo->blob = vips_blob_new( NULL, NULL, 0 );
streamo->bytes_remaining = VIPS_STREAMO_BUFFER_SIZE;
streamo->write_point = streamo->output_buffer;
streamo->write_point = 0;
}
/**
@ -323,18 +322,14 @@ vips_streamo_write_unbuffered( VipsStreamo *streamo,
static int
vips_streamo_flush( VipsStreamo *streamo )
{
int bytes_in_buffer =
VIPS_STREAMO_BUFFER_SIZE - streamo->bytes_remaining;
g_assert( streamo->write_point >= 0 );
g_assert( streamo->write_point <= VIPS_STREAMO_BUFFER_SIZE );
g_assert( bytes_in_buffer >= 0 );
g_assert( bytes_in_buffer <= VIPS_STREAMO_BUFFER_SIZE );
if( bytes_in_buffer > 0 ) {
if( streamo->write_point > 0 ) {
if( vips_streamo_write_unbuffered( streamo,
streamo->output_buffer, bytes_in_buffer ) )
streamo->output_buffer, streamo->write_point ) )
return( -1 );
streamo->bytes_remaining = VIPS_STREAMO_BUFFER_SIZE;
streamo->write_point = streamo->output_buffer;
streamo->write_point = 0;
}
return( 0 );
@ -355,27 +350,20 @@ vips_streamo_write( VipsStreamo *streamo, const void *buffer, size_t length )
{
VIPS_DEBUG_MSG( "vips_streamo_write: %zd bytes\n", length );
if( streamo->bytes_remaining >= length ) {
memcpy( streamo->write_point, buffer, length );
streamo->bytes_remaining -= length;
streamo->write_point += length;
if( length > VIPS_STREAMO_BUFFER_SIZE - streamo->write_point &&
vips_streamo_flush( streamo ) )
return( -1 );
if( length > VIPS_STREAMO_BUFFER_SIZE - streamo->write_point ) {
/* Still too large? Do an unbuffered write.
*/
if( vips_streamo_write_unbuffered( streamo, buffer, length ) )
return( -1 );
}
else {
if( vips_streamo_flush( streamo ) )
return( -1 );
if( streamo->bytes_remaining >= length ) {
memcpy( streamo->write_point, buffer, length );
streamo->bytes_remaining -= length;
streamo->write_point += length;
}
else
/* The buffer is empty and we still have too much
* data. Write directly.
*/
if( vips_streamo_write_unbuffered( streamo,
buffer, length ) )
return( -1 );
memcpy( streamo->output_buffer + streamo->write_point,
buffer, length );
streamo->write_point += length;
}
return( 0 );
@ -443,6 +431,30 @@ vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... )
return( result );
}
/**
* vips_streamo_putc:
* @streamo: output stream to operate on
* @ch: character to write
*
* Write a single character @ch to @streamo. See the macro VIPS_STREAMO_PUTC()
* for a faster way to do this.
*
* Returns: 0 on success, -1 on error.
*/
int
vips_streamo_putc( VipsStreamo *streamo, int ch )
{
VIPS_DEBUG_MSG( "vips_streamo_putc: %d\n", ch );
if( streamo->write_point > VIPS_STREAMO_BUFFER_SIZE &&
vips_streamo_flush( streamo ) )
return( -1 );
streamo->output_buffer[streamo->write_point++] = ch;
return( 0 );
}
/**
* vips_streamo_write_amp:
* @streamo: output stream to operate on
@ -497,8 +509,7 @@ vips_streamo_write_amp( VipsStreamo *streamo, const char *str )
return( -1 );
}
else {
if( !vips_streamo_write( streamo,
(guchar *) p, 1 ) )
if( !vips_streamo_putc( streamo, *p ) )
return( -1 );
}