From c639dd5123fbd54d113f6565cafb82ddab96c3dd Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Sat, 23 Jan 2016 18:40:53 -0500 Subject: [PATCH] Fix edge smoothing with rotation. --- src/drawer.js | 57 +++++++++++++++++++++++++++++++++++++---------- src/tile.js | 10 ++++----- src/tiledimage.js | 23 ++++++++++++++----- 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/drawer.js b/src/drawer.js index bad89a69..fcfb57b5 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -249,8 +249,9 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ this.canvas.width = viewportSize.x; this.canvas.height = viewportSize.y; if ( this.sketchCanvas !== null ) { - this.sketchCanvas.width = this.canvas.width; - this.sketchCanvas.height = this.canvas.height; + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; } } this._clear(); @@ -312,8 +313,9 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ if ( useSketch ) { if (this.sketchCanvas === null) { this.sketchCanvas = document.createElement( "canvas" ); - this.sketchCanvas.width = this.canvas.width; - this.sketchCanvas.height = this.canvas.height; + var sketchCanvasSize = this._calculateSketchCanvasSize(); + this.sketchCanvas.width = sketchCanvasSize.x; + this.sketchCanvas.height = sketchCanvasSize.y; this.sketchContext = this.sketchCanvas.getContext( "2d" ); } context = this.sketchContext; @@ -381,18 +383,27 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ translate : new $.Point(0, 0); + var widthExt = 0; + var heightExt = 0; + if (translate) { + var widthDiff = this.sketchCanvas.width - this.canvas.width; + var heightDiff = this.sketchCanvas.height - this.canvas.height; + widthExt = Math.round(widthDiff / 2); + heightExt = Math.round(heightDiff / 2); + } + this.context.save(); this.context.globalAlpha = opacity; this.context.drawImage( this.sketchCanvas, - position.x, - position.y, - this.sketchCanvas.width * scale, - this.sketchCanvas.height * scale, - 0, - 0, - this.canvas.width, - this.canvas.height + position.x - widthExt * scale, + position.y - heightExt * scale, + (this.canvas.width + 2 * widthExt) * scale, + (this.canvas.height + 2 * heightExt) * scale, + -widthExt, + -heightExt, + this.canvas.width + 2 * widthExt, + this.canvas.height + 2 * heightExt ); this.context.restore(); }, @@ -498,6 +509,16 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ } }, + /** + * Get the canvas size + * @param {Boolean} sketch If set to true return the size of the sketch canvas + * @returns {OpenSeadragon.Point} The size of the canvas + */ + getCanvasSize: function(sketch) { + var canvas = this._getContext(sketch).canvas; + return new $.Point(canvas.width, canvas.height); + }, + // private _offsetForRotation: function(degrees, useSketch) { var cx = this.canvas.width / 2; @@ -525,6 +546,18 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ x: viewportSize.x * pixelDensityRatio, y: viewportSize.y * pixelDensityRatio }; + }, + + // private + _calculateSketchCanvasSize: function() { + var canvasSize = this._calculateCanvasSize(); + var sketchCanvasSize = Math.ceil(Math.sqrt( + canvasSize.x * canvasSize.x + + canvasSize.y * canvasSize.y)); + return { + x: sketchCanvasSize, + y: sketchCanvasSize + }; } }; diff --git a/src/tile.js b/src/tile.js index a07bec74..4adb7a1d 100644 --- a/src/tile.js +++ b/src/tile.js @@ -350,11 +350,11 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{ * @param {Number} [scale=1] - Scale to be applied to position. * @return {OpenSeadragon.Point} */ - getTranslationForEdgeSmoothing: function(scale) { - // The translation vector must have positive values, otherwise the image goes a bit off - // the sketch canvas to the top and left and we must use negative coordinates to repaint it - // to the main canvas. And FF does not like it. It crashes the viewer. - return new $.Point(1, 1).minus( + getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) { + var sketchCanvasDelta = new $.Point( + Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2), + Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2)); + return sketchCanvasDelta.minus( this.position .times($.pixelDensityRatio) .times(scale || 1) diff --git a/src/tiledimage.js b/src/tiledimage.js index bf61a7de..6a64b0ce 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1319,19 +1319,23 @@ function drawTiles( tiledImage, lastDrawn ) { var zoom = tiledImage.viewport.getZoom(true); var imageZoom = tiledImage.viewportToImageZoom(zoom); - if ( imageZoom > tiledImage.smoothTileEdgesMinZoom && tile) { + if (imageZoom > tiledImage.smoothTileEdgesMinZoom && tile) { // 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; sketchScale = tile.getScaleForEdgeSmoothing(); - sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale); + sketchTranslate = tile.getTranslationForEdgeSmoothing(sketchScale, + tiledImage._drawer.getCanvasSize(false), + tiledImage._drawer.getCanvasSize(true)); } if ( useSketch ) { tiledImage._drawer._clear( true ); } - if (tiledImage.viewport.degrees !== 0) { + // When scaling, we must rotate only when blending the sketch canvas to avoid + // interpolation + if (tiledImage.viewport.degrees !== 0 && !sketchScale) { tiledImage._drawer._offsetForRotation(tiledImage.viewport.degrees, useSketch); } @@ -1400,12 +1404,19 @@ function drawTiles( tiledImage, lastDrawn ) { tiledImage._drawer.restoreContext( useSketch ); } - if (tiledImage.viewport.degrees !== 0) { + if (tiledImage.viewport.degrees !== 0 && !sketchScale) { tiledImage._drawer._restoreRotationChanges(useSketch); } - if ( useSketch ) { - tiledImage._drawer.blendSketch( tiledImage.opacity, sketchScale, sketchTranslate ); + if (useSketch) { + var offsetForRotation = tiledImage.viewport.degrees !== 0 && sketchScale; + if (offsetForRotation) { + tiledImage._drawer._offsetForRotation(tiledImage.viewport.degrees, false); + } + tiledImage._drawer.blendSketch(tiledImage.opacity, sketchScale, sketchTranslate); + if (offsetForRotation) { + tiledImage._drawer._restoreRotationChanges(false); + } } drawDebugInfo( tiledImage, lastDrawn ); }