如何使用openlayers在浏览器中显示高分辨率图像

How to display high resolution image in browser using openlayers

我正在尝试使用 openlayers 5 在浏览器中显示高分辨率图像。我找到了一个关于如何使用 zoomify 创建图像块并使用 openlayers 地图渲染它的示例。但我无法将它用于我自己的形象。我对此完全陌生。我问的问题可能很琐碎。请原谅我的无知

Example code - This is the example from openlayers website. I am trying to do the same with this image 我尝试用我的图像替换 zoomifyUrl 和 iipUrl url 但它没有用。

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import Zoomify from 'ol/source/Zoomify.js';

var imgWidth = 799;
var imgHeight = 586;

var zoomifyUrl = 'https://live.staticflickr.com/8173/7993440342_5d9c68faec_c.jpg';
var iipUrl = 'https://live.staticflickr.com/8173/7993440342_5d9c68faec_c.jpg' + '&JTL={z},{tileIndex}';

var layer = new TileLayer({
  source: new Zoomify({
    url: zoomifyUrl,
    size: [imgWidth, imgHeight],
    crossOrigin: 'anonymous'
  })
});

var extent = [0, -imgHeight, imgWidth, 0];

var map = new Map({
  layers: [layer],
  target: 'map',
  view: new View({
    // adjust zoom levels to those provided by the source
    resolutions: layer.getSource().getTileGrid().getResolutions(),
    // constrain the center: center cannot be set outside this extent
    extent: extent
  })
});
map.getView().fit(extent);

var control = document.getElementById('zoomifyProtocol');
control.addEventListener('change', function(event) {
  var value = event.currentTarget.value;
  if (value === 'iip') {
    layer.setSource(new Zoomify({
      url: iipUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: 'anonymous'
    }));
  } else if (value === 'zoomify') {
    layer.setSource(new Zoomify({
      url: zoomifyUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: 'anonymous'
    }));
  }

});

我想实现类似 openseadragon website 中的演示的东西。更改上述代码后,我得到了一个重复了一部分图像的网格。

要使用 Zoomify,您需要一个支持图像作为图块的服务器。您正在使用的 url 是 flickr 上的静态图像,OpenLayers 需要将其作为 ImageStatic 进行处理。这是使用来自 flickr

的最高分辨率图像的代码

  var extent = [0, 0, 10000, 7328];
  var resolutions = [64, 32, 16, 8, 4, 2, 1];

  var layer = new ol.layer.Image({
    source: new ol.source.ImageStatic({
      url: 'https://live.staticflickr.com/8173/7993440342_6a1f281898_o_d.jpg',
      imageExtent: extent
    })
  });

  var map = new ol.Map({
    layers: [layer],
    target: 'map',
    view: new ol.View({
      // adjust zoom levels to those provided by the source
      resolutions: resolutions,
      // constrain the center: center cannot be set outside this extent
      extent: extent
    })
  });
  map.getView().fit(extent);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

或者您可以 link 到 OpenSeadragon 使用的 url。奇怪的是,缩放级别 运行 从 8 到 14,一个图块在第 8 层,一个 55 x 41 的网格在第 14 层,其中最右边一列的图块宽 206 像素,底行的图块高 41 像素。可以使用 Zoomify,但需要自定义平铺 url 函数才能将 8 添加到 OpenLayers 预期的缩放级别。

  var imgWidth = 54*256 + 206;
  var imgHeight = 40*256 + 41;

  var zoomifyUrl = 'https://openseadragon.github.io/example-images/duomo/duomo_files/{z}/{x}_{y}.jpg';

  var layer = new ol.layer.Tile({
    source: new ol.source.Zoomify({
      url: zoomifyUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: 'anonymous'
    })
  });

  layer.getSource().setTileUrlFunction(function(tileCoord) {
    return zoomifyUrl.replace(
      '{z}', tileCoord[0]+8
    ).replace(
      '{x}', tileCoord[1]
    ).replace(
      '{y}', -(tileCoord[2]+1)
    );
  });

  var extent = [0, -imgHeight, imgWidth, 0];

  var map = new ol.Map({
    layers: [layer],
    target: 'map',
    view: new ol.View({
      // adjust zoom levels to those provided by the source
      resolutions: layer.getSource().getTileGrid().getResolutions(),
      // constrain the center: center cannot be set outside this extent
      extent: extent
    })
  });
  map.getView().fit(extent);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

查看该尝试的结果,很明显有些图块只有 255px 而不是标准的 256,这导致输出中出现白线。我添加了一个自定义的图块加载函数,将 255px 的宽度或高度拉伸到 256(但它不能在右侧和底部边缘拉伸图块,这可能小于 255px)。

  var imgWidth = 54*256 + 206;
  var imgHeight = 40*256 + 41;

  var zoomifyUrl = 'https://openseadragon.github.io/example-images/duomo/duomo_files/{z}/{x}_{y}.jpg';

  var layer = new ol.layer.Tile({
    source: new ol.source.Zoomify({
      url: zoomifyUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: 'anonymous'
    })
  });

  layer.getSource().setTileUrlFunction(function(tileCoord) {
    return zoomifyUrl.replace(
      '{z}', tileCoord[0]+8
    ).replace(
      '{x}', tileCoord[1]
    ).replace(
      '{y}', -(tileCoord[2]+1)
    );
  });

  var tileSize = ol.size.toSize(layer.getSource().getTileGrid().getTileSize(0));

  layer.getSource().setTileLoadFunction(function(imageTile, src) {
    var img = document.createElement('img');
    img.onload = function() {
      var width = img.naturalWidth >= tileSize[0]-1 ? tileSize[0] : img.naturalWidth;
      var height = img.naturalHeight >= tileSize[1]-1 ? tileSize[1] : img.naturalHeight;
      var canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;
      var ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0, width, height);
      imageTile.getImage().src = canvas.toDataURL();
    };
    img.crossOrigin = 'anonymous';
    img.src = src;
  });

  var extent = [0, -imgHeight, imgWidth, 0];

  var map = new ol.Map({
    layers: [layer],
    target: 'map',
    view: new ol.View({
      // adjust zoom levels to those provided by the source
      resolutions: layer.getSource().getTileGrid().getResolutions(),
      // constrain the center: center cannot be set outside this extent
      extent: extent
    })
  });
  map.getView().fit(extent);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

使用天珠 XML 解析器:

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

var layer = dzi.loadUrl(
    'https://openseadragon.github.io/example-images/duomo/duomo.dzi',
    { attributions: 'Image &copy 2012, <a href="https://www.flickr.com/photos/projectese/" target="_blank">Dario Morelli</a>' }
);

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

map.addLayer(layer);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script>

dzi = function() {

function loadUrl ( url,
                   opt_options  // attributions (defaults to undefined), crossOrigin (defaults to 'anonymous')
) {

    var options = opt_options || {};
    var crossOrigin = options.crossOrigin === undefined ? 'anonymous' : options.crossOrigin;

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

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

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = function() {

        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(xhr.responseText,'text/xml');

        var elements = xmlDoc.getElementsByTagName('Image');
        var tileSize = Number(elements[0].getAttribute('TileSize'));
        var format = elements[0].getAttribute('Format');
        var width = Number(elements[0].getElementsByTagName('Size')[0].getAttribute('Width'));
        var height = Number(elements[0].getElementsByTagName('Size')[0].getAttribute('Height'));
        var url = path + '_files/{z}/{x}_{y}.' + format;

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

        var 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;

}

return {
   "loadUrl" : loadUrl
}

} ();

</script>
<div id="map" class="map"></div>

以上回答有两个问题:

  • zoomify 中不支持 deepzoom
  • 瓷砖之间的白线。

我想通了。答案:Deepzoom into OpenLayers images using zoomify