Safari createPattern fails with SVGs: suggestions for alternatives? - javascript

I am using an SVG image as a background pattern for an HTML5 canvas element, using the following syntax:
var img = new Image();
img.onload = function() {
var pattern = badge.createPattern(img, 'repeat');
badge.fillStyle = pattern;
// draw 'badge' shape
badge.fill();
};
img.src = '../flags/iso/'+country+'.svg';
This works as expected in Firefox and Chrome, but in Safari (7.0.3) the background is blank (white). Using a png or jpg for the background image works as expected in Safari et al - it's only SVGs that render incorrectly.
Any pointers gratefully received. There are many other reports of Safari SVG bugs around, but I'm unsure if this is specific to that, or something to do with Canvas implementation.
UPDATE: This is a previously reported bug in Safari, but no action seems to have been taken. Problem is using SVG to createPattern.
If Safari cannot load SVGs with createPattern, are there any other alternatives to loading images into irregular shapes (polygons) in the canvas, acting as background images?

Possible workaround
You could try getting around by creating a bitmap image from the SVG first via canvas, then use that canvas as image source for the pattern:
var img = new Image();
img.onload = function() {
// canvas image source for pattern:
var svgCanvas = document.createElement("canvas");
svgCanvas.width = this.width;
svgCanvas.height = this.height;
// draw in the SVG to canvas
var svgCtx = svgCanvas.getContext("2d");
svgCtx.drawImage(this, 0, 0, this.width, this.height);
// use canvas as image source instead
var pattern = badge.createPattern(svgCanvas, 'repeat');
badge.fillStyle = pattern;
// draw 'badge' shape
badge.fill();
};
img.src = '../flags/iso/'+country+'.svg';

Related

Javascript Canvas draw image to buffer only

I'm using Canvas to process an image in various ways using it's image data only. I'm getting the image like this:
const vid = document.querySelector('video');
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
But if I don't physically draw the image on the screen like this:
context.drawImage(vid, 0, 0, canvas.width, canvas.height);
then I can't process it's image data...is there any way this can all be done in data? I have no use to display the image in my app at all. Is there any way to draw it to the buffer only or something?
All I'm doing is capturing the image and then processing it's image data so I have no need to display it anywhere.
You can dynamically create a canvas element using Javascript like
var canvas=document.createElement("canvas");
get it's context
var context = canvas.getContext('2d');
and ultimately don't append it to the DOM by omitting
document.body.appendChild(canvas);
Even though you're still able to do all drawing operations e.g. drawImage()

Svg to canvas conversion using Fabric Js taints the canvas

I am using fabric.js to convert svg to canvas, the code that i use works fine in chrome but in IE 11 the canvas that is created is getting tainted thus preventing me from reading data from canvas,below is code that i use
var d3canvas = document.createElement('canvas');
d3canvas.id = canvasId;
fabric.loadSVGFromString(svg.node().parentNode.innerHTML, function (objects, options) {
var canvasObj = new fabric.Canvas(canvasId);
var obj = fabric.util.groupSVGElements(objects, options);
canvasObj.add(obj).renderAll();
var canvasdata = d3canvas.toDataURL("image/bmp");//this line causes error as canvas is tainted
}
my question is whether there is a way to create canvas from svg without tainting the canvas in Fabric.js?
Note:I have already used canvg to convert svg to canvas but as the svg is complex its not getting properly converted to canvas
First deselect all object of canvas and use below code to convert canvas to SVG.
canvas.deactivateAllWithDispatch();
canvas.renderAll();
var image = canvas.toSVG();
var svg_image = "data:image/svg+xml,"+encodeURIComponent(image);
You will get SVG image value into svg_image variable.

Can an image be created from a new canvas object?

I'm attempting to create a new canvas, do some clipping operations on an image, and returning the new image.
But, even without doing anything to the image, I get an error when trying to render the image my method returns.
The HTMLImageElement provided is in the 'broken' state.
Here is my code:
let image = ImageUtils.getImage("path_to_my_image.jpg");
let canvas = document.createElement("canvas");
canvas.width = texture.width;
canvas.height = texture.height;
let g = canvas.getContext("2d");
g.drawImage(image, 0, 0);
let newImage = new Image();
newImage.src = canvas.toDataURL("image/jpeg");
return newImage;
I'm able to render the image normally if I don't try to generate it from a new canvas object, so I know that's not the issue. I've searched around quite a bit and haven't seen much on the topic.

canvas toDataURL() returns transparent image

I am attempting to use a chrome extension to take a screenshot of the current page, and then draw some shapes on it. After I have done that to the image, I turn the whole thing into a canvas that way it is all together, like the divs I have drawn on it are now baked into the 'image', and they are one in the same. After doing this, I want to turn the canvas back into a png image I can use to push to a service I have, but when I go to use the canvas.toDataURL() in order to do so, the image source that it creates is completely transparent. If I do it as a jpeg, it is completely black.
I read something about the canvas being 'dirtied' because I have drawn an image to it, and that this won't work in Chrome, but that doesn't make sense to me as I have gotten it to work before, but I am unable to use my previous method. Below is the code snippet that isn't working. I am just making a canvas element, and then I am drawing an image before that.
var passes = rectangles.length;
var run = 0;
var context = hiDefCanvas.getContext('2d');
while (run < passes) {
var rect = rectangles[run];
// Set the stroke and fill color
context.strokeStyle = 'rgba(0,255,130,0.7)';
context.fillStyle = 'rgba(0,0,255,0.1)';
context.rect(rect.left, rect.top, rect.width, rect.height);
context.setLineDash([2,1]);
context.lineWidth = 2;
run++;
} // end of the while loop
screencapImage.className = 'hide';
context.fill();
context.stroke();
console.log(hiDefCanvas.toDataURL());
And the image data that it returns is: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACWAAAAVGCAYAAAAaGIAxAAAgAElEQ…ECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQBVKBUe32pNYAAAAAElFTkSuQmCC which is a blank, transparent image.
Is there something special I need to do with Chrome? Is there something that I am missing? Thanks, I appreciate the time and help.
Had the same problem, and found the solution here:
https://bugzilla.mozilla.org/show_bug.cgi?id=749824
"I can confirm, that it works if you set preserveDrawingBuffer.
var glContextAttributes = { preserveDrawingBuffer: true };
var gl = canvas.getContext("experimental-webgl", glContextAttributes);"
After getting the context with preserveDrawingBuffer, toDataURL just works as expected, no completely transparent or black image.
Having a similar problem I found a solution, thanks to the following post
https://github.com/iddan/react-native-canvas/issues/29.
These methods return a promise, so you would need to wait for it to resolve before the variable can be populated.
My solution was to set asyn function and await for the result:
const canvas = <HTMLCanvasElement>document.getElementById("myCanvas")[0];
let ctx = canvas.getContext('2d');
let img = new Image();
img.onload = async (e) => { ctx.drawImage(img, 0, 0); ctx.font = "165px Arial";ctx.fillStyle = "white"; b64Code = await (<any>canvas).toDataURL(); }

Get color of pixel of existing base64-image via canvas

Got a image inside of a HTML document. Source is a base64 string. I want to retrieve the color of the pixel that is clicked on. Using a memory canvas all I get is zeros.
function getColor(imagecontainer,top,left){
var image = new Image();
image.onload = function() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
var myData = context.getImageData(Math.round(left)-2, Math.round(top)-2, 4, 4).data;
console.log(myData, left, top);
};
image.src = imagecontainer.find("img").attr("src");
}
There are many other questions regarding the same problem, however none of the solutions could solve this problem for me. MyData always contains zeros.
Update based on new information:
The cause could simply be that the main image (imagecontainer.find("img")) isn't loaded at the time it is references.
If this image exists in DOM you can use windows.onload to run your script:
window.onload = function() {
// code that uses the image
};
as this will run only when everything has loaded incl. image data. Optionally add an inline onload handler to the image tag (not recommended), or add the src via JavaScript and monitor the onload event there.
Another possible cause is that if this is IE and the image is in the cache, onload may not trigger. You can check the image's complete property to check for this:
var image = new Image();
image.onload = onloadHandler;
image.src = imagecontainer.find("img").attr("src");
if (image.complete) onloadHandler();
function onloadHandler() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
var myData = context.getImageData(Math.round(left)-2, Math.round(top)-2, 4, 4).data;
};
Although you can use this directly with the original image without loading another with the same url.

Categories