From 7e3320c167d2b3436b5094c485d86640fcb43161 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Tue, 23 Feb 2016 19:37:41 -0500 Subject: [PATCH 1/3] Fix transparent images clearing the images in backgroumd. Fix #849 --- src/tile.js | 9 ++++--- src/tiledimage.js | 9 ++++++- test/modules/multi-image.js | 47 ++++++++++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 7 deletions(-) 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] + }; + } + }); + })(); From d18485844dc5d23aaa45127fcacadd5102165f97 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Wed, 24 Feb 2016 19:48:11 -0500 Subject: [PATCH 2/3] Fix crash and improve tests.. --- src/tiledimage.js | 12 +++++------- test/modules/multi-image.js | 30 +++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/tiledimage.js b/src/tiledimage.js index 562f1f92..53c640c4 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1329,13 +1329,11 @@ function compareTiles( previousBest, tile ) { } function drawTiles( tiledImage, lastDrawn ) { - var i, - tile = lastDrawn[0]; - - if ( tiledImage.opacity <= 0 ) { - drawDebugInfo( tiledImage, lastDrawn ); + if (lastDrawn.length === 0) { return; } + var tile = lastDrawn[0]; + var useSketch = tiledImage.opacity < 1 || (tiledImage.compositeOperation && tiledImage.compositeOperation !== 'source-over') || @@ -1346,7 +1344,7 @@ function drawTiles( tiledImage, lastDrawn ) { var zoom = tiledImage.viewport.getZoom(true); var imageZoom = tiledImage.viewportToImageZoom(zoom); - if (imageZoom > tiledImage.smoothTileEdgesMinZoom && tile) { + if (imageZoom > tiledImage.smoothTileEdgesMinZoom) { // 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; @@ -1403,7 +1401,7 @@ function drawTiles( tiledImage, lastDrawn ) { tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch); } - for ( i = lastDrawn.length - 1; i >= 0; i-- ) { + for (var i = lastDrawn.length - 1; i >= 0; i--) { tile = lastDrawn[ i ]; tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch, sketchScale, sketchTranslate ); tile.beingDrawn = true; diff --git a/test/modules/multi-image.js b/test/modules/multi-image.js index cee7867f..1cfd0515 100644 --- a/test/modules/multi-image.js +++ b/test/modules/multi-image.js @@ -214,7 +214,13 @@ // 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); + // Pixel 250,250 will be in the hole of the A + var expectedVal = getPixelValue(imageData, 250, 250); + + notEqual(expectedVal.r, 0, 'Red channel should not be 0'); + notEqual(expectedVal.g, 0, 'Green channel should not be 0'); + notEqual(expectedVal.b, 0, 'Blue channel should not be 0'); + notEqual(expectedVal.a, 0, 'Alpha channel should not be 0'); viewer.addSimpleImage({ url: '/test/data/A.png' @@ -223,23 +229,29 @@ // 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); + var actualVal = getPixelValue(imageData, 250, 250); equal(actualVal.r, expectedVal.r, - 'Red channel should not change when stacking a transparent image'); + 'Red channel should not change in transparent part of the A'); equal(actualVal.g, expectedVal.g, - 'Green channel should not change when stacking a transparent image'); + 'Green channel should not change in transparent part of the A'); equal(actualVal.b, expectedVal.b, - 'Blue channel should not change when stacking a transparent image'); + 'Blue channel should not change in transparent part of the A'); equal(actualVal.a, expectedVal.a, - 'Alpha channel should not change when stacking a transparent image'); + 'Alpha channel should not change in transparent part of the A'); + + var onAVal = getPixelValue(imageData, 333, 250); + equal(onAVal.r, 0, 'Red channel should be null on the A'); + equal(onAVal.g, 0, 'Green channel should be null on the A'); + equal(onAVal.b, 0, 'Blue channel should be null on the A'); + equal(onAVal.a, 255, 'Alpha channel should be 255 on the A'); start(); - }, 1000); - }, 1000); + }, 500); + }, 500); function getPixelValue(imageData, x, y) { - var offset = x * imageData.width + y; + var offset = 4 * (y * imageData.width + x); return { r: imageData.data[offset], g: imageData.data[offset + 1], From 963986d1874bd1a5089a1cb7e94e3a189e3fa7c9 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Wed, 24 Feb 2016 19:53:35 -0500 Subject: [PATCH 3/3] Add missing parenthesis. --- src/tiledimage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tiledimage.js b/src/tiledimage.js index 53c640c4..9f3acf46 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -1337,7 +1337,7 @@ function drawTiles( tiledImage, lastDrawn ) { var useSketch = tiledImage.opacity < 1 || (tiledImage.compositeOperation && tiledImage.compositeOperation !== 'source-over') || - (!tiledImage._isBottomItem() && tile._hasTransparencyChannel); + (!tiledImage._isBottomItem() && tile._hasTransparencyChannel()); var sketchScale; var sketchTranslate;