mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-22 13:16:10 +03:00
tile edge smoothing at high zoom - #755
This commit is contained in:
parent
9fa3136e78
commit
8c4fcc9ca9
@ -290,8 +290,9 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
* drawingHandler({context, tile, rendered})
|
||||
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
* @param {Float} scale - Apply a scale to tile position and size
|
||||
*/
|
||||
drawTile: function( tile, drawingHandler, useSketch ) {
|
||||
drawTile: function( tile, drawingHandler, useSketch, scale ) {
|
||||
$.console.assert(tile, '[Drawer.drawTile] tile is required');
|
||||
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
|
||||
|
||||
@ -301,10 +302,10 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
// specifically, don't save,rotate,restore every time we draw a tile
|
||||
if( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.viewport.degrees, useSketch );
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
tile.drawCanvas( context, drawingHandler, scale );
|
||||
this._restoreRotationChanges( tile, useSketch );
|
||||
} else {
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
tile.drawCanvas( context, drawingHandler, scale );
|
||||
}
|
||||
} else {
|
||||
tile.drawHTML( this.canvas );
|
||||
@ -371,16 +372,29 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
/**
|
||||
* Blends the sketch canvas in the main canvas.
|
||||
* @param {Float} opacity The opacity of the blending.
|
||||
* @param {Float} sketchScale The scale at which tiles were drawn on the sketch. Default is 1.
|
||||
* Use sketchScale to draw at a lower scale and then enlarge onto the main canvas.
|
||||
* @returns {undefined}
|
||||
*/
|
||||
blendSketch: function(opacity) {
|
||||
blendSketch: function(opacity, sketchScale) {
|
||||
if (!this.useCanvas || !this.sketchCanvas) {
|
||||
return;
|
||||
}
|
||||
sketchScale = sketchScale || 1;
|
||||
|
||||
this.context.save();
|
||||
this.context.globalAlpha = opacity;
|
||||
this.context.drawImage(this.sketchCanvas, 0, 0);
|
||||
this.context.drawImage(
|
||||
this.sketchCanvas,
|
||||
0,
|
||||
0,
|
||||
this.sketchCanvas.width * sketchScale,
|
||||
this.sketchCanvas.height * sketchScale,
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height
|
||||
);
|
||||
this.context.restore();
|
||||
},
|
||||
|
||||
|
@ -249,6 +249,11 @@
|
||||
* image though it is less effective visually if the HTML5 Canvas is not
|
||||
* availble on the viewing device.
|
||||
*
|
||||
* @property {Number} [smoothTileEdgesMinZoom=1.1]
|
||||
* A zoom percentage ( expressed as a number between 0 and 1 ) of the highest
|
||||
* resolution level. When zoomed in beyond this value alternative compositing will
|
||||
* be used to smooth out the edges between tiles. This WILL have a performance impact.
|
||||
*
|
||||
* @property {Boolean} [autoResize=true]
|
||||
* Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.
|
||||
*
|
||||
@ -1000,6 +1005,7 @@ if (typeof define === 'function' && define.amd) {
|
||||
immediateRender: false,
|
||||
minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity
|
||||
maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels
|
||||
smoothTileEdgesMinZoom: 1.1, //-> higher than maxZoomPixelRatio disables it
|
||||
pixelsPerWheelLine: 40,
|
||||
autoResize: true,
|
||||
preserveImageSizeOnResize: false, // requires autoResize=true
|
||||
|
59
src/tile.js
59
src/tile.js
@ -240,11 +240,12 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
* @param {Function} drawingHandler - Method for firing the drawing event.
|
||||
* drawingHandler({context, tile, rendered})
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
* @param {Number} scale - Apply a scale to position and size
|
||||
*/
|
||||
drawCanvas: function( context, drawingHandler ) {
|
||||
drawCanvas: function( context, drawingHandler, scale ) {
|
||||
|
||||
var position = this.position,
|
||||
size = this.size,
|
||||
var position = this.position.times($.pixelDensityRatio),
|
||||
size = this.size.times($.pixelDensityRatio),
|
||||
rendered;
|
||||
|
||||
if (!this.cacheImageRecord) {
|
||||
@ -277,10 +278,10 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
//clearing only the inside of the rectangle occupied
|
||||
//by the png prevents edge flikering
|
||||
context.clearRect(
|
||||
(position.x * $.pixelDensityRatio)+1,
|
||||
(position.y * $.pixelDensityRatio)+1,
|
||||
(size.x * $.pixelDensityRatio)-2,
|
||||
(size.y * $.pixelDensityRatio)-2
|
||||
position.x + 1,
|
||||
position.y + 1,
|
||||
size.x - 2,
|
||||
size.y - 2
|
||||
);
|
||||
|
||||
}
|
||||
@ -289,16 +290,52 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
// changes as we are rendering the image
|
||||
drawingHandler({context: context, tile: this, rendered: rendered});
|
||||
|
||||
if (typeof scale === 'number' && scale !== 1) {
|
||||
// draw tile at a different scale
|
||||
position = position.times(scale);
|
||||
size = size.times(scale);
|
||||
|
||||
if (scale < 1 && $.Browser.vendor == $.BROWSERS.FIREFOX) {
|
||||
// In firefox edges are very visible because there seems to be
|
||||
// empty space between tiles caused by float coordinates.
|
||||
// Adding partial overlap fixes this.
|
||||
// These will be covered by the top and left tiles.
|
||||
context.drawImage( // duplicate first column to the left
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
rendered.canvas.height,
|
||||
Math.floor(position.x),
|
||||
position.y,
|
||||
1,
|
||||
size.y
|
||||
);
|
||||
context.drawImage( // duplicate first row up
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
rendered.canvas.width,
|
||||
1,
|
||||
position.x,
|
||||
Math.floor(position.y),
|
||||
size.x,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// context.globalCompositeOperation = 'source-out';
|
||||
context.drawImage(
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
rendered.canvas.width,
|
||||
rendered.canvas.height,
|
||||
position.x * $.pixelDensityRatio,
|
||||
position.y * $.pixelDensityRatio,
|
||||
size.x * $.pixelDensityRatio,
|
||||
size.y * $.pixelDensityRatio
|
||||
position.x,
|
||||
position.y,
|
||||
size.x,
|
||||
size.y
|
||||
);
|
||||
|
||||
context.restore();
|
||||
|
@ -133,19 +133,20 @@ $.TiledImage = function( options ) {
|
||||
_hasOpaqueTile: false, // Do we have even one fully opaque tile?
|
||||
|
||||
//configurable settings
|
||||
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
|
||||
animationTime: $.DEFAULT_SETTINGS.animationTime,
|
||||
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
|
||||
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
|
||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||
immediateRender: $.DEFAULT_SETTINGS.immediateRender,
|
||||
blendTime: $.DEFAULT_SETTINGS.blendTime,
|
||||
alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,
|
||||
minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,
|
||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||
opacity: $.DEFAULT_SETTINGS.opacity
|
||||
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
|
||||
animationTime: $.DEFAULT_SETTINGS.animationTime,
|
||||
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
|
||||
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
|
||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||
immediateRender: $.DEFAULT_SETTINGS.immediateRender,
|
||||
blendTime: $.DEFAULT_SETTINGS.blendTime,
|
||||
alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,
|
||||
minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,
|
||||
smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,
|
||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||
opacity: $.DEFAULT_SETTINGS.opacity
|
||||
|
||||
}, options );
|
||||
|
||||
@ -1302,6 +1303,19 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
return;
|
||||
}
|
||||
var useSketch = tiledImage.opacity < 1;
|
||||
var sketchScale = 1;
|
||||
|
||||
var zoom = tiledImage.viewport.getZoom();
|
||||
var imageZoom = tiledImage.viewportToImageZoom(zoom);
|
||||
if ( imageZoom > tiledImage.smoothTileEdgesMinZoom ) {
|
||||
// When zoomed in a lot (>100%) the tile edges are visible.
|
||||
// So we have to composite them at ~100% and scale them up together.
|
||||
useSketch = true;
|
||||
// Compositing at 100% is not precise and causes weird twithing.
|
||||
// So we composite at 101% zoom
|
||||
sketchScale = 1.01 / imageZoom;
|
||||
}
|
||||
|
||||
if ( useSketch ) {
|
||||
tiledImage._drawer._clear( true );
|
||||
}
|
||||
@ -1333,7 +1347,7 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
|
||||
for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
|
||||
tile = lastDrawn[ i ];
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch );
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale );
|
||||
tile.beingDrawn = true;
|
||||
|
||||
if( tiledImage.viewer ){
|
||||
@ -1360,7 +1374,7 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
}
|
||||
|
||||
if ( useSketch ) {
|
||||
tiledImage._drawer.blendSketch( tiledImage.opacity );
|
||||
tiledImage._drawer.blendSketch( tiledImage.opacity, sketchScale );
|
||||
}
|
||||
drawDebugInfo( tiledImage, lastDrawn );
|
||||
}
|
||||
|
@ -1342,6 +1342,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
blendTime: _this.blendTime,
|
||||
alwaysBlend: _this.alwaysBlend,
|
||||
minPixelRatio: _this.minPixelRatio,
|
||||
smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom,
|
||||
crossOriginPolicy: _this.crossOriginPolicy,
|
||||
debugMode: _this.debugMode
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user