diff --git a/src/tile.js b/src/tile.js index 9abb14b6..1144d797 100644 --- a/src/tile.js +++ b/src/tile.js @@ -193,6 +193,11 @@ $.Tile.prototype = { return this.level + "/" + this.x + "_" + this.y; }, + // private + _hasTransparencyChannel: function() { + return this.context2D || this.url.match('.png'); + }, + /** * Renders the tile in an html container. * @function @@ -284,8 +289,7 @@ $.Tile.prototype = { //ie its done fading or fading is turned off, and if we are drawing //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.context2D || this.url.match('.png'))) { + if (context.globalAlpha === 1 && this._hasTransparencyChannel()) { //clearing only the inside of the rectangle occupied //by the png prevents edge flikering context.clearRect( @@ -294,7 +298,6 @@ $.Tile.prototype = { size.x - 2, size.y - 2 ); - } // This gives the application a chance to make image manipulation diff --git a/src/tiledimage.js b/src/tiledimage.js index 7ad9d7f2..562f1f92 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -650,6 +650,11 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag * @property {?Object} userData - Arbitrary subscriber-defined object. */ this.raiseEvent('bounds-change'); + }, + + // private + _isBottomItem: function() { + return this.viewer.world.getItemAt(0) === this; } }); @@ -1332,7 +1337,9 @@ function drawTiles( tiledImage, lastDrawn ) { return; } var useSketch = tiledImage.opacity < 1 || - (tiledImage.compositeOperation && tiledImage.compositeOperation !== 'source-over'); + (tiledImage.compositeOperation && + tiledImage.compositeOperation !== 'source-over') || + (!tiledImage._isBottomItem() && tile._hasTransparencyChannel); var sketchScale; var sketchTranslate; diff --git a/test/modules/multi-image.js b/test/modules/multi-image.js index f3710429..cee7867f 100644 --- a/test/modules/multi-image.js +++ b/test/modules/multi-image.js @@ -5,12 +5,12 @@ module( 'Multi-Image', { setup: function() { - $( '
' ).appendTo( "#qunit-fixture" ); + $( '
' ).appendTo( "#qunit-fixture" ); testLog.reset(); viewer = OpenSeadragon( { - id: 'itemsexample', + id: 'example', prefixUrl: '/build/openseadragon/images/', springStiffness: 100 // Faster animation = faster tests }); @@ -21,7 +21,7 @@ } viewer = null; - $( "#itemsexample" ).remove(); + $("#example").remove(); } } ); @@ -208,4 +208,45 @@ viewer.open('/test/data/testpattern.dzi'); }); + asyncTest('Transparent image on top of others', function() { + viewer.open('/test/data/testpattern.dzi'); + + // TODO: replace with fully-loaded event listener when available. + setTimeout(function() { + var imageData = viewer.drawer.context.getImageData(0, 0, 500, 500); + var expectedVal = getPixelValue(imageData, 333, 250); + + viewer.addSimpleImage({ + url: '/test/data/A.png' + }); + + // TODO: replace with fully-loaded event listener when available. + setTimeout(function() { + var imageData = viewer.drawer.context.getImageData(0, 0, 500, 500); + var actualVal = getPixelValue(imageData, 333, 250); + + equal(actualVal.r, expectedVal.r, + 'Red channel should not change when stacking a transparent image'); + equal(actualVal.g, expectedVal.g, + 'Green channel should not change when stacking a transparent image'); + equal(actualVal.b, expectedVal.b, + 'Blue channel should not change when stacking a transparent image'); + equal(actualVal.a, expectedVal.a, + 'Alpha channel should not change when stacking a transparent image'); + + start(); + }, 1000); + }, 1000); + + function getPixelValue(imageData, x, y) { + var offset = x * imageData.width + y; + return { + r: imageData.data[offset], + g: imageData.data[offset + 1], + b: imageData.data[offset + 2], + a: imageData.data[offset + 3] + }; + } + }); + })();