-
-
Notifications
You must be signed in to change notification settings - Fork 698
support IIIF layout in dzsave #1465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Sample script by kjell to rename function getMaxZoom(imageSize, tileSize) {
let { x, y } = imageSize
return Math.ceil(Math.log(Math.max(x, y) / tileSize) / Math.LN2)
}
function zyxToIIIF(z, y, x, imageSize, tileSize = 512) {
let { x: imageWidth, y: imageHeight } = imageSize
let maxZoom = getMaxZoom(imageSize, tileSize)
let scale = Math.pow(2, maxZoom - z)
let tileBaseSize = tileSize * scale
let minx = x * tileBaseSize,
miny = y * tileBaseSize,
maxx = Math.min(minx + tileBaseSize, imageWidth),
maxy = Math.min(miny + tileBaseSize, imageHeight)
let xDiff = maxx - minx
let yDiff = maxy - miny
let size = Math.ceil(xDiff / scale)
let region = [minx, miny, xDiff, yDiff].join(',')
let iiif = `/${region}/${size},/0/color.jpg`
return iiif
}
module.exports = {
zyxToIIIF,
getMaxZoom,
}
if (!module.parent) {
// If this is being run directly and not `require()`d…
const fs = require('fs-extra')
const sharp = require('sharp')
function getNumericDirs(src) {
return fs
.readdirSync(src)
.filter(dir => dir === '0' || dir === '0.jpg' || parseInt(dir))
.sort((a, b) => a.replace('.jpg', '') - b.replace('.jpg', ''))
}
const src = process.argv[2]
/* TODO
* generate `info.json`
* how to get image dimensions for an existing directory of tiles?
* what to do when created files exist already: error?
* split this into smaller files
*/
function convertZyxTilesToIIIF(dir) {
const imageSize = { x: 25616, y: 12341 } // TODO dont hardcode
const zooms = getNumericDirs(dir)
zooms.map((z, zoomIndex) => {
getNumericDirs(`./${dir}/${z}`).map(y => {
getNumericDirs(`./${dir}/${z}/${y}`).map(xFile => {
const [x, ext] = xFile.split('.')
const iiif = zyxToIIIF(z, y, x, imageSize)
const _src = `${dir}/${z}/${y}/${x}.jpg`
const dest = `${dir}-iiif${iiif}`
fs.ensureDir(dest.replace('/color.jpg', ''), err => {
err
? console.error(err)
: fs.copy(_src, dest, err => {
err ? console.error(err) : console.info('.')
})
})
})
})
})
}
function tileImageAndConvert(src) {
const output = 'out'
const image = sharp(src)
const metadata = image
.metadata()
.then(meta => {
const imageSize = { x: meta.width, y: meta.height }
image
.limitInputPixels(false)
.tile({ layout: 'google', size: 512 })
.toFile(output, (err, info) => {
console.info('tiled', { err, info })
convertZyxTilesToIIIF(output)
})
})
.catch(err => console.error(err))
}
src.match(/.jpg/) ? tileImageAndConvert(src) : convertZyxTilesToIIIF(src)
} |
I am super interested in seeing this happen, but haven't gotten back to it since last year! I have the exact opposite of a tiny image laying around: https://cdn.dx.artsmia.org/barbari-map-iiif-vips/index.html. Here's one that's a bit more manageable https://cdn.dx.artsmia.org/barbari-map-iiif-vips/5887.html |
The interesting thing about IIIF is that it provides a descriptive API to generate derivatives of a master image without needing to pre-render everything, so at a higher level it would be interesting to see how hard it is to build the full (or something more than "level 0", as the full API can get involved) IIIF spec into vips. The IIIF "image api" uses https://github.com/cmoa/iiif_s3 is a ruby library that can be looked to as a much more comprehensive example than my script above for building a "level 0" compliant IIIF resource. It amounts to calculating what region/size parameters are needed to create the pyramidal tiles then saving them out to disk. Beyond implementing IIIF as an output format for generating tiles, implementing IIIF's notion of |
other similar tools to look at: |
However edsilv/biiif doesn't cut tiles, which is partly why it would be useful if libvips did! |
Hi @kjell ! I saw your nice map example, but what does the precomputed pyramid look like? dzsave is just for making precomputed pyramids, so I'd need a sample pyramid to look at, I think. Doing on-the-fly tiling is harder, of course. I did I tiny thing called https://github.com/jcupitt/tilesrv It can serve openslide images to deepzoom viewers and makes tiles and levels on the fly. It won't scale so well though -- more than a few 10s of clients on one server and it'll crawl. Back in the 90s I did the first version of iipimage, and I think Ruven now supports iiif clients. But I don't think he uses libvips. |
It's pretty much what you said up top: "google-like, don't pad edge tiles, name tiles differently." The precomputed pyramid files will look something like this:
The tiles are still
|
Ah I think I see. Is the |
I has a quick go: On this laptop I see:
So 2.8s and a max of 110mb of ram for a 9300 x 9300 pixel jpg image. It creates I don't think I'm making |
better info.json, but still not support for the full/ directory see #1465
I cleaned up the There's still no Speed is in line with the other layouts. For a 10k x 10k pixel RGB JPG with the very nice
ie. 1.4gb of memory and 59s of time. With
ie. 180mb of memory and 0.94s. |
tried on macos , awesome 🎉 i had to manually fix @id in info.json, this should be an optional argument in command line maybe
|
It could put the "x" output directory name into the |
(thanks for testing it, by the way!) |
It now adds the basename to the json It supports a couple of other useful features. You can set the tile format like this: vips dzsave img00152.jpg x --layout iiif --suffix .png and it'll set the You can output directly to zips:
And you can record all the image metadata:
It can be handy to have a record of all image metadata for (for example) virtual slide images. |
Apologies late to this ticket, am very interested in making use of this feature, but it would really need the full region to be created for compliance with viewers (see https://iiif.io/api/image/3.0/compliance/#3-image-parameters). Good examples from Tom Crane to illustrate this here: https://tomcrane.github.io/scratch/osd/iiif-sizes.html |
Hi @atiro, I opened an enhancement issue for this feature. |
@edsu It does now :-) https://github.com/IIIF-Commons/biiif-template |
Hi. Is there any update/branch/PR on iiif support in libvips? |
Yes, it was released three years ago in libvips 8.9 and has been improved a couple of times since. It supports IIIF3 now. It's still missing the |
I too need to rewrite the id attribute in the info.json file. It would indeed be very neat if there were an option in the command line to set the id to the right place. |
That's been supported since 8.10, @peterrobinson. Just set the https://www.libvips.org/API/current/VipsForeignSave.html#vips-dzsave |
Yes, I discovered that after I wrote the message. Very helpful. |
dzsave currently supports google maps, zoomify and deepzoom tile layouts.
Another popular tile naming convention is IIIF, see:
go-iiif/go-iiif#20 (comment)
lovell/sharp#1335
@kjell do you have a tiny sample image in the IIIF format handy?
It looks like
--layout=iiif
would be google-like, but not pad edge tiles, and would name tiles differently.The text was updated successfully, but these errors were encountered: