From 10a3782590d12f63b2852da11e6d4629f44286e1 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Thu, 19 May 2016 22:32:17 +0200 Subject: [PATCH 1/9] Add buffer write support for HDR Radiance --- libvips/foreign/radsave.c | 188 ++++++++++++++++++++++++++++----- libvips/include/vips/foreign.h | 2 + 2 files changed, 166 insertions(+), 24 deletions(-) diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index bfffe6c1..361cccb3 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -62,22 +62,6 @@ typedef VipsForeignSaveClass VipsForeignSaveRadClass; G_DEFINE_TYPE( VipsForeignSaveRad, vips_foreign_save_rad, VIPS_TYPE_FOREIGN_SAVE ); -static int -vips_foreign_save_rad_build( VipsObject *object ) -{ - VipsForeignSave *save = (VipsForeignSave *) object; - VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; - - if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_parent_class )-> - build( object ) ) - return( -1 ); - - if( vips__rad_save( save->ready, rad->filename ) ) - return( -1 ); - - return( 0 ); -} - /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR @@ -107,8 +91,8 @@ vips_foreign_save_rad_class_init( VipsForeignSaveRadClass *class ) gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; - object_class->nickname = "radsave"; - object_class->description = _( "save image to Radiance file" ); + object_class->nickname = "radsave_base"; + object_class->description = _( "save Radiance" ); object_class->build = vips_foreign_save_rad_build; foreign_class->suffs = vips__rad_suffs; @@ -118,12 +102,6 @@ vips_foreign_save_rad_class_init( VipsForeignSaveRadClass *class ) save_class->coding[VIPS_CODING_NONE] = FALSE; save_class->coding[VIPS_CODING_RAD] = TRUE; - VIPS_ARG_STRING( class, "filename", 1, - _( "Filename" ), - _( "Filename to save to" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsForeignSaveRad, filename ), - NULL ); } static void @@ -131,6 +109,122 @@ vips_foreign_save_rad_init( VipsForeignSaveRad *rad ) { } +typedef struct _VipsForeignSaveRadFile { + VipsForeignSaveRad parent_object; + + char *filename; +} VipsForeignSaveRadFile; + +typedef VipsForeignSaveRadClass VipsForeignSaveRadFileClass; + +G_DEFINE_TYPE( VipsForeignSaveRadFile, vips_foreign_save_Rad_file, + vips_foreign_save_Rad_get_type() ); + +static int +vips_foreign_save_rad_file_build( VipsObject *object ) +{ + VipsForeignSave *save = (VipsForeignSave *) object; + VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; + VipsForeignSaveRadFile *rad_file = (VipsForeignSaveRadFile *) object; + + if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_parent_class )-> + build( object ) ) + return( -1 ); + + if( vips__rad_save( save->ready, rad_file->filename ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_foreign_save_rad_file_class_init( VipsForeignSaveRadFileClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "radsave"; + object_class->description = _( "save image to Radiance file" ); + object_class->build = vips_foreign_save_rad_file_build; + + VIPS_ARG_STRING( class, "filename", 1, + _( "Filename" ), + _( "Filename to save to" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveRadFile, filename ), + NULL ); +} + +static void +vips_foreign_save_rad_file_init( VipsForeignSaveRadFile *file ) +{ +} + +typedef struct _VipsForeignSaveRadBuffer { + VipsForeignSaveRad parent_object; + + VipsArea *buf; +} VipsForeignSaveRadBuffer; + +typedef VipsForeignSaveRadClass VipsForeignSaveRadBufferClass; + +G_DEFINE_TYPE( VipsForeignSaveRadBuffer, vips_foreign_save_rad_buffer, + vips_foreign_save_rad_get_type() ); + +static int +vips_foreign_save_rad_buffer_build( VipsObject *object ) +{ + VipsForeignSave *save = (VipsForeignSave *) object; + VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; + + void *obuf; + size_t olen; + VipsBlob *blob; + + if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_buffer_parent_class )-> + build( object ) ) + return( -1 ); + + if( vips__rad_write_buf( save->ready, &obuf, &olen ) ) + return( -1 ); + + blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen ); + g_object_set( object, "buffer", blob, NULL ); + vips_area_unref( VIPS_AREA( blob ) ); + + return( 0 ); +} + +static void +vips_foreign_save_rad_buffer_class_init( VipsForeignSaveRadBufferClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "radsave_buffer"; + object_class->description = _( "save image to Radiance buffer" ); + object_class->build = vips_foreign_save_rad_buffer_build; + + VIPS_ARG_BOXED( class, "buffer", 1, + _( "Buffer" ), + _( "Buffer to save to" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsForeignSaveRadBuffer, buf ), + VIPS_TYPE_BLOB ); +} + +static void +vips_foreign_save_rad_buffer_init( VipsForeignSaveRadBuffer *buffer ) +{ +} + + #endif /*HAVE_RADIANCE*/ /** @@ -159,3 +253,49 @@ vips_radsave( VipsImage *in, const char *filename, ... ) return( result ); } + +/** + * vips_radsave_buffer: + * @in: image to save + * @buf: return output buffer here + * @len: return output length here + * @...: %NULL-terminated list of optional named arguments + * + * + * As vips_radsave(), but save to a memory buffer. + * + * The address of the buffer is returned in @obuf, the length of the buffer in + * @olen. You are responsible for freeing the buffer with g_free() when you + * are done with it. + * + * See also: vips_radsave(), vips_image_write_to_file(). + * + * Returns: 0 on success, -1 on error. + */ +int +vips_radsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) +{ + va_list ap; + VipsArea *area; + int result; + + area = NULL; + + va_start( ap, len ); + result = vips_call_split( "radsave_buffer", ap, in, &area ); + va_end( ap ); + + if( !result && + area ) { + if( buf ) { + *buf = area->data; + area->free_fn = NULL; + } + if( len ) + *len = area->length; + + vips_area_unref( area ); + } + + return( result ); +} \ No newline at end of file diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 218b7470..14d9a824 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -510,6 +510,8 @@ int vips_radload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); int vips_radsave( VipsImage *in, const char *filename, ... ) __attribute__((sentinel)); +int vips_radsave_buffer( VipsImage *in, void **buf, size_t *len, ... ) + __attribute__((sentinel)); int vips_pdfload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); From 23579d49283f0d3c98a02e589c3d3c9e759f723b Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Thu, 19 May 2016 22:37:33 +0200 Subject: [PATCH 2/9] delete obsolete line --- libvips/foreign/radsave.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index 361cccb3..96e4c429 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -93,7 +93,6 @@ vips_foreign_save_rad_class_init( VipsForeignSaveRadClass *class ) object_class->nickname = "radsave_base"; object_class->description = _( "save Radiance" ); - object_class->build = vips_foreign_save_rad_build; foreign_class->suffs = vips__rad_suffs; From 4c599ea272d7e7050d44d045554efa5c82e82179 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Fri, 20 May 2016 11:27:41 +0200 Subject: [PATCH 3/9] fix typo --- libvips/foreign/radsave.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index 96e4c429..d6204647 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -116,8 +116,8 @@ typedef struct _VipsForeignSaveRadFile { typedef VipsForeignSaveRadClass VipsForeignSaveRadFileClass; -G_DEFINE_TYPE( VipsForeignSaveRadFile, vips_foreign_save_Rad_file, - vips_foreign_save_Rad_get_type() ); +G_DEFINE_TYPE( VipsForeignSaveRadFile, vips_foreign_save_rad_file, + vips_foreign_save_rad_get_type() ); static int vips_foreign_save_rad_file_build( VipsObject *object ) From 14d7a97afc50cbf5ca5087509b215af59a58d250 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Fri, 20 May 2016 11:28:33 +0200 Subject: [PATCH 4/9] change write_new to make it independent from file I/O --- libvips/foreign/radiance.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index fc688b60..a3f6eb31 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -1176,7 +1176,7 @@ write_destroy( Write *write ) } static Write * -write_new( VipsImage *in, const char *filename ) +write_new( VipsImage *in) { Write *write; int i; @@ -1185,8 +1185,6 @@ write_new( VipsImage *in, const char *filename ) return( NULL ); write->in = in; - write->filename = vips_strdup( NULL, filename ); - write->fout = vips__file_open_write( filename, FALSE ); strcpy( write->format, COLRFMT ); write->expos = 1.0; for( i = 0; i < 3; i++ ) @@ -1201,11 +1199,6 @@ write_new( VipsImage *in, const char *filename ) write->prims[3][0] = CIE_x_w; write->prims[3][1] = CIE_y_w; - if( !write->filename || !write->fout ) { - write_destroy( write ); - return( NULL ); - } - return( write ); } @@ -1292,9 +1285,14 @@ vips__rad_save( VipsImage *in, const char *filename ) if( vips_image_pio_input( in ) || vips_check_coding_rad( "vips2rad", in ) ) return( -1 ); - if( !(write = write_new( in, filename )) ) + if( !(write = write_new( in )) ) return( -1 ); - if( vips2rad_put_header( write ) || + + write->filename = vips_strdup( NULL, filename ); + write->fout = vips__file_open_write( filename, FALSE ); + + if( !write->filename || !write->fout || + vips2rad_put_header( write ) || vips2rad_put_data( write ) ) { write_destroy( write ); return( -1 ); From 5678f93257f479b76ff68b18483e933b42172ca6 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 23 May 2016 16:37:28 +0200 Subject: [PATCH 5/9] Add buffer-write support for Radiance --- cplusplus/include/vips/vips-operators.h | 1 + cplusplus/vips-operators.cpp | 12 + libvips/foreign/foreign.c | 6 +- libvips/foreign/radiance.c | 287 +++++++++++++++++++++++- libvips/foreign/radiance.h | 1 + libvips/foreign/radsave.c | 4 +- 6 files changed, 303 insertions(+), 8 deletions(-) diff --git a/cplusplus/include/vips/vips-operators.h b/cplusplus/include/vips/vips-operators.h index 7466fcc7..92b30b1f 100644 --- a/cplusplus/include/vips/vips-operators.h +++ b/cplusplus/include/vips/vips-operators.h @@ -131,6 +131,7 @@ static VImage magickload_buffer( VipsBlob * buffer , VOption *options = 0 ); static VImage fitsload( char * filename , VOption *options = 0 ); static VImage openexrload( char * filename , VOption *options = 0 ); void radsave( char * filename , VOption *options = 0 ); +VipsBlob * radsave_buffer( VOption *options = 0 ); void ppmsave( char * filename , VOption *options = 0 ); void csvsave( char * filename , VOption *options = 0 ); void matrixsave( char * filename , VOption *options = 0 ); diff --git a/cplusplus/vips-operators.cpp b/cplusplus/vips-operators.cpp index 257234ad..ddbef979 100644 --- a/cplusplus/vips-operators.cpp +++ b/cplusplus/vips-operators.cpp @@ -1656,6 +1656,18 @@ void VImage::radsave( char * filename , VOption *options ) set( "filename", filename ) ); } +VipsBlob * VImage::radsave_buffer( VOption *options ) +{ + VipsBlob * buffer; + + call( "radsave_buffer" , + (options ? options : VImage::option()) -> + set( "in", *this ) -> + set( "buffer", &buffer ) ); + + return( buffer ); +} + void VImage::ppmsave( char * filename , VOption *options ) { call( "ppmsave" , diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index e51d2b17..15cfd024 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1619,7 +1619,8 @@ void vips_foreign_operation_init( void ) { extern GType vips_foreign_load_rad_get_type( void ); - extern GType vips_foreign_save_rad_get_type( void ); + extern GType vips_foreign_save_rad_file_get_type( void ); + extern GType vips_foreign_save_rad_buffer_get_type( void ); extern GType vips_foreign_load_mat_get_type( void ); extern GType vips_foreign_load_ppm_get_type( void ); extern GType vips_foreign_save_ppm_get_type( void ); @@ -1689,7 +1690,8 @@ vips_foreign_operation_init( void ) #ifdef HAVE_RADIANCE vips_foreign_load_rad_get_type(); - vips_foreign_save_rad_get_type(); + vips_foreign_save_rad_file_get_type(); + vips_foreign_save_rad_buffer_get_type(); #endif /*HAVE_RADIANCE*/ #ifdef HAVE_POPPLER diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index a3f6eb31..a52af471 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -132,6 +132,7 @@ #include #include #include +#include #include #include #include @@ -1151,7 +1152,7 @@ vips__rad_load( const char *filename, VipsImage *out, gboolean readbehind ) return( 0 ); } -/* What we track during a radiance file write. +/* What we track during a radiance write. */ typedef struct { VipsImage *in; @@ -1167,7 +1168,7 @@ typedef struct { } Write; static void -write_destroy( Write *write ) +write_destroy_file( Write *write ) { VIPS_FREE( write->filename ); VIPS_FREEF( fclose, write->fout ); @@ -1175,6 +1176,12 @@ write_destroy( Write *write ) vips_free( write ); } +static void +write_destroy( Write *write ) +{ + vips_free( write ); +} + static Write * write_new( VipsImage *in) { @@ -1202,8 +1209,8 @@ write_new( VipsImage *in) return( write ); } -static int -vips2rad_put_header( Write *write ) +static void +vips2rad_make_header( Write *write ) { const char *str; int i, j; @@ -1233,6 +1240,12 @@ vips2rad_put_header( Write *write ) write->rs.rt = YDECR | YMAJOR; write->rs.xr = write->in->Xsize; write->rs.yr = write->in->Ysize; +} + +static int +vips2rad_put_header( Write *write ) +{ + vips2rad_make_header(write); fprintf( write->fout, "#?RADIANCE\n" ); @@ -1294,11 +1307,277 @@ vips__rad_save( VipsImage *in, const char *filename ) if( !write->filename || !write->fout || vips2rad_put_header( write ) || vips2rad_put_data( write ) ) { + write_destroy_file( write ); + return( -1 ); + } + write_destroy_file( write ); + + return( 0 ); +} + +typedef struct _WriteBuf { + char *buf; + size_t len; + size_t alloc; +} WriteBuf; + +static void +write_buf_free( WriteBuf *wbuf ) +{ + VIPS_FREE( wbuf->buf ); + VIPS_FREE( wbuf ); +} + +static WriteBuf * +write_buf_new( void ) +{ + WriteBuf *wbuf; + + if( !(wbuf = VIPS_NEW( NULL, WriteBuf )) ) + return( NULL ); + + wbuf->buf = NULL; + wbuf->len = 0; + wbuf->alloc = 0; + + return( wbuf ); +} + +static void +write_buf_grow( WriteBuf *wbuf, size_t grow_len ) +{ + size_t new_len = wbuf->len + grow_len; + + if( new_len > wbuf->alloc ) { + size_t proposed_alloc = (16 + wbuf->alloc) * 3 / 2; + + wbuf->alloc = VIPS_MAX( proposed_alloc, new_len ); + + /* There's no vips_realloc(), so we call g_realloc() directly. + * This is safe, since vips_malloc() / vips_free() are wrappers + * over g_malloc() / g_free(). + * + * FIXME: add vips_realloc(). + */ + wbuf->buf = g_realloc( wbuf->buf, wbuf->alloc ); + + // VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n", + // wbuf->alloc ); + } +} + +static void +bprintf( WriteBuf *wbuf, const char *fmt, ... ) +{ + int length = 0; + char *write_start = NULL; + va_list ap; + + /* Determine required size */ + va_start(ap, fmt); + length = vsnprintf(write_start, length, fmt, ap); + va_end(ap); + + write_buf_grow( wbuf, length + 1 ); + + write_start = wbuf->buf + wbuf->len; + + va_start(ap, fmt); + length = vsnprintf(write_start, length + 1, fmt, ap); + va_end(ap); + + //memcpy( write_start, data, length ); + + wbuf->len += length; + + g_assert( wbuf->len <= wbuf->alloc ); +} + +#define bputformat(s,wb) bprintf(wb, "%s%s\n", FMTSTR, s) + +#define bputexpos(ex,wb) bprintf(wb,"%s%e\n",EXPOSSTR,ex) + +#define bputcolcor(cc,wb) bprintf(wb,"%s %f %f %f\n",COLCORSTR, \ + (cc)[RED],(cc)[GRN],(cc)[BLU]) + +#define bputaspect(pa,wb) bprintf(wb,"%s%f\n",ASPECTSTR,pa) + +#define bputprims(p,wb) bprintf(wb, \ + "%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(rs,wb) bprintf(wb,"%s",resolu2str(resolu_buf,rs)) + +static int +vips2rad_put_header_buf( WriteBuf *wbuf, Write *write ) +{ + vips2rad_make_header(write); + + bprintf( wbuf, "#?RADIANCE\n" ); + + bputformat( write->format, wbuf ); + bputexpos( write->expos, wbuf ); + bputcolcor( write->colcor, wbuf ); + bprintf( wbuf, "SOFTWARE=vips %s\n", vips_version_string() ); + bputaspect( write->aspect, wbuf ); + bputprims( write->prims, wbuf ); + bprintf( wbuf, "\n" ); + bputsresolu( &write->rs, wbuf ); + + return( 0 ); +} + +/* Write a single scanline to buffer. + */ +static int +scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) +{ + printf("scanline %zu %zu \n", wbuf->len, wbuf->alloc); + //unsigned char buffer[MAX_LINE]; + int buffer_pos = 0; + + int i, j, beg, cnt; + + write_buf_grow( wbuf, MAX_LINE ); + unsigned char *buffer = (unsigned char *) wbuf->buf + wbuf->len; + +#define PUTC_BUF( CH ) { \ + buffer[buffer_pos++] = (CH); \ + g_assert( buffer_pos <= MAX_LINE ); \ +} + + if( width < MINELEN || + width > MAXELEN ) { + /* Write as a flat scanline. + */ + memcpy( buffer, scanline, sizeof( COLR ) * width ); + wbuf->len += sizeof( COLR ) * width; + + return( 0 ); //fwrite( scanline, sizeof( COLR ), width, fp ) - width ); + } + /* An RLE scanline. Write magic header. + */ + PUTC_BUF( 2 ); + PUTC_BUF( 2 ); + PUTC_BUF( width >> 8 ); + PUTC_BUF( width & 255 ); + + for( i = 0; i < 4; i++ ) { + for( j = 0; j < width; ) { + /* Not needed, but keeps gcc used-before-set wsrning + * quiet. + */ + cnt = 1; + + /* Set beg / cnt to the start and length of the next + * run longer than MINRUN. + */ + for( beg = j; beg < width; beg += cnt ) { + for( cnt = 1; + cnt < 127 && + beg + cnt < width && + scanline[beg + cnt][i] == + scanline[beg][i]; + cnt++ ) + ; + + if( cnt >= MINRUN ) + break; + } + + /* Code pixels leading up to the run as a set of + * non-runs. + */ + while( j < beg ) { + int len = VIPS_MIN( 128, beg - j ); + COLR *p = scanline + j; + + int k; + + PUTC_BUF( len ); + for( k = 0; k < len; k++ ) + PUTC_BUF( p[k][i] ); + j += len; + } + + /* Code the run we found, if any + */ + if( cnt >= MINRUN ) { + PUTC_BUF( 128 + cnt ); + PUTC_BUF( scanline[j][i] ); + j += cnt; + } + } + } + + wbuf->len += buffer_pos; + //return( fwrite( buffer, 1, buffer_pos, fp ) - buffer_pos ); + return( 0 ); +} + +static int +vips2rad_put_data_block_buf( VipsRegion *region, VipsRect *area, void *a ) +{ + WriteBuf *wbuf = (WriteBuf *) a; + int i; + + for( i = 0; i < area->height; i++ ) { + VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + i ); + + if( scanline_write_buf( (COLR *) p, area->width, wbuf ) ) + return( -1 ); + } + + return( 0 ); +} + +static int +vips2rad_put_data_buf( WriteBuf *wbuf, Write *write ) +{ + if( vips_sink_disc( write->in, vips2rad_put_data_block_buf, wbuf ) ) + return( -1 ); + + return( 0 ); +} + +int +vips__rad_save_buf( VipsImage *in, void **obuf, size_t *olen ) +{ + Write *write; + WriteBuf *wbuf; + +#ifdef DEBUG + printf( "vips2rad: writing to buffer\n" ); +#endif /*DEBUG*/ + + if( vips_image_pio_input( in ) || + vips_check_coding_rad( "vips2rad", in ) ) + return( -1 ); + if( !(wbuf = write_buf_new()) ) + return( -1 ); + if( !(write = write_new( in )) ) { + write_buf_free( wbuf ); + return( -1 ); + } + + if( vips2rad_put_header_buf( wbuf, write ) || + vips2rad_put_data_buf( wbuf, write ) ) { write_destroy( write ); + write_buf_free( wbuf ); return( -1 ); } write_destroy( write ); + *obuf = wbuf->buf; + wbuf->buf = NULL; + if( olen ) + *olen = wbuf->len; + + write_buf_free( wbuf ); return( 0 ); } diff --git a/libvips/foreign/radiance.h b/libvips/foreign/radiance.h index 95f5c3e4..71a259b8 100644 --- a/libvips/foreign/radiance.h +++ b/libvips/foreign/radiance.h @@ -40,6 +40,7 @@ int vips__rad_header( const char *filename, VipsImage *out ); int vips__rad_load( const char *filename, VipsImage *out, gboolean readbehind ); int vips__rad_save( VipsImage *in, const char *filename ); +int vips__rad_save_buf( VipsImage *in, void **obuf, size_t *olen ); extern const char *vips__rad_suffs[]; diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index d6204647..8cfca8ae 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -126,7 +126,7 @@ vips_foreign_save_rad_file_build( VipsObject *object ) VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; VipsForeignSaveRadFile *rad_file = (VipsForeignSaveRadFile *) object; - if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_parent_class )-> + if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_file_parent_class )-> build( object ) ) return( -1 ); @@ -187,7 +187,7 @@ vips_foreign_save_rad_buffer_build( VipsObject *object ) build( object ) ) return( -1 ); - if( vips__rad_write_buf( save->ready, &obuf, &olen ) ) + if( vips__rad_save_buf( save->ready, &obuf, &olen ) ) return( -1 ); blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen ); From 486a08d8a6f19cfebdffa33ba4f3d4b8a609fa10 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 23 May 2016 16:49:47 +0200 Subject: [PATCH 6/9] relive debug stuff --- libvips/foreign/radiance.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index a52af471..f52056af 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -139,6 +139,7 @@ #include #include +#include #include "radiance.h" @@ -1361,8 +1362,8 @@ write_buf_grow( WriteBuf *wbuf, size_t grow_len ) */ wbuf->buf = g_realloc( wbuf->buf, wbuf->alloc ); - // VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n", - // wbuf->alloc ); + VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n", + wbuf->alloc ); } } @@ -1386,8 +1387,6 @@ bprintf( WriteBuf *wbuf, const char *fmt, ... ) length = vsnprintf(write_start, length + 1, fmt, ap); va_end(ap); - //memcpy( write_start, data, length ); - wbuf->len += length; g_assert( wbuf->len <= wbuf->alloc ); @@ -1436,8 +1435,6 @@ vips2rad_put_header_buf( WriteBuf *wbuf, Write *write ) static int scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) { - printf("scanline %zu %zu \n", wbuf->len, wbuf->alloc); - //unsigned char buffer[MAX_LINE]; int buffer_pos = 0; int i, j, beg, cnt; @@ -1457,7 +1454,7 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) memcpy( buffer, scanline, sizeof( COLR ) * width ); wbuf->len += sizeof( COLR ) * width; - return( 0 ); //fwrite( scanline, sizeof( COLR ), width, fp ) - width ); + return( 0 ); } /* An RLE scanline. Write magic header. */ @@ -1515,7 +1512,6 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) } wbuf->len += buffer_pos; - //return( fwrite( buffer, 1, buffer_pos, fp ) - buffer_pos ); return( 0 ); } From 98c7a766ded8b6eec2379f7609df6332ef557575 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 23 May 2016 16:49:47 +0200 Subject: [PATCH 7/9] remove debug stuff --- libvips/foreign/radiance.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index a52af471..f52056af 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -139,6 +139,7 @@ #include #include +#include #include "radiance.h" @@ -1361,8 +1362,8 @@ write_buf_grow( WriteBuf *wbuf, size_t grow_len ) */ wbuf->buf = g_realloc( wbuf->buf, wbuf->alloc ); - // VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n", - // wbuf->alloc ); + VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n", + wbuf->alloc ); } } @@ -1386,8 +1387,6 @@ bprintf( WriteBuf *wbuf, const char *fmt, ... ) length = vsnprintf(write_start, length + 1, fmt, ap); va_end(ap); - //memcpy( write_start, data, length ); - wbuf->len += length; g_assert( wbuf->len <= wbuf->alloc ); @@ -1436,8 +1435,6 @@ vips2rad_put_header_buf( WriteBuf *wbuf, Write *write ) static int scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) { - printf("scanline %zu %zu \n", wbuf->len, wbuf->alloc); - //unsigned char buffer[MAX_LINE]; int buffer_pos = 0; int i, j, beg, cnt; @@ -1457,7 +1454,7 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) memcpy( buffer, scanline, sizeof( COLR ) * width ); wbuf->len += sizeof( COLR ) * width; - return( 0 ); //fwrite( scanline, sizeof( COLR ), width, fp ) - width ); + return( 0 ); } /* An RLE scanline. Write magic header. */ @@ -1515,7 +1512,6 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) } wbuf->len += buffer_pos; - //return( fwrite( buffer, 1, buffer_pos, fp ) - buffer_pos ); return( 0 ); } From 922b237d9e1ee0721cf5f2b0544f5727abf74de5 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 23 May 2016 17:24:00 +0200 Subject: [PATCH 8/9] Add changelog --- libvips/foreign/radiance.c | 18 ++++++++++-------- libvips/foreign/radsave.c | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index f52056af..0a663153 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -15,6 +15,8 @@ * 23/1/14 * - put the reader globals into a struct so we can have many active * readers + * 23/5/16 + * - Add buffer save functions */ /* @@ -1458,10 +1460,10 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) } /* An RLE scanline. Write magic header. */ - PUTC_BUF( 2 ); - PUTC_BUF( 2 ); - PUTC_BUF( width >> 8 ); - PUTC_BUF( width & 255 ); + PUTC( 2 ); + PUTC( 2 ); + PUTC( width >> 8 ); + PUTC( width & 255 ); for( i = 0; i < 4; i++ ) { for( j = 0; j < width; ) { @@ -1495,17 +1497,17 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) int k; - PUTC_BUF( len ); + PUTC( len ); for( k = 0; k < len; k++ ) - PUTC_BUF( p[k][i] ); + PUTC( p[k][i] ); j += len; } /* Code the run we found, if any */ if( cnt >= MINRUN ) { - PUTC_BUF( 128 + cnt ); - PUTC_BUF( scanline[j][i] ); + PUTC( 128 + cnt ); + PUTC( scanline[j][i] ); j += cnt; } } diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index 8cfca8ae..9d3a6614 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -2,6 +2,8 @@ * * 2/12/11 * - wrap a class around the rad writer + * 23/5/16 + * - split into file and buffer save classes */ /* From d2c4bbeda25600a70e682b39e6ffdf571d5aa827 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Mon, 23 May 2016 18:21:13 +0200 Subject: [PATCH 9/9] Move common RLE code to function --- libvips/foreign/radiance.c | 105 ++++++++++--------------------------- libvips/foreign/radsave.c | 2 - 2 files changed, 27 insertions(+), 80 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index 0a663153..e6d97da0 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -814,29 +814,16 @@ scanline_read( Buffer *buffer, COLR *scanline, int width ) */ #define MAX_LINE (2 * MAXELEN * sizeof( COLR )) -/* Write a single scanline. +/* write an RLE scanline. Write magic header. */ -static int -scanline_write( COLR *scanline, int width, FILE *fp ) +static void +rle_scanline_write( COLR *scanline, int width, unsigned char *buffer, int *buffer_pos ) { - unsigned char buffer[MAX_LINE]; - int buffer_pos = 0; - #define PUTC( CH ) { \ - buffer[buffer_pos++] = (CH); \ - g_assert( buffer_pos <= MAX_LINE ); \ + buffer[(*buffer_pos)++] = (CH); \ + g_assert( *buffer_pos <= MAX_LINE ); \ } - int i, j, beg, cnt; - - if( width < MINELEN || - width > MAXELEN ) - /* Write as a flat scanline. - */ - return( fwrite( scanline, sizeof( COLR ), width, fp ) - width ); - - /* An RLE scanline. Write magic header. - */ PUTC( 2 ); PUTC( 2 ); PUTC( width >> 8 ); @@ -889,6 +876,25 @@ scanline_write( COLR *scanline, int width, FILE *fp ) } } } +} + +/* Write a single scanline. + */ +static int +scanline_write( COLR *scanline, int width, FILE *fp ) +{ + unsigned char buffer[MAX_LINE]; + int buffer_pos = 0; + + if( width < MINELEN || + width > MAXELEN ) + /* Write as a flat scanline. + */ + return( fwrite( scanline, sizeof( COLR ), width, fp ) - width ); + + /* An RLE scanline. + */ + rle_scanline_write( scanline, width, buffer, &buffer_pos ); return( fwrite( buffer, 1, buffer_pos, fp ) - buffer_pos ); } @@ -1439,16 +1445,9 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) { int buffer_pos = 0; - int i, j, beg, cnt; - write_buf_grow( wbuf, MAX_LINE ); unsigned char *buffer = (unsigned char *) wbuf->buf + wbuf->len; -#define PUTC_BUF( CH ) { \ - buffer[buffer_pos++] = (CH); \ - g_assert( buffer_pos <= MAX_LINE ); \ -} - if( width < MINELEN || width > MAXELEN ) { /* Write as a flat scanline. @@ -1458,60 +1457,10 @@ scanline_write_buf( COLR *scanline, int width, WriteBuf *wbuf ) return( 0 ); } - /* An RLE scanline. Write magic header. + + /* An RLE scanline. */ - PUTC( 2 ); - PUTC( 2 ); - PUTC( width >> 8 ); - PUTC( width & 255 ); - - for( i = 0; i < 4; i++ ) { - for( j = 0; j < width; ) { - /* Not needed, but keeps gcc used-before-set wsrning - * quiet. - */ - cnt = 1; - - /* Set beg / cnt to the start and length of the next - * run longer than MINRUN. - */ - for( beg = j; beg < width; beg += cnt ) { - for( cnt = 1; - cnt < 127 && - beg + cnt < width && - scanline[beg + cnt][i] == - scanline[beg][i]; - cnt++ ) - ; - - if( cnt >= MINRUN ) - break; - } - - /* Code pixels leading up to the run as a set of - * non-runs. - */ - while( j < beg ) { - int len = VIPS_MIN( 128, beg - j ); - COLR *p = scanline + j; - - int k; - - PUTC( len ); - for( k = 0; k < len; k++ ) - PUTC( p[k][i] ); - j += len; - } - - /* Code the run we found, if any - */ - if( cnt >= MINRUN ) { - PUTC( 128 + cnt ); - PUTC( scanline[j][i] ); - j += cnt; - } - } - } + rle_scanline_write( scanline, width, buffer, &buffer_pos ); wbuf->len += buffer_pos; return( 0 ); diff --git a/libvips/foreign/radsave.c b/libvips/foreign/radsave.c index 9d3a6614..7a4d0871 100644 --- a/libvips/foreign/radsave.c +++ b/libvips/foreign/radsave.c @@ -125,7 +125,6 @@ static int vips_foreign_save_rad_file_build( VipsObject *object ) { VipsForeignSave *save = (VipsForeignSave *) object; - VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; VipsForeignSaveRadFile *rad_file = (VipsForeignSaveRadFile *) object; if( VIPS_OBJECT_CLASS( vips_foreign_save_rad_file_parent_class )-> @@ -179,7 +178,6 @@ static int vips_foreign_save_rad_buffer_build( VipsObject *object ) { VipsForeignSave *save = (VipsForeignSave *) object; - VipsForeignSaveRad *rad = (VipsForeignSaveRad *) object; void *obuf; size_t olen;