This commit is contained in:
John Cupitt 2012-03-26 22:08:59 +01:00
parent eda3762fba
commit a2d512af73
5 changed files with 127 additions and 30 deletions

View File

@ -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 File

@ -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 File

@ -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;
}

View File

@ -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 File

@ -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 ) );