html5 canvas memory leak - javascript

I am developing a camera based SPA. When I'm trying to resize the image it cause to a memory leak.
without executing resize
first executing resize
.
second executing resize
The memory never go down until I do refresh.
It is strange the same app http://shitu.baidu.com does release the memory.
Here is the my resize function.
var useRightPen = function (img, pre_img_wid, pre_img_hei, aft_img_wid, aft_img_hei, callback) {
var canvas = document.createElement('canvas');
var ctx=canvas.getContext('2d');
canvas.setAttribute("height", aft_img_hei);
canvas.setAttribute("width", aft_img_wid);
var orientation = 1;
if (!!(/http/.test(img.src))) {
//memory keeps the same before the drawimage
canvas.getContext('2d').drawImage(img, 0, 0, aft_img_wid, aft_img_hei);
//memory goes up after the draimage
callback(canvas.toDataURL('image/jpeg'), aft_img_wid, aft_img_hei);
}
canvas = null;
}
Appreciate for everyone.
---update--06-11--2015
I make one fildde http://jsfiddle.net/onTheRoad/dc17guba/
The demo will reset the image src after every pick.Memory goes high on its way.

Related

Android 4.2 Stock browser. Canvas clearRect() sometimes doesn't work

So I have a problem with clearRect in js-canvas-animation. This problem happens only on Android API 16, and only in the moment when animation is restart.
I'm using setInterval() for my animation (here is simplify code)
function start() {
clearInterval(animationInterval);
x = 0;
canvas = document.getElementById("animationCanvas");
ctx = canvas.getContext("2d");
animationInterval = setInterval(func, 30);
}
function func() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(halfWidth - x, 0, 250, 150);
x += extensionStep;
}
It is look like a shore. But every time, when i restart animation with help start function, under new animation i see last frame previous animation. Already i was trying beginPath(), save, stroke. I check all question on SO and nothing.
How i can clear the background under animation?
So after several hours, i found one of the solves. It is strange bug for old android, because new android (i checked on api 24) it fixed. For hard cleaning you can detach canvas from DOM and reattach again:
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.style.display = 'none';// Detach from DOM
canvas.offsetHeight; // Force the detach
canvas.style.display = 'inherit'; // Reattach to DOM
It is simple operation and is not resource intensive.

Run requestAnimationFrame in background

I am using requestAnimationFrame to animate video streams and I know that request animation does not work in backgrounds so is there any way to make it run on background.
I know that we can animate using setInterval or setTimeout too but when I use these, animations were not work properly and images on video stream were blinking.
Here is my code:
const drawFrame = function drawFrame() {
if (!ctx) {
ctx = canvas.getContext('2d');
}
if (!tmpCanvas) {
tmpCanvas = document.createElement('canvas');
tmpCtx = tmpCanvas.getContext('2d');
tmpCanvas.width = canvas.width;
tmpCanvas.height = canvas.height;
}
tmpCtx.drawImage(videoElement, 0, 0, tmpCanvas.width, tmpCanvas.height);
const imgData = tmpCtx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
const data = selectedFilter(imgData);
ctx.putImageData(data, 0, 0);
if (!stopped) {
requestAnimationFrame(drawFrame);
} else {
tmpCanvas = null;
tmpCtx = null;
ctx = null;
}
};
requestAnimationFrame(drawFrame);
I guess you are out of luck. requestAnimationFrame intentionally pauses in the background because animations have no reason to be running in the background, and as you mention setInterval and setTimeout are not designed for animation and should not be used as such.
You mention that you need to animate a video stream. Do you mean that you are applying an animation on top of a video tag, or changing the appearance of the video element via a canvas element? In both cases, you shouldn't continue to do so in the background anyway, but you may give computeFrame (Firefox only) a go, which will fire once every frame of the video. Or is it that you are actually faking a video stream by animating a set of static images in succession? In that case, why are you not using the video element?

Making a 'History Panel' for a paint program

I'm making a very simple 'pixel-painting' program using HTML5/Canvas.
I'd like to give the user an option to go back in 'history', like the History panel in Photoshop / Adobe programs.
Basically it would be an undo button, but you'd be able to go back to the start of your actions, and there would also be a log showing the details of each action.
Is this possible? How would I even start storing this data?
How much memory is available within the Chrome browser in order to allow this on one page? – (Sorry if that is silly to ask, still quite new to Javascript and working within the browser.)
I have read this undo button Question, which is similar but I'd like to make the info about data being stored visible.
Thank you so so much for any help you can give!
You would need to build a simple undo-redo stack. Then you need to decide if you will store vector data or image data. The latter is more efficient but can also take up much more memory. You may have cases where you want to store both types of data (path on top of images).
The method would be in simple steps:
Store initial state for the new document. Keep a stack pointer pointing to the next free slot (for example using an array).
When mouse down is hit (or some other operation that will cause a change is started) move stack pointer forward.
When mouse button is released, make a snapshot, create thumbnail etc. It's up to you if you want to store the drawing as points or as a bitmap. If bitmap data you can get around storage space by compressing it using for example zip. Move stack pointer forward. If there exists snapshots in the stack at this point remove them.
When you need to undo, simply draw back previous stored step and move the stack pointer back. By keeping the snapshots you can do redo by moving stack pointer forward and redraw the snapshot, if any.
And finally, to visualize the undo-redo stack you can simply render each snapshot to a separate canvas at scale and extract that as an image which you put in the list.
Note: when creating a undo state it's important to clear any snapshots after the new stack pointer position. This is because if undo has been used, redo can be used if no changes. However, if undo was used and new drawing was added this would invalidate the next states so they have to be removed.
As to browser memory it will depend on the user's system. Some have a few gigabytes, other has a lot. There is no way to know. You would have to chose a UX strategy suitable for your scenario as well as target audience.
Example
This does not implement the logistics for handling the sync of the thumbnails, but has most other parts. I'll leave the rest as an exercise.
var ctx = c.getContext("2d"),
stack = [], // undo-redo stack
sp = 0, // stack pointer
isDown = false; // for drawing (demo)
capture(); // create an initial undo capture (blank)
ctx.lineCap = "round"; // setup line for demo
ctx.lineWidth = 4;
// simple draw mechanism
c.onmousedown = function(e) {
sp++; // on mouse down, move stack pointer to next slot
isDown = true; // NOTE: clear any snapshots after this point (not shown)
var pos = getXY(e); // start drawing some line - how you draw is up to you
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
}
window.onmousemove = function(e) {
if (!isDown) return; // only for drawing
var pos = getXY(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
}
window.onmouseup = function() {
if (!isDown) return;
isDown = false;
capture(); // capture an undo state
makeThumb(); // create and insert a thumbnail of state
};
function capture() {
stack[sp] = c.toDataURL(); // one way, you could use getImageData,
// or store points instead.. it's up to you
}
// Creates a thumbnail of current canvas and insert into visible undo stack
function makeThumb() {
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 64;
var ctxTmp = canvas.getContext("2d");
ctxTmp.drawImage(c, 0, 0, canvas.width, canvas.height);
undos.appendChild(canvas);
}
// UNDO button clicked
undo.onclick = function() {
var img = new Image; // restore previous state/snapshot
img.onload = function() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(this, 0, 0);
}
// move stack pointer back and get previous snapshot
if (sp > 0) img.src = stack[--sp];
};
// REDO button clicked
redo.onclick = function() {
// anything we can redo?
if (sp < stack.length) {
var img = new Image;
img.onload = function() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(this, 0, 0);
}
// move stack pointer forward and get next snapshot
img.src = stack[++sp];
}
};
function getXY(e) {
var r = c.getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top}
}
#c {background:#ccc}
<button id=undo>Undo</button>
<button id=redo>Redo</button><br>
<canvas id=c width=500 height=500></canvas>
<div id=undos></div>
You could copy the current canvas to a separate one each time an action is performed. Simply displaying old canvases could serve as an action log.
You can send a canvas to drawImage directly:
destContext.drawImage( srcCanvas, 0, 0 );
If that approach consumes too much memory, an alternative is to store all the commands in a stack, remove the last element when undoing, and redraw everything from scratch.

Saving canvas image in phonegap after canvas is drawn

I am creating a image in a canvas and saving the image. I found a very nice plugin here.
Code for the image saving:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = imageURI;
imageObj.onload = function() {
contentW = $("#content").width();
canvas.width = 400;
canvas.height = 600;
context.drawImage(imageObj, 0, 0,canvas.width,canvas.height);
//the plugin
setTimeout(function(){
window.savephotoplugin(canvas,"image/png",device.version,function(val){
//returns you the saved path in val
alert("Photo Saved: " + val);
});
},3000)
}
The plugin works very nice only problem is that it is done before the canvas is even drawn. So I put a setTimeout to avoid it, however is there a way to detect when canvas is done and call the function after it. Tried jquery .change() didn't work.
If anyone finds this code useful feel free to use and the plugin is very nice :)
As you can see drawImage doesn't accept any callbacks. Also canvas doesn't define any events about its drawing process. So you choice of timeout is correct. Only one thing you could possibly improve. Use setTimeout(..., 0) instead of setTimeout(..., 3000). More details about this trick here

HTML5 Image.onload race condition in Internet Explorer 9

I've found similar timing issues concerning IE 9 and drawing images to HTML5 cnavases discussed on stackoverflow, but none quite match mine.
I'm encountering an issue such that periodically the image's onload function is called, but it is still not ready to be drawn to a canvas. (The canvas remains blank). Within onload, the image's "complete" property is always true, and the "width" and "height" properties always contain the expected values. No exceptions are thrown. If I put a small delay in onload prior to drawing the image to the canvas, I never get a blank draw. I can also tie another attempt to draw the image to an event like a mouse click, and this is always successful. I do not observe this in Chrome or Firefox. I appreciate any insights. Thanks!
var canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 480;
var context = canvas.getContext("2d");
var image = new Image();
image.onload = function()
{
// this.complete always true here
// A delay here seems to guarantee the draw will succeed
context.drawImage(this, 0, 0); // Half the time canvas remains blank after draw
// If the canvas is still blank, a later call to context.drawImage with this image will succeed
}
image.src = "some.png";
I don't see where you append the canvas to the body--is that intentional?
Anyway, try putting the createElement inside the onload
Does this make things consistently good?
var canvas;
var context;
var image = new Image();
image.onload = function()
{
canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 480;
document.body.appendChild(canvas);
context = canvas.getContext("2d");
context.drawImage(this, 0, 0); // Half the time canvas remains blank after draw
}
image.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/city-q-c-640-480-6.jpg";

Categories

Resources