Permalink
Browse files

works!

  • Loading branch information...
1 parent eda3762 commit a2d512af73abcfd677d1371b393d966328740986 @jcupitt committed Mar 26, 2012
Showing with 127 additions and 30 deletions.
  1. +1 −0 ChangeLog
  2. +63 −0 acinclude.m4
  3. +61 −28 libvips/foreign/dzsave.c
  4. +1 −1 libvips/foreign/foreign.c
  5. +1 −1 libvips/iofuncs/util.c
View
@@ -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
View
@@ -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 <adl@gnu.org>
+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 <sys/stat.h>
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#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).
View
@@ -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,15 +481,15 @@ 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 );
/* 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;
}
@@ -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;
View
@@ -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 ) );

0 comments on commit a2d512a

Please sign in to comment.