mirror of
https://github.com/openseadragon/openseadragon.git
synced 2025-02-16 14:53:14 +03:00
Better tile caching for duplicate images
This commit is contained in:
parent
8466a91470
commit
8641279890
28
src/tile.js
28
src/tile.js
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function( $ ){
|
(function( $ ){
|
||||||
var TILE_CACHE = {};
|
|
||||||
/**
|
/**
|
||||||
* @class Tile
|
* @class Tile
|
||||||
* @memberof OpenSeadragon
|
* @memberof OpenSeadragon
|
||||||
@ -241,16 +241,23 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
rendered,
|
rendered,
|
||||||
canvas;
|
canvas;
|
||||||
|
|
||||||
if ( !this.loaded || !( this.image || TILE_CACHE[ this.url ] ) ){
|
if (!this.cacheImageRecord) {
|
||||||
|
$.console.warn('[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', this.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rendered = this.cacheImageRecord.getRenderedContext();
|
||||||
|
|
||||||
|
if ( !this.loaded || !( this.image || rendered) ){
|
||||||
$.console.warn(
|
$.console.warn(
|
||||||
"Attempting to draw tile %s when it's not yet loaded.",
|
"Attempting to draw tile %s when it's not yet loaded.",
|
||||||
this.toString()
|
this.toString()
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.globalAlpha = this.opacity;
|
|
||||||
|
|
||||||
//context.save();
|
context.globalAlpha = this.opacity;
|
||||||
|
|
||||||
//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
|
||||||
@ -268,24 +275,21 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !TILE_CACHE[ this.url ] ){
|
if(!rendered){
|
||||||
canvas = document.createElement( 'canvas' );
|
canvas = document.createElement( 'canvas' );
|
||||||
canvas.width = this.image.width;
|
canvas.width = this.image.width;
|
||||||
canvas.height = this.image.height;
|
canvas.height = this.image.height;
|
||||||
rendered = canvas.getContext('2d');
|
rendered = canvas.getContext('2d');
|
||||||
rendered.drawImage( this.image, 0, 0 );
|
rendered.drawImage( this.image, 0, 0 );
|
||||||
TILE_CACHE[ this.url ] = rendered;
|
this.cacheImageRecord.setRenderedContext(rendered);
|
||||||
//since we are caching the prerendered image on a canvas
|
//since we are caching the prerendered image on a canvas
|
||||||
//allow the image to not be held in memory
|
//allow the image to not be held in memory
|
||||||
this.image = null;
|
this.image = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
rendered = TILE_CACHE[ this.url ];
|
|
||||||
|
|
||||||
// This gives the application a chance to make image manipulation changes as we are rendering the image
|
// This gives the application a chance to make image manipulation changes as we are rendering the image
|
||||||
drawingHandler({context: context, tile: this, rendered: rendered});
|
drawingHandler({context: context, tile: this, rendered: rendered});
|
||||||
|
|
||||||
//rendered.save();
|
|
||||||
context.drawImage(
|
context.drawImage(
|
||||||
rendered.canvas,
|
rendered.canvas,
|
||||||
0,
|
0,
|
||||||
@ -297,9 +301,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
size.x,
|
size.x,
|
||||||
size.y
|
size.y
|
||||||
);
|
);
|
||||||
//rendered.restore();
|
|
||||||
|
|
||||||
//context.restore();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,9 +314,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
if ( this.element && this.element.parentNode ) {
|
if ( this.element && this.element.parentNode ) {
|
||||||
this.element.parentNode.removeChild( this.element );
|
this.element.parentNode.removeChild( this.element );
|
||||||
}
|
}
|
||||||
if ( TILE_CACHE[ this.url ]){
|
|
||||||
delete TILE_CACHE[ this.url ];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element = null;
|
this.element = null;
|
||||||
this.imgElement = null;
|
this.imgElement = null;
|
||||||
|
@ -43,6 +43,53 @@ var TileRecord = function( options ) {
|
|||||||
this.tiledImage = options.tiledImage;
|
this.tiledImage = options.tiledImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// private
|
||||||
|
var ImageRecord = function(options) {
|
||||||
|
$.console.assert( options, "[ImageRecord] options is required" );
|
||||||
|
$.console.assert( options.image, "[ImageRecord] options.image is required" );
|
||||||
|
this._image = options.image;
|
||||||
|
this._tiles = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageRecord.prototype = {
|
||||||
|
destroy: function() {
|
||||||
|
this._image = null;
|
||||||
|
this._renderedContext = null;
|
||||||
|
this._tiles = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getImage: function() {
|
||||||
|
return this._image;
|
||||||
|
},
|
||||||
|
|
||||||
|
getRenderedContext: function() {
|
||||||
|
return this._renderedContext;
|
||||||
|
},
|
||||||
|
|
||||||
|
setRenderedContext: function(renderedContext) {
|
||||||
|
this._renderedContext = renderedContext;
|
||||||
|
},
|
||||||
|
|
||||||
|
addTile: function(tile) {
|
||||||
|
this._tiles.push(tile);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTile: function(tile) {
|
||||||
|
for (var i = 0; i < this._tiles.length; i++) {
|
||||||
|
if (this._tiles[i] === tile) {
|
||||||
|
this._tiles.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTileCount: function() {
|
||||||
|
return this._tiles.length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class TileCache
|
* @class TileCache
|
||||||
* @memberof OpenSeadragon
|
* @memberof OpenSeadragon
|
||||||
@ -54,8 +101,10 @@ var TileRecord = function( options ) {
|
|||||||
$.TileCache = function( options ) {
|
$.TileCache = function( options ) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
this._tilesLoaded = [];
|
|
||||||
this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount;
|
this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount;
|
||||||
|
this._tilesLoaded = [];
|
||||||
|
this._imagesLoaded = [];
|
||||||
|
this._imagesLoadedCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
$.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||||
@ -69,7 +118,10 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches the specified tile, removing an old tile if necessary to stay under the
|
* Caches the specified tile, removing an old tile if necessary to stay under the
|
||||||
* maxImageCacheCount specified on construction.
|
* maxImageCacheCount specified on construction. Note that if multiple tiles reference
|
||||||
|
* the same image, there may be more tiles than maxImageCacheCount; the goal is to keep
|
||||||
|
* the number of images below that number. Note, as well, that even the number of images
|
||||||
|
* may temporarily surpass that number, but should eventually come back down to the max specified.
|
||||||
* @param {Object} options - Tile info.
|
* @param {Object} options - Tile info.
|
||||||
* @param {OpenSeadragon.Tile} options.tile - The tile to cache.
|
* @param {OpenSeadragon.Tile} options.tile - The tile to cache.
|
||||||
* @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.
|
* @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.
|
||||||
@ -80,12 +132,28 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
|||||||
cacheTile: function( options ) {
|
cacheTile: function( options ) {
|
||||||
$.console.assert( options, "[TileCache.cacheTile] options is required" );
|
$.console.assert( options, "[TileCache.cacheTile] options is required" );
|
||||||
$.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" );
|
$.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" );
|
||||||
|
$.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" );
|
||||||
|
$.console.assert( options.tile.image, "[TileCache.cacheTile] options.tile.image is required" );
|
||||||
$.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" );
|
$.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" );
|
||||||
|
|
||||||
var cutoff = options.cutoff || 0;
|
var cutoff = options.cutoff || 0;
|
||||||
var insertionIndex = this._tilesLoaded.length;
|
var insertionIndex = this._tilesLoaded.length;
|
||||||
|
|
||||||
if ( this._tilesLoaded.length >= this._maxImageCacheCount ) {
|
var imageRecord = this._imagesLoaded[options.tile.url];
|
||||||
|
if (!imageRecord) {
|
||||||
|
imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({
|
||||||
|
image: options.tile.image
|
||||||
|
});
|
||||||
|
|
||||||
|
this._imagesLoadedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageRecord.addTile(options.tile);
|
||||||
|
options.tile.cacheImageRecord = imageRecord;
|
||||||
|
|
||||||
|
// Note that just because we're unloading a tile doesn't necessarily mean
|
||||||
|
// we're unloading an image. With repeated calls it should sort itself out, though.
|
||||||
|
if ( this._imagesLoadedCount >= this._maxImageCacheCount ) {
|
||||||
var worstTile = null;
|
var worstTile = null;
|
||||||
var worstTileIndex = -1;
|
var worstTileIndex = -1;
|
||||||
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;
|
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;
|
||||||
@ -115,7 +183,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( worstTile && worstTileIndex >= 0 ) {
|
if ( worstTile && worstTileIndex >= 0 ) {
|
||||||
worstTile.unload();
|
this._unloadTile(worstTile);
|
||||||
insertionIndex = worstTileIndex;
|
insertionIndex = worstTileIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,11 +202,29 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
|||||||
for ( var i = 0; i < this._tilesLoaded.length; ++i ) {
|
for ( var i = 0; i < this._tilesLoaded.length; ++i ) {
|
||||||
tileRecord = this._tilesLoaded[ i ];
|
tileRecord = this._tilesLoaded[ i ];
|
||||||
if ( tileRecord.tiledImage === tiledImage ) {
|
if ( tileRecord.tiledImage === tiledImage ) {
|
||||||
tileRecord.tile.unload();
|
this._unloadTile(tileRecord.tile);
|
||||||
this._tilesLoaded.splice( i, 1 );
|
this._tilesLoaded.splice( i, 1 );
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getImageRecord: function(url) {
|
||||||
|
return this._imagesLoaded[url];
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_unloadTile: function(tile) {
|
||||||
|
tile.unload();
|
||||||
|
tile.cacheImageRecord = null;
|
||||||
|
|
||||||
|
var imageRecord = this._imagesLoaded[tile.url];
|
||||||
|
imageRecord.removeTile(tile);
|
||||||
|
if (!imageRecord.getTileCount()) {
|
||||||
|
imageRecord.destroy();
|
||||||
|
delete this._imagesLoaded[tile.url];
|
||||||
|
this._imagesLoadedCount--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,6 +485,19 @@ function updateTile( tiledImage, drawLevel, haveDrawn, x, y, level, levelOpacity
|
|||||||
tiledImage
|
tiledImage
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!tile.loaded) {
|
||||||
|
var imageRecord = tiledImage._tileCache.getImageRecord(tile.url);
|
||||||
|
if (imageRecord) {
|
||||||
|
tile.loaded = true;
|
||||||
|
tile.image = imageRecord.getImage();
|
||||||
|
|
||||||
|
tiledImage._tileCache.cacheTile({
|
||||||
|
tile: tile,
|
||||||
|
tiledImage: tiledImage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( tile.loaded ) {
|
if ( tile.loaded ) {
|
||||||
var needsUpdate = blendTile(
|
var needsUpdate = blendTile(
|
||||||
tiledImage,
|
tiledImage,
|
||||||
|
@ -9,12 +9,15 @@
|
|||||||
var testInitialOpen = false;
|
var testInitialOpen = false;
|
||||||
var testOverlays = false;
|
var testOverlays = false;
|
||||||
var testMargins = false;
|
var testMargins = false;
|
||||||
|
var testNavigator = false;
|
||||||
var margins;
|
var margins;
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
debugMode: true,
|
debugMode: true,
|
||||||
zoomPerScroll: 1.02,
|
zoomPerScroll: 1.02,
|
||||||
showNavigator: true,
|
showNavigator: testNavigator,
|
||||||
|
wrapHorizontal: true,
|
||||||
|
wrapVertical: true,
|
||||||
id: "contentDiv",
|
id: "contentDiv",
|
||||||
prefixUrl: "../../../build/openseadragon/images/"
|
prefixUrl: "../../../build/openseadragon/images/"
|
||||||
};
|
};
|
||||||
@ -83,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this.crossTest3();
|
// this.crossTest3();
|
||||||
this.basicTest();
|
this.crossTest2();
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
@ -119,7 +122,8 @@
|
|||||||
self.viewer.addTiledImage( options );
|
self.viewer.addTiledImage( options );
|
||||||
});
|
});
|
||||||
|
|
||||||
this.viewer.open("../../data/tall.dzi", {
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/tall.dzi",
|
||||||
x: 1.5,
|
x: 1.5,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 1
|
width: 1
|
||||||
@ -129,12 +133,13 @@
|
|||||||
// ----------
|
// ----------
|
||||||
crossTest2: function() {
|
crossTest2: function() {
|
||||||
this.viewer.open([
|
this.viewer.open([
|
||||||
|
// {
|
||||||
|
// tileSource: "../../data/tall.dzi",
|
||||||
|
// x: 1.5,
|
||||||
|
// y: 0,
|
||||||
|
// width: 1
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
tileSource: "../../data/tall.dzi",
|
|
||||||
x: 1.5,
|
|
||||||
y: 0,
|
|
||||||
width: 1
|
|
||||||
}, {
|
|
||||||
tileSource: '../../data/wide.dzi',
|
tileSource: '../../data/wide.dzi',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -184,7 +189,7 @@
|
|||||||
self.viewer.world.addHandler('add-item', function() {
|
self.viewer.world.addHandler('add-item', function() {
|
||||||
loaded++;
|
loaded++;
|
||||||
if (loaded === expected) {
|
if (loaded === expected) {
|
||||||
self.viewer.viewport.goHome();
|
self.viewer.viewport.goHome(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -208,7 +213,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.viewer.open("../../data/testpattern.dzi", {
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
x: startX,
|
x: startX,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 1
|
width: 1
|
||||||
@ -217,7 +223,8 @@
|
|||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
bigTest: function() {
|
bigTest: function() {
|
||||||
this.viewer.open("../../data/testpattern.dzi", {
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
x: -2,
|
x: -2,
|
||||||
y: -2,
|
y: -2,
|
||||||
width: 6
|
width: 6
|
||||||
@ -246,7 +253,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.viewer.open(dzi, {
|
this.viewer.open({
|
||||||
|
tileSource: dzi,
|
||||||
width: 100
|
width: 100
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user