Deepzoom into OpenLayers images using zoomify

How do I deepzoom into OpenLayers images using Zoomify?

Taking cues from the answer How to display high resolution image in browser using openlayers, I was able to implement the zooming function but the maxZoom does not work here and I am unable zoom further into the image.

DZI image parser

function loadUrl(url, opt_options) {
  const options = opt_options || {};
  const crossOrigin =
    options.crossOrigin === undefined ? 'anonymous' : options.crossOrigin;

  const layer = new ol.layer.Tile();

  const last = url.lastIndexOf('.');
  const path = url.slice(0, last);

  const xhr = new XMLHttpRequest();

  let width;
  let height;

  xhr.open('GET', url);
  xhr.onload = function() {
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xhr.responseText, 'text/xml');

    const elements = xmlDoc.getElementsByTagName('Image');
    const tileSize = Number(elements[0].getAttribute('TileSize'));
    const format = elements[0].getAttribute('Format');

    width = Number(
      elements[0].getElementsByTagName('Size')[0].getAttribute('Width')
    );
    height = Number(
      elements[0].getElementsByTagName('Size')[0].getAttribute('Height')
    );
    const url = `${path}_files/{z}/{x}_{y}.${format}`;

    const source = new ol.source.Zoomify({
      url,
      size: [width, height],
      tileSize,
      crossOrigin
    });

    const offset = Math.ceil(Math.log(tileSize) / Math.LN2);

    source.setTileUrlFunction(function(tileCoord) {
      return url
        .replace('{z}', tileCoord[0] + offset)
        .replace('{x}', tileCoord[1])
        .replace('{y}', -(tileCoord[2] + 1));
    });

    layer.setExtent([0, -height, width, 0]);
    layer.setSource(source);
  };

  xhr.send();

  return {
    layer,
    width,
    height
  };
}

Map Object

const map = new ol.Map({
  target: 'map',
  logo: false
});

const { layer } = loadUrl(
  'https://openseadragon.github.io/example-images/duomo/duomo.dzi'
);

layer.on('change:source', function(evt) {
  map.setView(
    new ol.View({
      resolutions: layer.getSource().getTileGrid().getResolutions(),
      extent: layer.getExtent(),
      zoom: 5,
      maxZoom: 30
    })
  );
  map.getView().fit(layer.getExtent(), { size: map.getSize() });
});

map.addLayer(layer);

How do I remove the zoom constraints?

1 answer

  • answered 2019-10-22 08:31 Ganesh Rathinavel

    I have figured it out.

    Code for the same:

    function loadUrl(url) {
      return new Promise(resolve => {
        const layer = new ol.layer.Tile();
    
        const last = url.lastIndexOf('.');
        const path = url.slice(0, last);
    
        const xhr = new XMLHttpRequest();
    
        let width = 0;
        let height = 0;
    
        xhr.open('GET', url);
        xhr.onload = () => {
          const parser = new DOMParser();
          const xmlDoc = parser.parseFromString(xhr.responseText, 'text/xml');
    
          const elements = xmlDoc.getElementsByTagName('Image');
          const tileSize = Number(elements[0].getAttribute('TileSize'));
          const format = elements[0].getAttribute('Format');
    
          width = Number(
            elements[0].getElementsByTagName('Size')[0].getAttribute('Width')
          );
          height = Number(
            elements[0].getElementsByTagName('Size')[0].getAttribute('Height')
          );
    
          const formattedUrl = `${path}_files/{z}/{x}_{y}.${format}`;
    
          const offset = Math.ceil(Math.log(tileSize) / Math.LN2);
    
          return resolve({
            url: formattedUrl,
            offset,
            layer,
            imgWidth: width,
            imgHeight: height,
            tileSize
          });
        };
    
        xhr.send();
      });
    }
    
    function run(url, imgWidth, imgHeight, offset, tileSize) {
      const imgCenter = [imgWidth / 2, -imgHeight / 2];
    
      // Maps always need a projection, but Zoomify layers are not geo-referenced, and
      // are only measured in pixels.  So, we create a fake projection that the map
      // can use to properly display the layer.
      const proj = new ol.proj.Projection({
        code: 'ZOOMIFY',
        units: 'pixels',
        extent: [0, 0, imgWidth, imgHeight]
      });
    
      const layer = new ol.layer.Tile({
        source: new ol.source.Zoomify({
          url,
          size: [imgWidth, imgHeight],
          tileSize,
          crossOrigin: 'anonymous'
        })
      });
    
      layer.getSource().setTileUrlFunction(tileCoord => {
        return url
          .replace('{z}', tileCoord[0] + offset)
          .replace('{x}', tileCoord[1])
          .replace('{y}', -(tileCoord[2] + 1));
      });
    
      const map = new ol.Map({
        layers: [layer],
        target: 'map',
        view: new ol.View({
          projection: proj,
          center: imgCenter,
          zoom: 0,
          extent: [0, -imgHeight, imgWidth, 0]
        })
      });
    }
    
    const nwurl =
      'https://openseadragon.github.io/example-images/duomo/duomo.dzi';
    
    loadUrl(nwurl).then(res => {
      const { url, offset, imgWidth, imgHeight, tileSize } = res;
    
      run(url, imgWidth, imgHeight, offset, tileSize);
    });