Mercurial > hg > orthanc-wsi
changeset 274:2805246064aa iiif
added SetIIIFForcePowersOfTwoScaleFactors()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 12 Jul 2023 11:24:56 +0200 |
parents | 1c95010d9d2e |
children | 801790c81f20 |
files | Resources/TestIIIFTiles.py ViewerPlugin/IIIF.cpp ViewerPlugin/IIIF.h ViewerPlugin/Plugin.cpp |
diffstat | 4 files changed, 117 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/TestIIIFTiles.py Wed Jul 12 11:24:56 2023 +0200 @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import requests +import sys + +if len(sys.argv) != 2: + print('Usage: %s <URL to info.json>' % sys.argv[0]) + exit(-1) + +r = requests.get(sys.argv[1]) +r.raise_for_status() + +info = r.json() + +assert(len(info['tiles']) == 1) +assert(len(info['tiles'][0]['scaleFactors']) == len(info['sizes'])) + +width = None +height = None +for size in info['sizes']: + if (width == None or + size['width'] > width): + width = size['width'] + height = size['height'] + +tw = info['tiles'][0]['width'] +th = info['tiles'][0]['height'] + +assert(isinstance(width, int)) +assert(isinstance(height, int)) +assert(isinstance(tw, int)) +assert(isinstance(th, int)) + +def CeilingDivision(a, b): + if a % b == 0: + return a // b + else: + return a // b + 1 + +for s in info['tiles'][0]['scaleFactors']: + assert(isinstance(s, int)) + + countTilesX = CeilingDivision(width, tw * s) + countTilesY = CeilingDivision(height, th * s) + print(tw * s, th * s, countTilesX, countTilesY) + + for m in range(countTilesY): + for n in range(countTilesX): + + # Reference: + # https://iiif.io/api/image/3.0/implementation/#3-tile-region-parameter-calculation + + # Calculate region parameters /xr,yr,wr,hr/ + xr = n * tw * s + yr = m * th * s + wr = tw * s + if (xr + wr > width): + wr = width - xr + hr = th * s + if (yr + hr > height): + hr = height - yr + + # Calculate size parameters /ws,hs/ + ws = tw + if (xr + tw*s > width): + ws = (width - xr + s - 1) / s # +s-1 in numerator to round up + hs = th + if (yr + th*s > height): + hs = (height - yr + s - 1) / s + + url = '%s/%d,%d,%d,%d/%d,%d/0/default.jpg' % (info['id'], xr, yr, wr, hr, ws, hs) + r = requests.get(url) + + if r.status_code == 200: + print('SUCCESS: %s' % url) + else: + print('ERROR: %s' % url)
--- a/ViewerPlugin/IIIF.cpp Wed Jul 12 08:48:16 2023 +0200 +++ b/ViewerPlugin/IIIF.cpp Wed Jul 12 11:24:56 2023 +0200 @@ -40,6 +40,7 @@ static std::string iiifPublicUrl_; +static bool iiifForcePowersOfTwoScaleFactors_ = false; static void ServeIIIFTiledImageInfo(OrthancPluginRestOutput* output, @@ -77,7 +78,9 @@ Json::Value sizes = Json::arrayValue; Json::Value scaleFactors = Json::arrayValue; - for (unsigned int i = pyramid.GetLevelCount(); i > 0; i--) + unsigned int power = 1; + + for (unsigned int i = 0; i < pyramid.GetLevelCount(); i++) { /** * According to the IIIF Image API 3.0 specification, @@ -90,16 +93,28 @@ * width/height of the image is divisible by the width/height of * the level. **/ - if (pyramid.GetLevelWidth(0) % pyramid.GetLevelWidth(i - 1) == 0 && - pyramid.GetLevelHeight(0) % pyramid.GetLevelHeight(i - 1) == 0) + if (pyramid.GetLevelWidth(0) % pyramid.GetLevelWidth(i) == 0 && + pyramid.GetLevelHeight(0) % pyramid.GetLevelHeight(i) == 0) { - Json::Value level; - level["width"] = pyramid.GetLevelWidth(i - 1); - level["height"] = pyramid.GetLevelHeight(i - 1); - sizes.append(level); + unsigned int scaleFactor = pyramid.GetLevelWidth(0) / pyramid.GetLevelWidth(i); + + if (!iiifForcePowersOfTwoScaleFactors_ || + scaleFactor == power) + { + Json::Value level; + level["width"] = pyramid.GetLevelWidth(i); + level["height"] = pyramid.GetLevelHeight(i); + sizes.append(level); - scaleFactors.append(pyramid.GetLevelWidth(0) / - pyramid.GetLevelWidth(i - 1)); + scaleFactors.append(scaleFactor); + + power *= 2; + } + else + { + LOG(WARNING) << "IIIF - Dropping level " << i << " of series " << seriesId + << ", as it doesn't follow the powers-of-two pattern"; + } } else { @@ -107,7 +122,7 @@ << ", as the full width/height (" << pyramid.GetLevelWidth(0) << "x" << pyramid.GetLevelHeight(0) << ") of the image is not an integer multiple of the level width/height (" - << pyramid.GetLevelWidth(i - 1) << "x" << pyramid.GetLevelHeight(i - 1) << ")"; + << pyramid.GetLevelWidth(i) << "x" << pyramid.GetLevelHeight(i) << ")"; } } @@ -234,7 +249,7 @@ !Orthanc::SerializationToolbox::ParseUnsignedInteger32(regionWidth, tokens[2]) || !Orthanc::SerializationToolbox::ParseUnsignedInteger32(regionHeight, tokens[3])) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "IIIF - Not a (x,y,width,height) region, found: " + region); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "IIIF - Invalid (x,y,width,height) region, found: " + region); } uint32_t cropWidth, cropHeight; @@ -258,7 +273,7 @@ if (!ok) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "IIIF - Not a (width,height) crop, found: " + size); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "IIIF - Invalid (width,height) crop, found: " + size); } std::unique_ptr<OrthancWSI::RawTile> rawTile; @@ -602,3 +617,8 @@ OrthancPlugins::RegisterRestCallback<ServeIIIFFrameInfo>("/wsi/iiif/frames/([0-9a-f-]+)/([0-9]+)/info.json", true); OrthancPlugins::RegisterRestCallback<ServeIIIFFrameImage>("/wsi/iiif/frames/([0-9a-f-]+)/([0-9]+)/full/max/0/default.jpg", true); } + +void SetIIIFForcePowersOfTwoScaleFactors(bool force) +{ + iiifForcePowersOfTwoScaleFactors_ = force; +}
--- a/ViewerPlugin/IIIF.h Wed Jul 12 08:48:16 2023 +0200 +++ b/ViewerPlugin/IIIF.h Wed Jul 12 11:24:56 2023 +0200 @@ -25,3 +25,10 @@ #include <string> void InitializeIIIF(const std::string& iiifPublicUrl); + +/** + * Filter pyramids whose level sizes don't follow a powers-of-two + * pattern. This can be used to bypass issue 2379 on OpenSeadragon <= + * 4.1: https://github.com/openseadragon/openseadragon/issues/2379 + **/ +void SetIIIFForcePowersOfTwoScaleFactors(bool force);
--- a/ViewerPlugin/Plugin.cpp Wed Jul 12 08:48:16 2023 +0200 +++ b/ViewerPlugin/Plugin.cpp Wed Jul 12 11:24:56 2023 +0200 @@ -310,6 +310,7 @@ } InitializeIIIF(iiifPublicUrl); + SetIIIFForcePowersOfTwoScaleFactors(true); // TODO => CONFIG serveMirador = true; // TODO => CONFIG serveOpenSeadragon = true; // TODO => CONFIG