diff --git a/examples/data/square.svg b/examples/data/square.svg index 0b7a912a53..e7a5e249f3 100644 --- a/examples/data/square.svg +++ b/examples/data/square.svg @@ -2,6 +2,6 @@ - + diff --git a/examples/icon-color.js b/examples/icon-color.js index e88e3d52b8..11b30dd50e 100644 --- a/examples/icon-color.js +++ b/examples/icon-color.js @@ -25,6 +25,7 @@ rome.setStyle(new Style({ image: new Icon({ color: '#8959A8', crossOrigin: 'anonymous', + imgSize: [20, 20], src: 'data/square.svg' }) })); diff --git a/src/ol/style/IconImage.js b/src/ol/style/IconImage.js index d2361e5bb7..38ca4cda5c 100644 --- a/src/ol/style/IconImage.js +++ b/src/ol/style/IconImage.js @@ -85,15 +85,18 @@ class IconImage extends EventTarget { /** * @private + * @param {CanvasRenderingContext2D=} context A context with the image already drawn into. * @return {boolean} The image canvas is tainted. */ - isTainted_() { + isTainted_(context) { if (this.tainted_ === undefined && this.imageState_ === ImageState.LOADED) { - this.tainted_ = false; - const context = createCanvasContext2D(1, 1); - try { + if (!context) { + context = createCanvasContext2D(1, 1); context.drawImage(this.image_, 0, 0); + } + try { context.getImageData(0, 0, 1, 1); + this.tainted_ = false; } catch (e) { this.tainted_ = true; } @@ -203,7 +206,7 @@ class IconImage extends EventTarget { * @private */ replaceColor_() { - if (!this.color_ || this.isTainted_()) { + if (!this.color_) { return; } @@ -213,6 +216,25 @@ class IconImage extends EventTarget { const ctx = this.canvas_.getContext('2d'); ctx.drawImage(this.image_, 0, 0); + if (this.isTainted_(ctx)) { + // If reading from the canvas throws a SecurityError the same effect can be + // achieved with globalCompositeOperation. + // This could be used as the default, but it is not fully supported by all + // browsers. E. g. Internet Explorer 11 does not support the multiply + // operation and the resulting image shape will be completelly filled with + // the provided color. + // So this is only used as a fallback. It is still better than having no icon + // at all. + const c = this.color_; + ctx.globalCompositeOperation = 'multiply'; + ctx.fillStyle = 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')'; + ctx.fillRect(0, 0, this.image_.width, this.image_.height); + + ctx.globalCompositeOperation = 'destination-in'; + ctx.drawImage(this.image_, 0, 0); + return; + } + const imgData = ctx.getImageData(0, 0, this.image_.width, this.image_.height); const data = imgData.data; const r = this.color_[0] / 255.0;