diff --git a/ChangeLog b/ChangeLog index a1d2c8af82..1c7f955811 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ master - text: prevent use of rgba subpixel anti-aliasing [lovell] - tiffsave: always apply resolution unit conversion [kleisauke] - cache: suppress invalidation errors in release builds [kleisauke] +- dzsave: IIIF: use named region of 'full' when no crop takes place [lovell] 5/6/25 8.17.0 diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 6ca34c45f3..1fe0b2d84b 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -1212,6 +1212,9 @@ tile_name(Level *level, int x, int y) save->ready->Xsize - left); int height = VIPS_MIN(dz->tile_size * level->sub, save->ready->Ysize - top); + gboolean is_region_full = left == 0 && top == 0 && + width == save->ready->Xsize && + height == save->ready->Ysize; /* Rotation is always 0. */ @@ -1223,11 +1226,17 @@ tile_name(Level *level, int x, int y) int ysize = VIPS_MIN(dz->tile_size, level->height - y * dz->tile_size); - g_snprintf(subdir, VIPS_PATH_MAX, - "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d,%d" G_DIR_SEPARATOR_S "%d", - left, top, width, height, - xsize, ysize, - rotation); + if (is_region_full) + g_snprintf(subdir, VIPS_PATH_MAX, + "full" G_DIR_SEPARATOR_S "%d,%d" G_DIR_SEPARATOR_S "%d", + xsize, ysize, + rotation); + else + g_snprintf(subdir, VIPS_PATH_MAX, + "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d,%d" G_DIR_SEPARATOR_S "%d", + left, top, width, height, + xsize, ysize, + rotation); } else { /* IIIF2 "size" is just real tile width, I think. @@ -1235,11 +1244,17 @@ tile_name(Level *level, int x, int y) int size = VIPS_MIN(dz->tile_size, level->width - x * dz->tile_size); - g_snprintf(subdir, VIPS_PATH_MAX, - "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d," G_DIR_SEPARATOR_S "%d", - left, top, width, height, - size, - rotation); + if (is_region_full) + g_snprintf(subdir, VIPS_PATH_MAX, + "full" G_DIR_SEPARATOR_S "%d," G_DIR_SEPARATOR_S "%d", + size, + rotation); + else + g_snprintf(subdir, VIPS_PATH_MAX, + "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d," G_DIR_SEPARATOR_S "%d", + left, top, width, height, + size, + rotation); } g_snprintf(name, VIPS_PATH_MAX, "default%s", dz->file_suffix); diff --git a/test/test-suite/test_foreign.py b/test/test-suite/test_foreign.py index d20e403947..efc8cbae3f 100644 --- a/test/test-suite/test_foreign.py +++ b/test/test-suite/test_foreign.py @@ -1407,6 +1407,27 @@ def test_dzsave(self): assert x.width == 256 assert x.height == 256 + # IIIF v2 + im = pyvips.Image.black(3509, 2506, bands=3) + filename = temp_filename(self.tempdir, '') + im.dzsave(filename, layout="iiif") + assert os.path.exists(filename + "/info.json") + assert os.path.exists(filename + "/0,0,512,512/512,/0/default.jpg") + assert os.path.exists(filename + "/2560,2048,512,458/512,/0/default.jpg") + x = pyvips.Image.new_from_file(filename + "/full/439,/0/default.jpg") + assert x.width == 439 + assert x.height == 314 + + # IIIF v3 + filename = temp_filename(self.tempdir, '') + im.dzsave(filename, layout="iiif3") + assert os.path.exists(filename + "/info.json") + assert os.path.exists(filename + "/0,0,512,512/512,512/0/default.jpg") + assert os.path.exists(filename + "/2560,2048,512,458/512,458/0/default.jpg") + x = pyvips.Image.new_from_file(filename + "/full/439,314/0/default.jpg") + assert x.width == 439 + assert x.height == 314 + # test zip output filename = temp_filename(self.tempdir, '.zip') self.colour.dzsave(filename)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: