move buf writers on top of dbuf
tiff and webp not moved
This commit is contained in:
parent
40294bb85c
commit
f2a178e98f
22
TODO
22
TODO
@ -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
|
||||
|
||||
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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" );
|
||||
|
Loading…
Reference in New Issue
Block a user