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(); }
Related
I'm using rot-js to draw a grid with hexagons and want to add triangles and other shapes to the canvas. I've tried acting on display.getContainer() but that's not working. What needs to be done to get this to work?
Setting ctx.globalCompositeOperation = "xor", I'm able to see the objects being drawn (but the colors are all wrong).
Setting ctx.globalAlpha = .8 also allows everything to be visible to an extent so I'm thinking this has something to do with layers.
If I work directly on an existing canvas element, drawing works fine.
Hard to tell for sure since you didn't provide anything about what you are actually doing, but given the description, I'll guess you are not waiting for the next frame before doing your own drawings over the ones made by the library.
The library stacks all its rendering operations in a requestAnimationFrame callback, so if you do it before, your drawings will be covered by the lib's ones.
To workaround this, simply wrap your own drawing operations in a requestAnimationFrame callback, it will get stacked after the ones of the lib, and will get drawn on top.
const display = new ROT.Display();
const canvas = display.getContainer();
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
// async calls
display.draw(5, 4, "#");
display.draw(15, 4, "%", "#0f0");
display.draw(25, 4, "#", "#f00", "#009");
// end async calls
// this will get covered
ctx.fillStyle = 'red';
ctx.fillRect(20,20,40,40);
// wait next frame
requestAnimationFrame(() => {
ctx.fillStyle = 'green';
ctx.fillRect(120,20,40,40);
})
<script src="https://cdn.jsdelivr.net/npm/rot-js"></script>
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';
I am a beginner at HTML5, Jquery/JavaScript.
I am attempting to create a canvas (sort of like windows paint application) and I am looking at other users sample functions/code to see whats it going on and attempt to re-create it.
$(function(){
var paint = new Paint($('#surface').get(0));
// Setup line template
var templateLine = new Paint($('#toolbar #line').get(0), {'readonly': true});
templateLine.shape = new Line([10, 10], [50, 50]);
templateLine.place(templateLine.shape);
I am unsure what is going on here. I know this new Paint is not an internal built-in function. What is it?
Secondly whats the difference between this and
$( document).ready(function(){
var canvas = $("#canvas").get(0);
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
// Choose a color
ctx.fillStyle = "black";
ctx.strokeStyle = color;
ctx.fillRect(0, 0, 50, 50);
} else {
// Browser doesn't support CANVAS
}
});
Help!!!
Well, first off, the code you're looking at in the beginning of your question was probably using some canvas library or API, but that is not the vanilla HTML5 Canvas API, making it completely different from what you've written below, even if they have the same output (although it doesn't look like they do).
Secondly, color is not defined, so unless that's defined in your code somewhere else, your code's not going to work. Otherwise, your code will draw a black rectangle in the corner of the canvas with the stroke color of whatever color is.
I made a jsFiddle which demonstrates pixel manipulation in JavaScript. It works perfectly fine in Chrome. Then I moved to test it on Firefox.
It doesn't work and it threw an error:
IndexSizeError: Index or size is negative or greater than the allowed amount
This confuses me. But wait, there's more.
When I click Run again, the code suddenly works. I don't know what sorcery is this, or it's just some weird Firefox bug.
You can see the problem here: http://jsfiddle.net/DerekL/RdK7H/
When you are in jsFiddle, click on Select File and select a PNG file. You should see the code is not working. Then you click Run. Do the same thing again, and it suddenly works.
There are also some problems in some of the functions in Firefox which also frustrated me, however it is not part of this question.
If you need to know, I'm using Firefox 26.0.
It is because your image hasn't completed loading yet so the default width and height of the image is returned (both 0). As you cannot use 0 for the width and height of getImageData() you get an error.
When I click Run again, the code suddenly works. I don't know what
sorcery is this, or it's just some weird Firefox bug.
It's because the image is now in the cache and the browser happens to be able to provide it before you attempt to read its width and height (no, the bug is in your code :-) ).
Handling image loading with a busy loop and a timeout value is begging to fail.
Make sure you add an onload handler to the image (this may require you to refactor the code a bit to support a callback (or promise) and the return value won't be valid for the same reason as the error):
getRGBArray: function(uri, callback){ /// add parameter for callback here
var image = new Image();
image.onload = imageLoaded; /// add an onload handler here
image.src = uri;
function imageLoaded() {
//var t = Date.now();
//while(Date.now() - t < 3000 && !image.width);
var width = this.width, /// replace image with this to be sure you
height = this.height, /// ..are dealing with the correct image in
canvas = $("<canvas>").attr({ /// ..case you load several ones..
width: width,
height: height
}).appendTo("body"),
ctx = canvas[0].getContext("2d");
ctx.drawImage(this, 0, 0);
var imgData = ctx.getImageData(0, 0, width, height).data;
...
callback(imgData); /// example of callback
}
...
}
Optionally separate the image loading so you can call this function without relying on if the image has loaded or not.
Update
As briefly mentioned you can separate the image loading from the your main code. For example - instead of loading your image in the getRGBArray() function, pre-load it somewhere else in the code and pass the image as an argument instead (callback cannot be avoided but you can keep your original code synchronous after the loading point):
function loadImage(url, callback) {
var image = new Image();
image.onload = function() {
callback(this);
}
image.src = uri;
}
Then call it for example like this:
loadImage(url, readyToGo);
function readyToGo(image) {
var pixels = getRGBArray(image);
...
}
A small modification in the original function to make it use the passed image instead of url:
getRGBArray: function(image){
var width = image.width,
height = image.height,
canvas = $("<canvas>").attr({
width: width,
height: height
}).appendTo("body"),
ctx = canvas[0].getContext("2d");
ctx.drawImage(image, 0, 0);
var imgData = ctx.getImageData(0, 0, width, height).data;
...
return opt;
}
...
}
Hope this helps!
I was trying to draw an image (png-file) to a to act as a background-image and I do not know why the js i have thus far is not working.
Here's what I have:
var canvas = document.getElementById('hplogo-z');
var cnvs = canvas.getContext('2d');
background = new Image();
background.onload = function(){
cnvs.drawImage(background, x, y);
}
background.src = 'bg.png';
Any ideas on what I am doing wrong?
I was unable to reproduce your problem, so the only things I can guess are that your path is wrong or there is something wrong with your image.
I would recommend you attempt to replace your current path with something from placehold.it, or use a different image in a different location in order to see if your image/path is indeed the problem.