Deepzoom into OpenLayers images using zoomify

1.1k views Asked by At

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

There are 1 answers

0
Ganesh Rathinavel On

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);
});