diff --git a/ChangeLog b/ChangeLog index 72168e31..f971b369 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 19/3/12 started 7.29.0 - better PNG alpha handling - sanity-check PNG read geometry +- add dzsave, save in deep zoom format 13/3/12 started 7.28.2 - xres/yres tiffsave args were broken diff --git a/acinclude.m4 b/acinclude.m4 index 4a35d012..ba47c576 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -501,3 +501,66 @@ $2]) CPPFLAGS="$save_CPPFLAGS" ]) +dnl @synopsis AC_FUNC_MKDIR +dnl +dnl Check whether mkdir() is mkdir or _mkdir, and whether it takes one +dnl or two arguments. +dnl +dnl This macro can define HAVE_MKDIR, HAVE__MKDIR, and +dnl MKDIR_TAKES_ONE_ARG, which are expected to be used as follows: +dnl +dnl #if HAVE_MKDIR +dnl # if MKDIR_TAKES_ONE_ARG +dnl /* MinGW32 */ +dnl # define mkdir(a, b) mkdir(a) +dnl # endif +dnl #else +dnl # if HAVE__MKDIR +dnl /* plain Windows 32 */ +dnl # define mkdir(a, b) _mkdir(a) +dnl # else +dnl # error "Don't know how to create a directory on this system." +dnl # endif +dnl #endif +dnl +dnl @category C +dnl @author Alexandre Duret-Lutz +dnl @version 2003-12-28 +dnl @license GPLWithACException + +AC_DEFUN([AC_FUNC_MKDIR], +[AC_CHECK_FUNCS([mkdir _mkdir]) +AC_CACHE_CHECK([whether mkdir takes one argument], + [ac_cv_mkdir_takes_one_arg], +[AC_TRY_COMPILE([ +#include +#if HAVE_UNISTD_H +# include +#endif +], [mkdir (".");], +[ac_cv_mkdir_takes_one_arg=yes], [ac_cv_mkdir_takes_one_arg=no])]) +if test x"$ac_cv_mkdir_takes_one_arg" = xyes; then + AC_DEFINE([MKDIR_TAKES_ONE_ARG], 1, + [Define if mkdir takes only one argument.]) +fi +]) + +dnl Note: +dnl ===== +dnl I have not implemented the following suggestion because I don't have +dnl access to such a broken environment to test the macro. So I'm just +dnl appending the comments here in case you have, and want to fix +dnl AC_FUNC_MKDIR that way. +dnl +dnl |Thomas E. Dickey (dickey@herndon4.his.com) said: +dnl | it doesn't cover the problem areas (compilers that mistreat mkdir +dnl | may prototype it in dir.h and dirent.h, for instance). +dnl | +dnl |Alexandre: +dnl | Would it be sufficient to check for these headers and #include +dnl | them in the AC_TRY_COMPILE block? (and is AC_HEADER_DIRENT +dnl | suitable for this?) +dnl | +dnl |Thomas: +dnl | I think that might be a good starting point (with the set of recommended +dnl | ifdef's and includes for AC_HEADER_DIRENT, of course). diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 93d5c2a4..33c69da4 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -62,6 +62,7 @@ struct _Layer { VipsImage *image; /* The image we build */ VipsRegion *strip; /* The current strip of pixels */ + VipsRegion *copy; /* Pixels we copy to the next strip */ int sub; /* Subsample factor for this layer */ int n; /* Layer number ... 0 for smallest */ @@ -96,6 +97,7 @@ static void layer_free( Layer *layer ) { VIPS_FREEF( g_object_unref, layer->strip ); + VIPS_FREEF( g_object_unref, layer->copy ); VIPS_FREEF( g_object_unref, layer->image ); VIPS_FREEF( layer_free, layer->below ); @@ -122,6 +124,9 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above, int w, int h ) VipsRect strip; layer->dz = dz; + layer->image = NULL; + layer->strip = NULL; + layer->copy = NULL; if( !above ) /* Top of pyramid. @@ -134,13 +139,20 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above, int w, int h ) layer->above = above; layer->image = vips_image_new(); - if( vips_image_copy_fields( layer->image, save->in ) ) { + if( vips_image_copy_fields( layer->image, save->ready ) ) { layer_free( layer ); return( NULL ); } layer->image->Xsize = w; layer->image->Ysize = h; - layer->strip = vips_region_new( save->in ); + layer->strip = vips_region_new( layer->image ); + layer->copy = vips_region_new( layer->image ); + + /* The regions will get used in the bg thread callback, so make sure + * we don't own them. + */ + vips__region_no_ownership( layer->strip ); + vips__region_no_ownership( layer->copy ); /* Build a line of tiles here. */ @@ -194,10 +206,8 @@ static void shrink_region_labpack( VipsRegion *from, VipsRegion *to ) { int ls = VIPS_REGION_LSKIP( from ); - int ps = VIPS_IMAGE_SIZEOF_PEL( from->im ); - int nb = from->im->Bands; - int x, y, z; + int x, y; VipsRect target; /* Calculate output size and position. @@ -215,7 +225,7 @@ shrink_region_labpack( VipsRegion *from, VipsRegion *to ) /* Ignore the extra bits for speed. */ - for( x = 0; x < out.width; x++ ) { + for( x = 0; x < target.width; x++ ) { signed char *sp = (signed char *) p; unsigned char *up = (unsigned char *) p; @@ -357,8 +367,10 @@ strip_save( Layer *layer ) tile.height = dz->tile_height + dz->overlap; vips_rect_intersectrect( &tile, &strip->valid, &tile ); + /* Extract relative to the strip top-left corner. + */ if( vips_extract_area( image, &extr, - tile.left, tile.top, tile.width, tile.height, NULL ) ) { + tile.left, 0, tile.width, tile.height, NULL ) ) { g_object_unref( image ); return( -1 ); } @@ -368,7 +380,7 @@ strip_save( Layer *layer ) x, y, dz->suffix ); - if( vips_image_write_file( extr, vips_buf_all( &buf ) ) ) { + if( vips_image_write_to_file( extr, vips_buf_all( &buf ) ) ) { g_object_unref( image ); g_object_unref( extr ); return( -1 ); @@ -391,10 +403,12 @@ static int strip_arrived( Layer *layer ) { VipsForeignSaveDz *dz = layer->dz; + VipsForeignSave *save = VIPS_FOREIGN_SAVE( dz ); Layer *below = layer->below; VipsRect target; VipsRect new_strip; + VipsRect overlap; if( strip_save( layer ) ) return( -1 ); @@ -410,36 +424,45 @@ strip_arrived( Layer *layer ) */ if( !vips_rect_isempty( &target ) && below ) { - VipsRect overlap; - VipsRect overlap; - /* Shrink into place. */ - if( dz->image->Coding == VIPS_CODING_NONE ) - shrink_region( layer->strip, below->strip, - target.left, target.top ); + if( save->ready->Coding == VIPS_CODING_NONE ) + shrink_region( layer->strip, below->strip ); else - shrink_region_labpack( layer->strip, below->strip, - target.left, target.top ); + shrink_region_labpack( layer->strip, below->strip ); /* If we've filled the strip of the layer below, recurse. */ if( VIPS_RECT_BOTTOM( &target ) == - VIPS_RECT_BOTTOM( &below->strip.valid ) && + VIPS_RECT_BOTTOM( &below->strip->valid ) && strip_arrived( below ) ) return( -1 ); } - /* Move our strip down the image. We need to keep ->overlap pixels from - * the end of the region. + /* Move our strip down the image. */ new_strip.left = 0; - new_strip.top = layer->region->valid.top + layer->region->valid.height; + new_strip.top = layer->strip->valid.top + layer->strip->valid.height; new_strip.width = layer->image->Xsize; new_strip.height = dz->tile_height + dz->overlap; + + vips_rect_intersectrect( &new_strip, &layer->strip->valid, &overlap ); + if( !vips_rect_isempty( &overlap ) ) { + /* There are some pixels we need to copy over. + */ + if( vips_region_buffer( layer->copy, &overlap ) ) + return( -1 ); + vips_region_copy( layer->strip, layer->copy, + &overlap, overlap.left, overlap.top ); + } + if( vips_region_buffer( layer->strip, &new_strip ) ) return( -1 ); + if( !vips_rect_isempty( &overlap ) ) + vips_region_copy( layer->copy, layer->strip, + &overlap, overlap.left, overlap.top ); + return( 0 ); } @@ -458,7 +481,7 @@ pyramid_strip( VipsRegion *region, VipsRect *area, void *a ) /* Write what we can into the current top strip. */ - vips_rect_intersectrect( area, &dz->layer->strip.valid, + vips_rect_intersectrect( area, &dz->layer->strip->valid, &overlap ); vips_region_copy( region, dz->layer->strip, &overlap, overlap.left, overlap.top ); @@ -466,7 +489,7 @@ pyramid_strip( VipsRegion *region, VipsRect *area, void *a ) /* If we've filled the strip, write. */ if( VIPS_RECT_BOTTOM( &overlap ) == - VIPS_RECT_BOTTOM( &dz->layer->strip.valid ) && + VIPS_RECT_BOTTOM( &dz->layer->strip->valid ) && strip_arrived( dz->layer ) ) return( -1 ); @@ -482,8 +505,6 @@ vips_foreign_save_dz_build( VipsObject *object ) VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveDz *dz = (VipsForeignSaveDz *) object; - char *p; - if( VIPS_OBJECT_CLASS( vips_foreign_save_dz_parent_class )-> build( object ) ) return( -1 ); @@ -500,15 +521,23 @@ vips_foreign_save_dz_build( VipsObject *object ) return( -1 ); } + if( dz->overlap >= dz->tile_width || + dz->overlap >= dz->tile_height ) { + vips_error( "dzsave", + "%s", _( "overlap must be less than tile " + "width and height" ) ) ; + return( -1 ); + } + /* Build the skeleton of the image pyramid. */ if( !(dz->layer = pyramid_build( dz, - NULL, save->read->Xsize, save->read->Ysize )) ) + NULL, save->ready->Xsize, save->ready->Ysize )) ) return( -1 ); if( pyramid_mkdir( dz ) ) return( -1 ); - if( vips_sink_disc( save->read, pyramid_strip, dz ) ) + if( vips_sink_disc( save->ready, pyramid_strip, dz ) ) return( -1 ); return( 0 ); @@ -532,6 +561,8 @@ static int bandfmt_dz[10] = { UC, C, US, S, UI, I, F, F, D, D }; +const char *dz_suffs[] = { ".dz", NULL }; + static void vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class ) { @@ -548,6 +579,8 @@ vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class ) object_class->description = _( "save image to deep zoom format" ); object_class->build = vips_foreign_save_dz_build; + foreign_class->suffs = dz_suffs; + save_class->saveable = VIPS_SAVEABLE_ANY; save_class->format_table = bandfmt_dz; save_class->coding[VIPS_CODING_LABQ] = TRUE; @@ -571,7 +604,7 @@ vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class ) _( "Tile overlap in pixels" ), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsForeignSaveDz, overlap ), - 1, 1024, 1 ); + 0, 1024, 0 ); VIPS_ARG_INT( class, "tile_width", 11, _( "Tile width" ), @@ -593,7 +626,7 @@ static void vips_foreign_save_dz_init( VipsForeignSaveDz *dz ) { VIPS_SETSTR( dz->suffix, ".jpg" ); - dz->overlap = 1; + dz->overlap = 0; dz->tile_width = 128; dz->tile_height = 128; } diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index f6feaf87..ef64b34a 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2331,7 +2331,7 @@ vips_matload( const char *filename, VipsImage **out, ... ) * Returns: 0 on success, -1 on error. */ int -vips_dzsave( VIpsImage *in, const char *dirname, ... ) +vips_dzsave( VipsImage *in, const char *dirname, ... ) { va_list ap; int result; diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index 6d83b531..b45f7e79 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1199,7 +1199,7 @@ vips_mkdirf( const char *name, ... ) /* Try that. */ - if( !mkdir( buf1, 0755 ) ) { + if( mkdir( buf1, 0755 ) ) { vips_error( "mkdirf", _( "unable to create directory \"%s\", %s" ), buf1, strerror( errno ) );