Fix comments on #2148: hasTransparency as a property. Move '.image' tile property to be a getter instead. Rename 'ImageJob' data property from 'image' to 'data'. Repair comments related to #2148.

This commit is contained in:
Jirka 2022-04-29 18:41:43 +02:00
parent 92ad2c5552
commit 45a7a4aaf3
5 changed files with 81 additions and 62 deletions

View File

@ -58,11 +58,11 @@ function ImageJob (options) {
}, options); }, options);
/** /**
* Image object which will contain downloaded image. * Data object which will contain downloaded image data.
* @member {Image|*} image element (default) or other form of image data (depends on TileSource) * @member {Image|*} image data object, by default an Image object (depends on TileSource)
* @memberof OpenSeadragon.ImageJob# * @memberof OpenSeadragon.ImageJob#
*/ */
this.image = null; this.data = null;
} }
ImageJob.prototype = { ImageJob.prototype = {
@ -77,12 +77,11 @@ ImageJob.prototype = {
var selfAbort = this.abort; var selfAbort = this.abort;
this.jobId = window.setTimeout(function () { this.jobId = window.setTimeout(function () {
self.errorMsg = "Image load exceeded timeout (" + self.timeout + " ms)"; self.finish(false, "Image load exceeded timeout (" + self.timeout + " ms)");
self.finish(false);
}, this.timeout); }, this.timeout);
this.abort = function() { this.abort = function() {
self.request.abort(); self.source.downloadTileAbort(self);
if (typeof selfAbort === "function") { if (typeof selfAbort === "function") {
selfAbort(); selfAbort();
} }
@ -93,8 +92,7 @@ ImageJob.prototype = {
finish: function(successful, errorMessage) { finish: function(successful, errorMessage) {
this.errorMsg = errorMessage; this.errorMsg = errorMessage;
//consider deprecation of .image attribute this.data = this.source.downloadTileFinish(this, successful);
this.image = this.source.downloadTileFinish(this, successful);
if (this.jobId) { if (this.jobId) {
window.clearTimeout(this.jobId); window.clearTimeout(this.jobId);
@ -145,6 +143,17 @@ $.ImageLoader.prototype = {
* @param {Function} [options.abort] - Called when this image job is aborted. * @param {Function} [options.abort] - Called when this image job is aborted.
*/ */
addJob: function(options) { addJob: function(options) {
if (!options.source) {
$.console.error('ImageLoader.prototype.addJob() requires [options.source]. ' +
'TileSource since new API defines how images are fetched. Creating a dummy TileSource.');
let implementation = $.TileSource.prototype;
options.source = {
downloadTileStart: implementation.downloadTileStart,
downloadTileAbort: implementation.downloadTileAbort,
downloadTileFinish: implementation.downloadTileFinish
};
}
var _this = this, var _this = this,
complete = function(job) { complete = function(job) {
completeJob(_this, job, options.callback); completeJob(_this, job, options.callback);
@ -207,7 +216,7 @@ function completeJob(loader, job, callback) {
loader.jobsInProgress++; loader.jobsInProgress++;
} }
callback(job.image, job.errorMsg, job.request); callback(job.data, job.errorMsg, job.request); //todo job.request might not exist
} }
}(OpenSeadragon)); }(OpenSeadragon));

View File

@ -164,12 +164,6 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* @memberof OpenSeadragon.Tile# * @memberof OpenSeadragon.Tile#
*/ */
this.imgElement = null; this.imgElement = null;
/**
* The Image object for this tile.
* @member {Object} image
* @memberof OpenSeadragon.Tile#
*/
this.image = null;
/** /**
* The alias of this.element.style. * The alias of this.element.style.
@ -222,6 +216,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
*/ */
this.visibility = null; this.visibility = null;
/**
* The transparency indicator of this tile.
* @member {Boolean} true if tile contains transparency for correct rendering
* @memberof OpenSeadragon.Tile#
*/
this.hasTransparency = false;
/** /**
* Whether this tile is currently being drawn. * Whether this tile is currently being drawn.
* @member {Boolean} beingDrawn * @member {Boolean} beingDrawn
@ -266,8 +267,8 @@ $.Tile.prototype = {
// private // private
_hasTransparencyChannel: function() { _hasTransparencyChannel: function() {
console.warn("Tile.prototype._hasTransparencyChannel has been " + console.warn("Tile.prototype._hasTransparencyChannel() has been " +
"deprecated and will be removed in the future."); "deprecated and will be removed in the future. Use TileSource.prototype.hasTransparency() instead.");
return !!this.context2D || this.url.match('.png'); return !!this.context2D || this.url.match('.png');
}, },
@ -296,8 +297,11 @@ $.Tile.prototype = {
// content during animation of the container size. // content during animation of the container size.
if ( !this.element ) { if ( !this.element ) {
var image = this.image;
if (!this.image) return;
this.element = $.makeNeutralElement( "div" ); this.element = $.makeNeutralElement( "div" );
this.imgElement = this.imageData(); this.imgElement = image.cloneNode();
this.imgElement.style.msInterpolationMode = "nearest-neighbor"; this.imgElement.style.msInterpolationMode = "nearest-neighbor";
this.imgElement.style.width = "100%"; this.imgElement.style.width = "100%";
this.imgElement.style.height = "100%"; this.imgElement.style.height = "100%";
@ -325,22 +329,23 @@ $.Tile.prototype = {
}, },
/** /**
* Get the tile image data as <img> element if * The Image object for this tile.
* supported * @member {Object} image
* * @memberof OpenSeadragon.Tile#
* @return {Image || undefined} * @return {Image}
*/ */
imageData: function() { get image() {
return this.image || this.cacheImageRecord.getImage(); this.cacheImageRecord.getImage();
}, },
/** /**
* Get the CanvasRenderingContext2D instance for tile image data drawn * The CanvasRenderingContext2D instance for tile image data drawn
* onto Canvas if supported * onto Canvas if enabled and available
* * @member {CanvasRenderingContext2D} canvasContext
* @return {CanvasRenderingContext2D || undefined} * @memberof OpenSeadragon.Tile#
* @return {CanvasRenderingContext2D}
*/ */
canvasContext: function() { get canvasContext() {
return this.context2D || this.cacheImageRecord.getRenderedContext(); return this.context2D || this.cacheImageRecord.getRenderedContext();
}, },
@ -372,7 +377,7 @@ $.Tile.prototype = {
return; return;
} }
rendered = this.canvasContext(); rendered = this.canvasContext;
if ( !this.loaded || !rendered ){ if ( !this.loaded || !rendered ){
$.console.warn( $.console.warn(
@ -384,7 +389,6 @@ $.Tile.prototype = {
} }
context.save(); context.save();
context.globalAlpha = this.opacity; context.globalAlpha = this.opacity;
if (typeof scale === 'number' && scale !== 1) { if (typeof scale === 'number' && scale !== 1) {
@ -398,19 +402,11 @@ $.Tile.prototype = {
position = position.plus(translate); position = position.plus(translate);
} }
if (source === undefined) {
$.console.warn('[Tile.drawCanvas] deprecated call without argument \'hasTransparency\'.');
hasTransparency = context.globalAlpha === 1 && this._hasTransparencyChannel();
} else {
hasTransparency = context.globalAlpha === 1 &&
source.hasTransparency(this.context2D, this.url, this.ajaxHeaders, this.postData);
}
//if we are supposed to be rendering fully opaque rectangle, //if we are supposed to be rendering fully opaque rectangle,
//ie its done fading or fading is turned off, and if we are drawing //ie its done fading or fading is turned off, and if we are drawing
//an image with an alpha channel, then the only way //an image with an alpha channel, then the only way
//to avoid seeing the tile underneath is to clear the rectangle //to avoid seeing the tile underneath is to clear the rectangle
if (hasTransparency) { if (context.globalAlpha === 1 && this.hasTransparency) {
if (shouldRoundPositionAndSize) { if (shouldRoundPositionAndSize) {
// Round to the nearest whole pixel so we don't get seams from overlap. // Round to the nearest whole pixel so we don't get seams from overlap.
position.x = Math.round(position.x); position.x = Math.round(position.x);

View File

@ -45,7 +45,6 @@ var TileRecord = function( options ) {
// private class // private class
var ImageRecord = function(options) { var ImageRecord = function(options) {
//private scope: changed image -> data
$.console.assert( options, "[ImageRecord] options is required" ); $.console.assert( options, "[ImageRecord] options is required" );
$.console.assert( options.data, "[ImageRecord] options.data is required" ); $.console.assert( options.data, "[ImageRecord] options.data is required" );
this._tiles = []; this._tiles = [];
@ -63,14 +62,6 @@ ImageRecord.prototype = {
this._tiles = null; this._tiles = null;
}, },
// Removed (left as a comment so that it stands out)
// setRenderedContext: function(renderedContext) {
// $.console.error("ImageRecord.setRenderedContext is deprecated. " +
// "The rendered context should be created by the ImageRecord " +
// "itself when calling ImageRecord.getRenderedContext.");
// this._renderedContext = renderedContext;
// },
addTile: function(tile) { addTile: function(tile) {
$.console.assert(tile, '[ImageRecord.addTile] tile is required'); $.console.assert(tile, '[ImageRecord.addTile] tile is required');
this._tiles.push(tile); this._tiles.push(tile);
@ -146,9 +137,16 @@ $.TileCache.prototype = {
var imageRecord = this._imagesLoaded[options.tile.cacheKey]; var imageRecord = this._imagesLoaded[options.tile.cacheKey];
if (!imageRecord) { if (!imageRecord) {
$.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" );
if (!options.data) {
$.console.error("[TileCache.cacheTile] options.image was renamed to options.data. '.image' attribute "
+ "has been deprecated and will be removed in the future.");
options.data = options.image;
}
$.console.assert( options.data, "[TileCache.cacheTile] options.data is required to create an ImageRecord" );
imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({ imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({
data: options.image, data: options.data,
ownerTile: options.tile, ownerTile: options.tile,
create: options.tiledImage.source.createTileCache, create: options.tiledImage.source.createTileCache,
destroy: options.tiledImage.source.destroyTileCache, destroy: options.tiledImage.source.destroyTileCache,

View File

@ -1576,8 +1576,8 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
ajaxHeaders: tile.ajaxHeaders, ajaxHeaders: tile.ajaxHeaders,
crossOriginPolicy: this.crossOriginPolicy, crossOriginPolicy: this.crossOriginPolicy,
ajaxWithCredentials: this.ajaxWithCredentials, ajaxWithCredentials: this.ajaxWithCredentials,
callback: function( image, errorMsg, tileRequest ){ callback: function( data, errorMsg, tileRequest ){
_this._onTileLoad( tile, time, image, errorMsg, tileRequest ); _this._onTileLoad( tile, time, data, errorMsg, tileRequest );
}, },
abort: function() { abort: function() {
tile.loading = false; tile.loading = false;
@ -1591,12 +1591,12 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* Callback fired when a Tile's Image finished downloading. * Callback fired when a Tile's Image finished downloading.
* @param {OpenSeadragon.Tile} tile * @param {OpenSeadragon.Tile} tile
* @param {Number} time * @param {Number} time
* @param {Image} image * @param {*} data image data
* @param {String} errorMsg * @param {String} errorMsg
* @param {XMLHttpRequest} tileRequest * @param {XMLHttpRequest} tileRequest
*/ */
_onTileLoad: function( tile, time, image, errorMsg, tileRequest ) { _onTileLoad: function( tile, time, data, errorMsg, tileRequest ) {
if ( !image ) { if ( !data ) {
$.console.error( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg ); $.console.error( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg );
/** /**
* Triggered when a tile fails to load. * Triggered when a tile fails to load.
@ -1632,7 +1632,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
finish = function() { finish = function() {
var ccc = _this.source; var ccc = _this.source;
var cutoff = ccc.getClosestLevel(); var cutoff = ccc.getClosestLevel();
_this._setTileLoaded(tile, image, cutoff, tileRequest); _this._setTileLoaded(tile, data, cutoff, tileRequest);
}; };
// Check if we're mid-update; this can happen on IE8 because image load events for // Check if we're mid-update; this can happen on IE8 because image load events for
@ -1649,11 +1649,11 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @private * @private
* @inner * @inner
* @param {OpenSeadragon.Tile} tile * @param {OpenSeadragon.Tile} tile
* @param {Image|* || undefined} image * @param {*} data image data
* @param {Number || undefined} cutoff * @param {Number || undefined} cutoff
* @param {XMLHttpRequest || undefined} tileRequest * @param {XMLHttpRequest || undefined} tileRequest
*/ */
_setTileLoaded: function(tile, image, cutoff, tileRequest) { _setTileLoaded: function(tile, data, cutoff, tileRequest) {
var increment = 0, var increment = 0,
_this = this; _this = this;
@ -1667,9 +1667,12 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
if (increment === 0) { if (increment === 0) {
tile.loading = false; tile.loading = false;
tile.loaded = true; tile.loaded = true;
tile.hasTransparency = this.source.hasTransparency(
tile.context2D, tile.url, tile.ajaxHeaders, tile.postData
);
if (!tile.context2D) { if (!tile.context2D) {
_this._tileCache.cacheTile({ _this._tileCache.cacheTile({
image: image, data: data,
tile: tile, tile: tile,
cutoff: cutoff, cutoff: cutoff,
tiledImage: _this tiledImage: _this
@ -1687,6 +1690,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
* @type {object} * @type {object}
* @property {Image|*} image - The image (data) of the tile. * @property {Image|*} image - The image (data) of the tile.
* @property {*} data - image data
* @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile. * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.
* @property {OpenSeadragon.Tile} tile - The tile which has been loaded. * @property {OpenSeadragon.Tile} tile - The tile which has been loaded.
* @property {XMLHttpRequest} tileRequest - The AJAX request that loaded this tile (if applicable). * @property {XMLHttpRequest} tileRequest - The AJAX request that loaded this tile (if applicable).
@ -1699,7 +1703,11 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
tile: tile, tile: tile,
tiledImage: this, tiledImage: this,
tileRequest: tileRequest, tileRequest: tileRequest,
image: image, get image() {
$.console.error("[tile-loaded] event property 'image' has been deprecated and will be removed in the future");
return data;
},
data: data,
getCompletionCallback: getCompletionCallback getCompletionCallback: getCompletionCallback
}); });
// In case the completion callback is never called, we at least force it once. // In case the completion callback is never called, we at least force it once.

View File

@ -712,7 +712,7 @@ $.TileSource.prototype = {
}, },
/** /**
* Decide whether tiles have transparency: this is crucial for * Decide whether tiles have transparency: this is crucial for correct images blending.
* @return {boolean} true if the image has transparency * @return {boolean} true if the image has transparency
*/ */
hasTransparency: function(context2D, url, ajaxHeaders, post) { hasTransparency: function(context2D, url, ajaxHeaders, post) {
@ -794,6 +794,14 @@ $.TileSource.prototype = {
} }
}, },
/**
* Provide means of aborting the execution.
* @param {object} context job, the same object as with downloadTileStart(..)
*/
downloadTileAbort: function (context) {
context.request.abort();
},
/** /**
* @param {object} context job, the same object as with downloadTileStart(..) * @param {object} context job, the same object as with downloadTileStart(..)
* @param successful true if successful * @param successful true if successful