move buf writers on top of dbuf

tiff and webp not moved
This commit is contained in:
John Cupitt 2017-02-28 13:40:34 +00:00
parent 40294bb85c
commit f2a178e98f
6 changed files with 196 additions and 167 deletions

22
TODO
View File

@ -1,25 +1,3 @@
- use VipsDbuf for tiffsave_buffer etc.
$ grep -l save_buffer *.c
dzsave.c
jpegsave.c
pngsave.c
radsave.c
tiffsave.c
webpsave.c
done png, jpg
tiff needs seek ... perhaps add this to dbuf?
dzsave uses gsf
rad and webp left to do
vips2jpeg term_destination() needs some kind of truncate call for dbuf
- verify xml data against master for vips save and dzsave

View File

@ -17,6 +17,8 @@
* readers
* 23/5/16
* - add buffer save functions
* 28/2/17
* - use dbuf for buffer output
*/
/*
@ -1172,9 +1174,7 @@ typedef struct {
char *filename;
FILE *fout;
char *buf;
size_t len;
size_t alloc;
VipsDbuf dbuf;
char format[256];
double expos;
@ -1189,7 +1189,7 @@ write_destroy( Write *write )
{
VIPS_FREE( write->filename );
VIPS_FREEF( fclose, write->fout );
VIPS_FREE( write->buf );
vips_dbuf_destroy( &write->dbuf );
vips_free( write );
}
@ -1208,9 +1208,7 @@ write_new( VipsImage *in )
write->filename = NULL;
write->fout = NULL;
write->buf = NULL;
write->len = 0;
write->alloc = 0;
vips_dbuf_init( &write->dbuf );
strcpy( write->format, COLRFMT );
write->expos = 1.0;
@ -1346,91 +1344,30 @@ vips__rad_save( VipsImage *in, const char *filename )
return( 0 );
}
static void
write_buf_grow( Write *write, size_t grow_len )
{
size_t new_len = write->len + grow_len;
if( new_len > write->alloc ) {
size_t proposed_alloc = (16 + write->alloc) * 3 / 2;
write->alloc = VIPS_MAX( proposed_alloc, new_len );
/* Our caller must free with g_free(), so we must use
* g_realloc().
*/
write->buf = g_realloc( write->buf, write->alloc );
VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n",
write->alloc );
}
}
static void
bprintf( Write *write, const char *fmt, ... )
{
int length;
char *write_start;
va_list ap;
/* Determine required size.
*/
va_start( ap, fmt );
length = vsnprintf( NULL, 0, fmt, ap );
va_end( ap );
write_buf_grow( write, length + 1 );
write_start = write->buf + write->len;
va_start( ap, fmt );
length = vsnprintf( write_start, length + 1, fmt, ap );
va_end( ap );
write->len += length;
g_assert( write->len <= write->alloc );
}
#define bputformat( write, s ) \
bprintf( write, "%s%s\n", FMTSTR, s )
#define bputexpos( write, ex ) \
bprintf( write, "%s%e\n", EXPOSSTR, ex )
#define bputcolcor( write, cc ) \
bprintf( write, "%s %f %f %f\n", \
COLCORSTR, (cc)[RED], (cc)[GRN], (cc)[BLU] )
#define bputaspect( write, pa ) \
bprintf( write, "%s%f\n", ASPECTSTR, pa )
#define bputprims( write, p ) \
bprintf( write, "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n", \
PRIMARYSTR, \
(p)[RED][CIEX], (p)[RED][CIEY], \
(p)[GRN][CIEX], (p)[GRN][CIEY], \
(p)[BLU][CIEX], (p)[BLU][CIEY], \
(p)[WHT][CIEX], (p)[WHT][CIEY] )
#define bputsresolu( write, rs ) \
bprintf( write, "%s", resolu2str( resolu_buf, rs ) )
static int
vips2rad_put_header_buf( Write *write )
{
vips2rad_make_header( write );
bprintf( write, "#?RADIANCE\n" );
bputformat( write, write->format );
bputexpos( write, write->expos );
bputcolcor( write, write->colcor );
bprintf( write, "SOFTWARE=vips %s\n", vips_version_string() );
bputaspect( write, write->aspect );
bputprims( write, write->prims );
bprintf( write, "\n" );
bputsresolu( write, &write->rs );
vips_dbuf_appendf( &write->dbuf, "#?RADIANCE\n" );
vips_dbuf_appendf( &write->dbuf, "%s%s\n", FMTSTR, write->format );
vips_dbuf_appendf( &write->dbuf, "%s%e\n", EXPOSSTR, write->expos );
vips_dbuf_appendf( &write->dbuf, "%s %f %f %f\n",
COLCORSTR,
write->colcor[RED], write->colcor[GRN], write->colcor[BLU] );
vips_dbuf_appendf( &write->dbuf, "SOFTWARE=vips %s\n",
vips_version_string() );
vips_dbuf_appendf( &write->dbuf, "%s%f\n", ASPECTSTR, write->aspect );
vips_dbuf_appendf( &write->dbuf,
"%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
PRIMARYSTR,
write->prims[RED][CIEX], write->prims[RED][CIEY],
write->prims[GRN][CIEX], write->prims[GRN][CIEY],
write->prims[BLU][CIEX], write->prims[BLU][CIEY],
write->prims[WHT][CIEX], write->prims[WHT][CIEY] );
vips_dbuf_appendf( &write->dbuf, "\n" );
vips_dbuf_appendf( &write->dbuf, "%s",
resolu2str( resolu_buf, &write->rs ) );
return( 0 );
}
@ -1441,25 +1378,25 @@ static int
scanline_write_buf( Write *write, COLR *scanline, int width )
{
unsigned char *buffer;
size_t size;
int length;
write_buf_grow( write, MAX_LINE );
buffer = (unsigned char *) write->buf + write->len;
vips_dbuf_allocate( &write->dbuf, MAX_LINE );
buffer = vips_dbuf_get_write( &write->dbuf, &size );
if( width < MINELEN ||
width > MAXELEN ) {
/* Write as a flat scanline.
*/
memcpy( buffer, scanline, sizeof( COLR ) * width );
write->len += sizeof( COLR ) * width;
length = sizeof( COLR ) * width;
memcpy( buffer, scanline, length );
}
else {
int length;
else
/* An RLE scanline.
*/
rle_scanline_write( scanline, width, buffer, &length );
write->len += length;
}
vips_dbuf_seek( &write->dbuf, length - size, SEEK_CUR );
return( 0 );
}
@ -1510,10 +1447,7 @@ vips__rad_save_buf( VipsImage *in, void **obuf, size_t *olen )
return( -1 );
}
*obuf = write->buf;
write->buf = NULL;
if( olen )
*olen = write->len;
*obuf = vips_dbuf_steal( &write->dbuf, olen );
write_destroy( write );

View File

@ -734,10 +734,12 @@ term_destination( j_compress_ptr cinfo )
size_t size;
/* This can be called before the output area fills. We need to chop
* size down to the number of bytes actually written.
/* We probably won't have filled the area that was last allocated in
* empty_output_buffer(). Chop the data size down to the length that
* was actually written.
*/
buf->dbuf.write_point = buf->dbuf.max_size - buf->pub.free_in_buffer;
vips_dbuf_seek( &buf->dbuf, -buf->pub.free_in_buffer, SEEK_END );
vips_dbuf_truncate( &buf->dbuf );
*(buf->obuf) = vips_dbuf_steal( &buf->dbuf, &size );
*(buf->olen) = size;

View File

@ -49,11 +49,17 @@ typedef struct _VipsDbuf {
/* The current base, and the size of the allocated memory area.
*/
unsigned char *data;
size_t max_size;
size_t allocated_size;
/* And the write point.
/* The size of the actual data that's been written. This will usually
* be <= allocated_size, but always >= write_point.
*/
size_t data_size;
/* The write point.
*/
size_t write_point;
} VipsDbuf;
void vips_dbuf_destroy( VipsDbuf *buf );
@ -63,8 +69,10 @@ unsigned char *vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size );
gboolean vips_dbuf_append( VipsDbuf *dbuf,
const unsigned char *data, size_t size );
gboolean vips_dbuf_appendf( VipsDbuf *dbuf, const char *fmt, ... );
void vips_dbuf_rewind( VipsDbuf *dbuf );
void vips_dbuf_reset( VipsDbuf *dbuf );
void vips_dbuf_destroy( VipsDbuf *dbuf );
gboolean vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence );
void vips_dbuf_truncate( VipsDbuf *dbuf );
unsigned char *vips_dbuf_string( VipsDbuf *dbuf, size_t *size );
unsigned char *vips_dbuf_steal( VipsDbuf *dbuf, size_t *size );

View File

@ -51,37 +51,74 @@ void
vips_dbuf_init( VipsDbuf *dbuf )
{
dbuf->data = NULL;
dbuf->max_size = 0;
dbuf->allocated_size = 0;
dbuf->data_size = 0;
dbuf->write_point = 0;
}
/**
* vips_dbuf_minimum_size:
* @dbuf: the buffer
* @size: the minimum size
*
* Make sure @dbuf is at least @size bytes.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
gboolean
vips_dbuf_minimum_size( VipsDbuf *dbuf, size_t size )
{
if( size > dbuf->allocated_size ) {
size_t new_allocated_size = 3 * (16 + size) / 2;
unsigned char *new_data;
if( !(new_data =
g_try_realloc( dbuf->data, new_allocated_size )) ) {
vips_error( "VipsDbuf", "%s", _( "out of memory" ) );
return( FALSE );
}
dbuf->data = new_data;
dbuf->allocated_size = new_allocated_size;
}
return( TRUE );
}
/**
* vips_dbuf_allocate:
* @dbuf: the buffer
* @size: the size to allocate
*
* Make sure @dbuf has at least @size bytes available for writing.
* Make sure @dbuf has at least @size bytes available after the write point.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
gboolean
vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
{
size_t new_write_point = dbuf->write_point + size;
return( vips_dbuf_minimum_size( dbuf, dbuf->write_point + size ) );
}
if( new_write_point > dbuf->max_size ) {
size_t new_max_size = 3 * (16 + new_write_point) / 2;
/**
* vips_dbuf_null_terminate:
* @dbuf: the buffer
*
* Make sure the byte after the last data byte is `\0`. This extra byte is not
* included in the data size and the write point is not moved.
*
* This makes it safe to treat the dbuf contents as a C string.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
static gboolean
vips_dbuf_null_terminate( VipsDbuf *dbuf )
{
if( !vips_dbuf_minimum_size( dbuf, dbuf->data_size + 1 ) )
return( FALSE );
unsigned char *new_data;
if( !(new_data = g_try_realloc( dbuf->data, new_max_size )) ) {
vips_error( "VipsDbuf", "%s", _( "out of memory" ) );
return( FALSE );
}
dbuf->data = new_data;
dbuf->max_size = new_max_size;
}
dbuf->data[dbuf->data_size] = 0;
return( TRUE );
}
@ -92,21 +129,28 @@ vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
* @size: (allow-none): optionally return length in bytes here
*
* Return a pointer to an area you can write to, return length of area in
* @size. Use vips_dbuf_allocate() before this call to make the space.
* @size. Use vips_dbuf_allocate() before this call to set a minimum amount of
* space to have available.
*
* The write point moves to just beyond the returned block. Use
* vips_dbuf_seek() to move it back again.
*
* Returns: (transfer none): start of write area.
*/
unsigned char *
vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
{
unsigned char *data = dbuf->data + dbuf->write_point;
unsigned char *write = dbuf->data + dbuf->write_point;
size_t length = dbuf->data + dbuf->allocated_size - write;
memset( write, 0, length );
dbuf->write_point = dbuf->allocated_size;
dbuf->data_size = dbuf->allocated_size;
if( size )
*size = dbuf->max_size - dbuf->write_point;
*size = length;
dbuf->write_point = dbuf->max_size;
return( data );
return( write );
}
/**
@ -115,7 +159,7 @@ vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
* @data: the data to append to the buffer
* @size: the size of the len to append
*
* Append len bytes from @data to the buffer. The buffer expands if necessary.
* Append @size bytes from @data. @dbuf expands if necessary.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
@ -127,6 +171,7 @@ vips_dbuf_append( VipsDbuf *dbuf, const unsigned char *data, size_t size )
memcpy( dbuf->data + dbuf->write_point, data, size );
dbuf->write_point += size;
dbuf->data_size = VIPS_MAX( dbuf->data_size, dbuf->write_point );
return( TRUE );
}
@ -161,16 +206,17 @@ vips_dbuf_appendf( VipsDbuf *dbuf, const char *fmt, ... )
}
/**
* vips_dbuf_rewind:
* vips_dbuf_reset:
* @dbuf: the buffer
*
* Reset the buffer to empty. No memory is freed, just the write pointer is
* reset.
* Reset the buffer to empty. No memory is freed, just the data size and
* write point are reset.
*/
void
vips_dbuf_rewind( VipsDbuf *dbuf )
vips_dbuf_reset( VipsDbuf *dbuf )
{
dbuf->write_point = 0;
dbuf->data_size = 0;
}
/**
@ -182,9 +228,73 @@ vips_dbuf_rewind( VipsDbuf *dbuf )
void
vips_dbuf_destroy( VipsDbuf *dbuf )
{
vips_dbuf_reset( dbuf );
VIPS_FREE( dbuf->data );
dbuf->max_size = 0;
dbuf->write_point = 0;
dbuf->allocated_size = 0;
}
/**
* vips_dbuf_seek:
* @dbuf: the buffer
* @offset: how to move the write point
* @whence: from start, from end, from current
*
* Move the write point. @whence can be %SEEK_SET, %SEEK_CUR, %SEEK_END, with
* the usual meaning.
*/
gboolean
vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence )
{
off_t new_write_point;
switch( whence ) {
case SEEK_SET:
new_write_point = offset;
break;
case SEEK_END:
new_write_point = dbuf->data_size + offset;
break;
case SEEK_CUR:
new_write_point = dbuf->write_point + offset;
break;
default:
g_assert( 0 );
new_write_point = dbuf->write_point;
break;
}
if( new_write_point < 0 ) {
vips_error( "VipsDbuf", "%s", "negative seek" );
return( FALSE );
}
/* Possibly need to grow the buffer
*/
if( !vips_dbuf_minimum_size( dbuf, new_write_point ) )
return( FALSE );
dbuf->write_point = new_write_point;
if( dbuf->data_size < dbuf->write_point ) {
memset( dbuf->data, 0, dbuf->write_point - dbuf->data_size );
dbuf->data_size = dbuf->write_point;
}
return( TRUE );
}
/**
* vips_dbuf_truncate:
* @dbuf: the buffer
*
* Truncate the data so that it ends at the write point. No memory is freed.
*/
void
vips_dbuf_truncate( VipsDbuf *dbuf )
{
dbuf->data_size = dbuf->write_point;
}
/**
@ -205,17 +315,15 @@ vips_dbuf_steal( VipsDbuf *dbuf, size_t *size )
{
unsigned char *data;
vips_dbuf_append( dbuf, (unsigned char *) "", 1 );
dbuf->write_point -= 1;
vips_dbuf_null_terminate( dbuf );
data = dbuf->data;
if( size )
*size = dbuf->write_point;
*size = dbuf->data_size;
dbuf->data = NULL;
dbuf->max_size = 0;
dbuf->write_point = 0;
vips_dbuf_destroy( dbuf );
return( data );
}
@ -235,11 +343,10 @@ vips_dbuf_steal( VipsDbuf *dbuf, size_t *size )
unsigned char *
vips_dbuf_string( VipsDbuf *dbuf, size_t *size )
{
vips_dbuf_append( dbuf, (unsigned char *) "", 1 );
dbuf->write_point -= 1;
vips_dbuf_null_terminate( dbuf );
if( size )
*size = dbuf->write_point;
*size = dbuf->data_size;
return( dbuf->data );
}

View File

@ -536,7 +536,7 @@ parser_element_start_handler( void *user_data,
vips_strncpy( vep->type, p[1], MAX_PARSE_ATTR );
}
vips_dbuf_rewind( &vep->dbuf );
vips_dbuf_reset( &vep->dbuf );
}
else if( strcmp( name, "header" ) == 0 )
vep->header = TRUE;
@ -545,7 +545,7 @@ parser_element_start_handler( void *user_data,
else if( strcmp( name, "root" ) == 0 ) {
for( p = atts; *p; p += 2 )
if( strcmp( p[0], "xmlns" ) == 0 &&
!vips_isprefix( NAMESPACE_URI "/vips", p[1] ) ) {
!vips_isprefix( NAMESPACE_URI "vips", p[1] ) ) {
vips_error( "VipsImage", "%s",
_( "incorrect namespace in XML" ) );
vep->error = TRUE;
@ -812,7 +812,7 @@ build_xml( VipsImage *image )
vips_dbuf_init( &dbuf );
vips_dbuf_appendf( &dbuf, "<?xml version=\"1.0\"?>\n" );
vips_dbuf_appendf( &dbuf, "<root xmlns=\"%s/vips/%d.%d.%d\">\n",
vips_dbuf_appendf( &dbuf, "<root xmlns=\"%svips/%d.%d.%d\">\n",
NAMESPACE_URI,
VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION );
vips_dbuf_appendf( &dbuf, " <header>\n" );