Merge pull request #825 from avandecreme/rotation

Fix edge smoothing with rotation.
This commit is contained in:
Ian Gilman 2016-01-28 11:27:31 -08:00
commit a244d7ef86
3 changed files with 86 additions and 21 deletions

View File

@ -250,8 +250,9 @@ $.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();
@ -313,9 +314,23 @@ $.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" );
// If the viewport is not currently rotated, the sketchCanvas
// will have the same size as the main canvas. However, if
// the viewport get rotated later on, we will need to resize it.
if (this.viewport.getRotation() === 0) {
var self = this;
this.viewer.addHandler('rotate', function resizeSketchCanvas() {
self.viewer.removeHandler('rotate', resizeSketchCanvas);
var sketchCanvasSize = self._calculateSketchCanvasSize();
self.sketchCanvas.width = sketchCanvasSize.x;
self.sketchCanvas.height = sketchCanvasSize.y;
});
}
}
context = this.sketchContext;
}
@ -383,6 +398,15 @@ $.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;
if (compositeOperation) {
@ -390,14 +414,14 @@ $.Drawer.prototype = {
}
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();
},
@ -503,6 +527,16 @@ $.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;
@ -530,6 +564,23 @@ $.Drawer.prototype = {
x: viewportSize.x * pixelDensityRatio,
y: viewportSize.y * pixelDensityRatio
};
},
// private
_calculateSketchCanvasSize: function() {
var canvasSize = this._calculateCanvasSize();
if (this.viewport.getRotation() === 0) {
return canvasSize;
}
// If the viewport is rotated, we need a larger sketch canvas in order
// to support edge smoothing.
var sketchCanvasSize = Math.ceil(Math.sqrt(
canvasSize.x * canvasSize.x +
canvasSize.y * canvasSize.y));
return {
x: sketchCanvasSize,
y: sketchCanvasSize
};
}
};

View File

@ -351,11 +351,14 @@ $.Tile.prototype = {
* @param {Number} [scale=1] - Scale to be applied to position.
* @return {OpenSeadragon.Point}
*/
getTranslationForEdgeSmoothing: function(scale) {
getTranslationForEdgeSmoothing: function(scale, canvasSize, sketchCanvasSize) {
// 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(
// to the main canvas. In that case, some browsers throw:
// INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.
var x = Math.max(1, Math.ceil((sketchCanvasSize.x - canvasSize.x) / 2));
var y = Math.max(1, Math.ceil((sketchCanvasSize.y - canvasSize.y) / 2));
return new $.Point(x, y).minus(
this.position
.times($.pixelDensityRatio)
.times(scale || 1)

View File

@ -1337,19 +1337,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);
}
@ -1418,12 +1422,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, tiledImage.compositeOperation );
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, tiledImage.compositeOperation);
if (offsetForRotation) {
tiledImage._drawer._restoreRotationChanges(false);
}
}
drawDebugInfo( tiledImage, lastDrawn );
}