mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-21 20:56:09 +03:00
Merge pull request #2075 from TanukiSharp/master
Extends the fix for seams in transparent images to any browsers
This commit is contained in:
commit
fab395dc02
@ -344,15 +344,18 @@ $.Drawer.prototype = {
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
* @param {Float} [scale=1] - Apply a scale to tile position and size. Defaults to 1.
|
||||
* @param {OpenSeadragon.Point} [translate] A translation vector to offset tile position
|
||||
* @param {Boolean} [shouldRoundPositionAndSize] - Tells whether to round
|
||||
* position and size of tiles supporting alpha channel in non-transparency
|
||||
* context.
|
||||
*/
|
||||
drawTile: function(tile, drawingHandler, useSketch, scale, translate) {
|
||||
drawTile: function(tile, drawingHandler, useSketch, scale, translate, shouldRoundPositionAndSize) {
|
||||
$.console.assert(tile, '[Drawer.drawTile] tile is required');
|
||||
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
|
||||
|
||||
if (this.useCanvas) {
|
||||
var context = this._getContext(useSketch);
|
||||
scale = scale || 1;
|
||||
tile.drawCanvas(context, drawingHandler, scale, translate);
|
||||
tile.drawCanvas(context, drawingHandler, scale, translate, shouldRoundPositionAndSize);
|
||||
} else {
|
||||
tile.drawHTML( this.canvas );
|
||||
}
|
||||
|
@ -209,6 +209,17 @@
|
||||
* You can pass a CSS color value like "#FF8800".
|
||||
* When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.
|
||||
*
|
||||
* @property {Object} [subPixelRoundingForTransparency=null]
|
||||
* Determines when subpixel rounding should be applied for tiles when rendering images that support transparency.
|
||||
* This property is a subpixel rounding enum values dictionary [{@link BROWSERS}] --> {@link SUBPIXEL_ROUNDING_OCCURRENCES}.
|
||||
* The key is a {@link BROWSERS} value, and the value is one of {@link SUBPIXEL_ROUNDING_OCCURRENCES},
|
||||
* indicating, for a given browser, when to apply subpixel rounding.
|
||||
* Key '*' is the fallback value for any browser not specified in the dictionary.
|
||||
* This property has a simple mode, and one can set it directly to
|
||||
* {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER}, {@link SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST} or {@link SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS}
|
||||
* in order to apply this rule for all browser. The values {@link SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS} would be equivalent to { '*', SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS }.
|
||||
* The default is {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER} for all browsers, for backward compatibility reason.
|
||||
*
|
||||
* @property {Number} [degrees=0]
|
||||
* Initial rotation.
|
||||
*
|
||||
@ -1258,11 +1269,12 @@ function OpenSeadragon( options ){
|
||||
flipped: false,
|
||||
|
||||
// APPEARANCE
|
||||
opacity: 1,
|
||||
preload: false,
|
||||
compositeOperation: null,
|
||||
imageSmoothingEnabled: true,
|
||||
placeholderFillStyle: null,
|
||||
opacity: 1,
|
||||
preload: false,
|
||||
compositeOperation: null,
|
||||
imageSmoothingEnabled: true,
|
||||
placeholderFillStyle: null,
|
||||
subPixelRoundingForTransparency: null,
|
||||
|
||||
//REFERENCE STRIP SETTINGS
|
||||
showReferenceStrip: false,
|
||||
@ -1403,6 +1415,20 @@ function OpenSeadragon( options ){
|
||||
CHROMEEDGE: 7
|
||||
},
|
||||
|
||||
/**
|
||||
* An enumeration of when subpixel rounding should occur.
|
||||
* @static
|
||||
* @type {Object}
|
||||
* @property {Number} NEVER Never apply subpixel rounding for transparency.
|
||||
* @property {Number} ONLY_AT_REST Do not apply subpixel rounding for transparency during animation (panning, zoom, rotation) and apply it once animation is over.
|
||||
* @property {Number} ALWAYS Apply subpixel rounding for transparency during animation and when animation is over.
|
||||
*/
|
||||
SUBPIXEL_ROUNDING_OCCURRENCES: {
|
||||
NEVER: 0,
|
||||
ONLY_AT_REST: 1,
|
||||
ALWAYS: 2
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep track of which {@link Viewer}s have been created.
|
||||
* - Key: {@link Element} to which a Viewer is attached.
|
||||
|
13
src/tile.js
13
src/tile.js
@ -318,8 +318,11 @@ $.Tile.prototype = {
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
* @param {Number} [scale=1] - Apply a scale to position and size
|
||||
* @param {OpenSeadragon.Point} [translate] - A translation vector
|
||||
* @param {Boolean} [shouldRoundPositionAndSize] - Tells whether to round
|
||||
* position and size of tiles supporting alpha channel in non-transparency
|
||||
* context.
|
||||
*/
|
||||
drawCanvas: function( context, drawingHandler, scale, translate ) {
|
||||
drawCanvas: function( context, drawingHandler, scale, translate, shouldRoundPositionAndSize ) {
|
||||
|
||||
var position = this.position.times($.pixelDensityRatio),
|
||||
size = this.size.times($.pixelDensityRatio),
|
||||
@ -363,6 +366,14 @@ $.Tile.prototype = {
|
||||
//an image with an alpha channel, then the only way
|
||||
//to avoid seeing the tile underneath is to clear the rectangle
|
||||
if (context.globalAlpha === 1 && this._hasTransparencyChannel()) {
|
||||
if (shouldRoundPositionAndSize) {
|
||||
// Round to the nearest whole pixel so we don't get seams from overlap.
|
||||
position.x = Math.round(position.x);
|
||||
position.y = Math.round(position.y);
|
||||
size.x = Math.round(size.x);
|
||||
size.y = Math.round(size.y);
|
||||
}
|
||||
|
||||
//clearing only the inside of the rectangle occupied
|
||||
//by the png prevents edge flikering
|
||||
context.clearRect(
|
||||
|
@ -160,24 +160,25 @@ $.TiledImage = function( options ) {
|
||||
_hasOpaqueTile: false, // Do we have even one fully opaque tile?
|
||||
_tilesLoading: 0, // The number of pending tile requests.
|
||||
//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,
|
||||
smoothTileEdgesMinZoom: $.DEFAULT_SETTINGS.smoothTileEdgesMinZoom,
|
||||
iOSDevice: $.DEFAULT_SETTINGS.iOSDevice,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,
|
||||
ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials,
|
||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||
opacity: $.DEFAULT_SETTINGS.opacity,
|
||||
preload: $.DEFAULT_SETTINGS.preload,
|
||||
compositeOperation: $.DEFAULT_SETTINGS.compositeOperation
|
||||
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,
|
||||
iOSDevice: $.DEFAULT_SETTINGS.iOSDevice,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,
|
||||
ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials,
|
||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||
opacity: $.DEFAULT_SETTINGS.opacity,
|
||||
preload: $.DEFAULT_SETTINGS.preload,
|
||||
compositeOperation: $.DEFAULT_SETTINGS.compositeOperation,
|
||||
subPixelRoundingForTransparency: $.DEFAULT_SETTINGS.subPixelRoundingForTransparency
|
||||
}, options );
|
||||
|
||||
this._preload = this.preload;
|
||||
@ -1951,6 +1952,73 @@ function compareTiles( previousBest, tile ) {
|
||||
return previousBest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* Defines the value for subpixel rounding to fallback to in case of missing or
|
||||
* invalid value.
|
||||
*/
|
||||
var DEFAULT_SUBPIXEL_ROUNDING_RULE = $.SUBPIXEL_ROUNDING_OCCURRENCES.NEVER;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* Checks whether the input value is an invalid subpixel rounding enum value.
|
||||
*
|
||||
* @param {SUBPIXEL_ROUNDING_OCCURRENCES} value - The subpixel rounding enum value to check.
|
||||
* @returns {Boolean} Returns true if the input value is none of the expected
|
||||
* {@link SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS}, {@link SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST} or {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER} value.
|
||||
*/
|
||||
function isSubPixelRoundingRuleUnknown(value) {
|
||||
return value !== $.SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS &&
|
||||
value !== $.SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST &&
|
||||
value !== $.SUBPIXEL_ROUNDING_OCCURRENCES.NEVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* Ensures the returned value is always a valid subpixel rounding enum value,
|
||||
* defaulting to {@link SUBPIXEL_ROUNDING_OCCURRENCES.NEVER} if input is missing or invalid.
|
||||
*
|
||||
* @param {SUBPIXEL_ROUNDING_OCCURRENCES} value - The subpixel rounding enum value to normalize.
|
||||
* @returns {SUBPIXEL_ROUNDING_OCCURRENCES} Returns a valid subpixel rounding enum value.
|
||||
*/
|
||||
function normalizeSubPixelRoundingRule(value) {
|
||||
if (isSubPixelRoundingRuleUnknown(value)) {
|
||||
return DEFAULT_SUBPIXEL_ROUNDING_RULE;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* Ensures the returned value is always a valid subpixel rounding enum value,
|
||||
* defaulting to 'NEVER' if input is missing or invalid.
|
||||
*
|
||||
* @param {Object} subPixelRoundingRules - A subpixel rounding enum values dictionary [{@link BROWSERS}] --> {@link SUBPIXEL_ROUNDING_OCCURRENCES}.
|
||||
* @returns {SUBPIXEL_ROUNDING_OCCURRENCES} Returns the determined subpixel rounding enum value for the
|
||||
* current browser.
|
||||
*/
|
||||
function determineSubPixelRoundingRule(subPixelRoundingRules) {
|
||||
if (typeof subPixelRoundingRules === 'number') {
|
||||
return normalizeSubPixelRoundingRule(subPixelRoundingRules);
|
||||
}
|
||||
|
||||
if (!subPixelRoundingRules || !$.Browser) {
|
||||
return DEFAULT_SUBPIXEL_ROUNDING_RULE;
|
||||
}
|
||||
|
||||
var subPixelRoundingRule = subPixelRoundingRules[$.Browser.vendor];
|
||||
|
||||
if (isSubPixelRoundingRuleUnknown(subPixelRoundingRule)) {
|
||||
subPixelRoundingRule = subPixelRoundingRules['*'];
|
||||
}
|
||||
|
||||
return normalizeSubPixelRoundingRule(subPixelRoundingRule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
@ -2099,9 +2167,20 @@ function drawTiles( tiledImage, lastDrawn ) {
|
||||
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);
|
||||
}
|
||||
|
||||
var subPixelRoundingRule = determineSubPixelRoundingRule(tiledImage.subPixelRoundingForTransparency);
|
||||
|
||||
var shouldRoundPositionAndSize = false;
|
||||
|
||||
if (subPixelRoundingRule === $.SUBPIXEL_ROUNDING_OCCURRENCES.ALWAYS) {
|
||||
shouldRoundPositionAndSize = true;
|
||||
} else if (subPixelRoundingRule === $.SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST) {
|
||||
var isAnimating = tiledImage.viewer && tiledImage.viewer.isAnimating();
|
||||
shouldRoundPositionAndSize = !isAnimating;
|
||||
}
|
||||
|
||||
for (var i = lastDrawn.length - 1; i >= 0; i--) {
|
||||
tile = lastDrawn[ i ];
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate );
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate, shouldRoundPositionAndSize );
|
||||
tile.beingDrawn = true;
|
||||
|
||||
if( tiledImage.viewer ){
|
||||
|
@ -713,6 +713,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
}
|
||||
|
||||
THIS[ this.hash ].animating = false;
|
||||
|
||||
this.world.removeAll();
|
||||
this.imageLoader.clear();
|
||||
|
||||
@ -1503,7 +1504,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
ajaxWithCredentials: queueItem.options.ajaxWithCredentials,
|
||||
loadTilesWithAjax: queueItem.options.loadTilesWithAjax,
|
||||
ajaxHeaders: queueItem.options.ajaxHeaders,
|
||||
debugMode: _this.debugMode
|
||||
debugMode: _this.debugMode,
|
||||
subPixelRoundingForTransparency: _this.subPixelRoundingForTransparency
|
||||
});
|
||||
|
||||
if (_this.collectionMode) {
|
||||
@ -2357,6 +2359,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
}
|
||||
this.goToPage( next );
|
||||
},
|
||||
|
||||
isAnimating: function () {
|
||||
return THIS[ this.hash ].animating;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -3503,7 +3509,9 @@ function updateOnce( viewer ) {
|
||||
animated = viewer.referenceStrip.update( viewer.viewport ) || animated;
|
||||
}
|
||||
|
||||
if ( !THIS[ viewer.hash ].animating && animated ) {
|
||||
var currentAnimating = THIS[ viewer.hash ].animating;
|
||||
|
||||
if ( !currentAnimating && animated ) {
|
||||
/**
|
||||
* Raised when any spring animation starts (zoom, pan, etc.).
|
||||
*
|
||||
@ -3517,7 +3525,13 @@ function updateOnce( viewer ) {
|
||||
abortControlsAutoHide( viewer );
|
||||
}
|
||||
|
||||
if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) {
|
||||
var isAnimationFinished = currentAnimating && !animated;
|
||||
|
||||
if ( isAnimationFinished ) {
|
||||
THIS[ viewer.hash ].animating = false;
|
||||
}
|
||||
|
||||
if ( animated || isAnimationFinished || THIS[ viewer.hash ].forceRedraw || viewer.world.needsDraw() ) {
|
||||
drawWorld( viewer );
|
||||
viewer._drawOverlays();
|
||||
if( viewer.navigator ){
|
||||
@ -3541,7 +3555,7 @@ function updateOnce( viewer ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( THIS[ viewer.hash ].animating && !animated ) {
|
||||
if ( isAnimationFinished ) {
|
||||
/**
|
||||
* Raised when any spring animation ends (zoom, pan, etc.).
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user