Skip to content

Commit f499cef

Browse files
committed
add iiif layout to dzsave
1 parent 4cf8246 commit f499cef

File tree

4 files changed

+135
-2
lines changed

4 files changed

+135
-2
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- nifti load/save uses double for all floating point metadata
1818
- add vips_error_buffer_copy()
1919
- add @no_strip option to dzsave [kalozka1]
20+
- add iiif layout to dzsave
2021

2122
31/8/19 started 8.8.3
2223
- revert sharpen restoring the input colourspace

libvips/foreign/dzsave.c

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
* - add @skip_blanks
8484
* 21/10/19
8585
* - add @no_strip
86+
* 9/11/19
87+
* - add IIIF layout
8688
*/
8789

8890
/*
@@ -937,6 +939,86 @@ write_blank( VipsForeignSaveDz *dz )
937939
return( 0 );
938940
}
939941

942+
/* Write IIIF JSON metadata.
943+
*/
944+
static int
945+
write_json( VipsForeignSaveDz *dz )
946+
{
947+
GsfOutput *out;
948+
char buf[VIPS_PATH_MAX];
949+
int i;
950+
951+
out = vips_gsf_path( dz->tree, "info.json", NULL );
952+
953+
gsf_output_printf( out,
954+
"{\n"
955+
" \"@context\": \"http://iiif.io/api/image/2/context.json\",\n"
956+
" \"@id\": \"https://example.com/iiif/apple\",\n"
957+
" \"profile\": [\n"
958+
" \"http://iiif.io/api/image/2/level0.json\",\n"
959+
" {\n"
960+
" \"formats\": [\n"
961+
" \"jpg\"\n"
962+
" ],\n"
963+
" \"qualities\": [\n"
964+
" \"default\"\n"
965+
" ]\n"
966+
" }\n"
967+
" ],\n"
968+
" \"protocol\": \"http://iiif.io/api/image\",\n"
969+
" \"sizes\": [\n" );
970+
971+
for( i = 0; i < dz->layer->n + 5; i++ ) {
972+
gsf_output_printf( out,
973+
" {\n"
974+
" \"width\": %d,\n"
975+
" \"height\": \"full\"\n"
976+
" }",
977+
1 << (i + 4) );
978+
if( i != dz->layer->n - 4 )
979+
gsf_output_printf( out, "," );
980+
gsf_output_printf( out, "\n" );
981+
}
982+
983+
gsf_output_printf( out,
984+
" ],\n" );
985+
986+
gsf_output_printf( out,
987+
" \"tiles\": [\n"
988+
" {\n"
989+
" \"scalefactors\": [\n" );
990+
991+
for( i = 0; i < dz->layer->n; i++ ) {
992+
gsf_output_printf( out,
993+
" %d",
994+
1 << i );
995+
if( i != dz->layer->n - 1 )
996+
gsf_output_printf( out, "," );
997+
gsf_output_printf( out, "\n" );
998+
}
999+
1000+
gsf_output_printf( out,
1001+
" ],\n"
1002+
" \"width\": %d\n"
1003+
" }\n"
1004+
" ],\n", dz->tile_size );
1005+
1006+
gsf_output_printf( out,
1007+
" \"width\": %d,\n"
1008+
" \"height\": %d\n",
1009+
dz->layer->image->Xsize,
1010+
dz->layer->image->Ysize );
1011+
1012+
gsf_output_printf( out,
1013+
"}\n" );
1014+
1015+
(void) gsf_output_close( out );
1016+
g_object_unref( out );
1017+
1018+
return( 0 );
1019+
}
1020+
1021+
9401022
static int
9411023
write_vips_meta( VipsForeignSaveDz *dz )
9421024
{
@@ -1306,6 +1388,40 @@ tile_name( Layer *layer, int x, int y )
13061388

13071389
break;
13081390

1391+
case VIPS_FOREIGN_DZ_LAYOUT_IIIF:
1392+
{
1393+
/* Tiles are addressed in full resolution coordinates, so
1394+
* scale up by layer->sub and dz->tile_size
1395+
*/
1396+
int left = x * dz->tile_size * layer->sub;
1397+
int top = y * dz->tile_size * layer->sub;
1398+
int width = VIPS_MIN( dz->tile_size * layer->sub,
1399+
layer->width * layer->sub - left );
1400+
int height = VIPS_MIN( dz->tile_size * layer->sub,
1401+
layer->height * layer->sub - top );
1402+
1403+
/* IIIF "size" is just real tile width, I think.
1404+
*
1405+
* TODO .. .is this right? shouldn't it be the smaller of
1406+
* width and height?
1407+
*/
1408+
int size = VIPS_MIN( dz->tile_size,
1409+
layer->width - x * dz->tile_size );
1410+
1411+
vips_snprintf( dirname, VIPS_PATH_MAX, "%d,%d,%d,%d",
1412+
left, top, width, height );
1413+
vips_snprintf( dirname2, VIPS_PATH_MAX, "%d,", size );
1414+
vips_snprintf( name, VIPS_PATH_MAX, "default%s",
1415+
dz->file_suffix );
1416+
1417+
/* "0" is rotation and is always 0.
1418+
*/
1419+
out = vips_gsf_path( dz->tree,
1420+
name, dirname, dirname2, "0", NULL );
1421+
}
1422+
1423+
break;
1424+
13091425
default:
13101426
g_assert_not_reached();
13111427

@@ -1814,10 +1930,11 @@ vips_foreign_save_dz_build( VipsObject *object )
18141930
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz );
18151931
VipsRect real_pixels;
18161932

1817-
/* Google and zoomify default to zero overlap, ".jpg".
1933+
/* Google, zoomify and iiif default to zero overlap, ".jpg".
18181934
*/
18191935
if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY ||
1820-
dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE ) {
1936+
dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE ||
1937+
dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF ) {
18211938
if( !vips_object_argument_isset( object, "overlap" ) )
18221939
dz->overlap = 0;
18231940
if( !vips_object_argument_isset( object, "suffix" ) )
@@ -1832,6 +1949,13 @@ vips_foreign_save_dz_build( VipsObject *object )
18321949
dz->tile_size = 256;
18331950
}
18341951

1952+
/* Some iif writers default to 256, some to 512. We pick 512.
1953+
*/
1954+
if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF ) {
1955+
if( !vips_object_argument_isset( object, "tile_size" ) )
1956+
dz->tile_size = 512;
1957+
}
1958+
18351959
/* skip_blanks defaults to 5 in google mode.
18361960
*/
18371961
if( dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE &&
@@ -2136,6 +2260,11 @@ vips_foreign_save_dz_build( VipsObject *object )
21362260
return( -1 );
21372261
break;
21382262

2263+
case VIPS_FOREIGN_DZ_LAYOUT_IIIF:
2264+
if( write_json( dz ) )
2265+
return( -1 );
2266+
break;
2267+
21392268
default:
21402269
g_assert_not_reached();
21412270
}

libvips/include/vips/foreign.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,13 +588,15 @@ int vips_niftisave( VipsImage *in, const char *filename, ... )
588588
* @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout
589589
* @VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY: use Zoomify directory layout
590590
* @VIPS_FOREIGN_DZ_LAYOUT_GOOGLE: use Google maps directory layout
591+
* @VIPS_FOREIGN_DZ_LAYOUT_IIIF: use IIIF directory layout
591592
*
592593
* What directory layout and metadata standard to use.
593594
*/
594595
typedef enum {
595596
VIPS_FOREIGN_DZ_LAYOUT_DZ,
596597
VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY,
597598
VIPS_FOREIGN_DZ_LAYOUT_GOOGLE,
599+
VIPS_FOREIGN_DZ_LAYOUT_IIIF,
598600
VIPS_FOREIGN_DZ_LAYOUT_LAST
599601
} VipsForeignDzLayout;
600602

libvips/iofuncs/enumtypes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ vips_foreign_dz_layout_get_type( void )
612612
{VIPS_FOREIGN_DZ_LAYOUT_DZ, "VIPS_FOREIGN_DZ_LAYOUT_DZ", "dz"},
613613
{VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY, "VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY", "zoomify"},
614614
{VIPS_FOREIGN_DZ_LAYOUT_GOOGLE, "VIPS_FOREIGN_DZ_LAYOUT_GOOGLE", "google"},
615+
{VIPS_FOREIGN_DZ_LAYOUT_IIIF, "VIPS_FOREIGN_DZ_LAYOUT_IIIF", "iiif"},
615616
{VIPS_FOREIGN_DZ_LAYOUT_LAST, "VIPS_FOREIGN_DZ_LAYOUT_LAST", "last"},
616617
{0, NULL, NULL}
617618
};

0 commit comments

Comments
 (0)