OpenLayers 3加载超大显微切片图(ndpi/svs/tiff)分片异常问题
如何让所有大尺寸显微切片图在OpenLayers 3中均以小瓦片形式加载?
我拥有超过10GB的ndpi、svs、tiff格式显微切片图,当前使用OpenLayers 3版本进行展示。部分图片加载时会被转换为多个小瓦片(tileUrlFunction触发40次API调用),加载速度较快;但同类型、同大小的另一部分图片却不会被转换为小瓦片(tileUrlFunction仅触发1次API调用)。
相关代码
var projection = new ol.proj.Projection({ code: 'meters', units: 'm', getPointResolution: function (resolution) { return resolution * params.umperpixel[0]; } }); var extent = [params.left[0], -(params.totYpix[0] + params.bottom[0]), params.totXpix[0] + params.right[0], params.top[0]]; var tilegrid = new ol.tilegrid.WMTS({ matrixIds: resolutions, origins: origins, sizes: matrixSizes, tileSizes: sizes, resolutions: resolutions }); var zoomTilegrid = new ol.tilegrid.WMTS({ matrixIds: [resolutions[resolutions.length - 1]], origins: [origins[origins.length - 1]], sizes: [matrixSizes[matrixSizes.length - 1]], tileSizes: [sizes[sizes.length - 1]], resolutions: [resolutions[resolutions.length - 1]] }); slide.source = new ol.source.TileImage({ crossOrigin: 'anonymous', wrapX: false, projection: projection, tileGrid: tilegrid, tileUrlFunction: function (tileCoord) { return fetchTiles(slide, tileCoord, params); } }); slide.zoomSource = new ol.source.TileImage({ crossOrigin: 'anonymous', wrapX: false, projection: projection, tileGrid: zoomTilegrid, tileUrlFunction: function (tileCoord) { return fetchTiles(slide, tileCoord, params, true); } }); function fetchTiles(slide, tileCoord, params, forZoom) { if (tileCoord !== null) { var res = angular.copy(slide.map.getView().getResolution()); var key = params.resolutions.indexOf(res), x = tileCoord[1], y = -tileCoord[2] - 1, level = forZoom ? params[params.format[key] + 'level'].slice(-1) : params[params.format[key] + 'level'][key]; return getTileUrl() + 'fetchimage.cgi?' + serializeData({ 'PATH': (params.prefix[key] === 'ndpi' || params.prefix[key] === 'svs' || params.prefix[key] === 'webslide') ? path : path + '.' + params.prefix[key], 'SLIDEFORMAT': params.format[key], 'X': x, 'Y': y, 'IMAGEFORMAT': params.type[key], 'LEVEL': level }); } }
瓦片请求参数示例
传递给fetchimage.cgi的tileCoord数组的X与Y组合(所有请求的Level均为4):
1-1 (Level-4) 2-1 3-1 4-1 5-1 6-1 7-1 8-1 9-1 10-1 11-1 12-1 13-1 1-2 (Level-4) 2-2 3-2 4-2 5-2 6-2 8-2 7-2 9-2 10-2 11-2 12-2 13-2 1-3 (Level-4) 2-3 3-3 4-3 5-3 6-3 7-3 8-3 9-3 10-3 11-3 12-3 13-3
示例请求:
http://testdomain/fetchimage.cgi?PATH=fullfilename.ndpi&SLIDEFORMAT=ndpi&X=13&Y=1&IMAGEFORMAT=jpg&LEVEL=4
排查与解决方向
1. 确保瓦片网格参数一致性
检查tilegrid初始化的核心参数,保证所有切片图的瓦片拆分逻辑统一:
- 确认
resolutions数组包含多个层级的分辨率值,不能仅存在一个层级(否则OpenLayers只会加载单张瓦片) - 验证
matrixSizes(每个层级的瓦片行列数)是否根据切片图实际尺寸计算准确,公式参考:matrixSize = Math.ceil(图片实际像素尺寸 / (tileSize * 对应层级缩放比))
2. 校验切片图元数据的准确性
代码中extent由params对象的left、totYpix等参数计算而来,若部分切片图的这些元数据错误,会导致OpenLayers判断图层范围过小,无需拆分瓦片:
- 核对每个切片图的
extent是否覆盖完整像素范围,避免因范围计算错误导致瓦片逻辑失效 - 检查
params.resolutions.indexOf(res)的返回值,确保能匹配到正确的层级索引(若返回-1会触发错误的瓦片层级逻辑)
3. 修正瓦片层级取值逻辑
当前level的取值依赖params[params.format[key]+'level']数组,若部分切片图的该数组长度不足,会导致层级取值错误:
- 确保
params[params.format[key]+'level']数组长度与resolutions一致,每个分辨率层级对应正确的瓦片层级 - 非缩放场景下避免使用
slice(-1)取最后一个元素,保证level取对应索引的正确值
4. 强制启用瓦片拆分兜底配置
若上述排查均无问题,可在ol.source.TileImage中添加配置强制禁用单瓦片加载逻辑:
slide.source = new ol.source.TileImage({ crossOrigin: 'anonymous', wrapX: false, projection: projection, tileGrid: tilegrid, tileUrlFunction: function (tileCoord) { return fetchTiles(slide, tileCoord, params); }, // 强制禁用单瓦片加载兜底逻辑 tileLoadFunction: function(tile, src) { if (src) { tile.getImage().src = src; } } });
内容的提问来源于stack exchange,提问作者R.G.Krish
相关产品推荐
相关产品推荐

