I'm just trying to convert imagedata to an heightmap, to show in on the canvas. But when i do this, a strange thing appears, for all the images I tested.
Here is my code :
window.onload = function()
{
var canvas = document.getElementById('game');
if(!canvas)
{
alert("Impossible de récupérer le canvas.");
return;
}
var context = canvas.getContext('2d');
if(!context)
{
alert("Impossible de récupérer le contexte du canvas.");
return;
}
var img = new Image();
img.src = "noise.png";
var size = 250000;
var data = new Float32Array(size);
var pxlData = new Array(size);
for ( var i = 0; i < size; i ++ ) {
data[i] = 0
}
for (var i = 0; i < size; i++)
{
pxlData[i] = new Array(4);
pxlData[i][0] = 0;
pxlData[i][1] = 0;
pxlData[i][2] = 0;
}
img.onload = function()
{
context.drawImage(img, 0, 0);
var imgd = context.getImageData(0, 0, 500, 500);
context.clearRect(0, 0, canvas.width, canvas.height);
var pix = imgd.data;
var j=0;
var x=0;
var y=0;
var i=0;
for (var i = 0, n = pix.length; i < n; i += (4)) {
var all = pix[i]+pix[i+1]+pix[i+2];
pxlData[j][0] = pix[i];
pxlData[j][1] = pix[i+1];
pxlData[j][2] = pix[i+2];
pxlData[j][3] = pix[i+3];
data[j++] = all/3;
}
var alpha;
for(y = 0; y < 500; y++)
{
for(x = 0; x < 500; x++)
{
if(data[x * y] <= 100){
context.fillStyle = "blue";
}else if(data[x * y] >= 100){
context.fillStyle = "green";
}
//context.fillStyle = 'rgba('+ data[x * y] +', '+ data[x * y] +', '+ data[x * y] +', 1)';
context.fillRect(x, y, 1, 1);
// context.fillStyle = 'rgba('+ pxlData[x * y][0] +', '+ pxlData[x * y][1] +', '+ pxlData[x * y][2] +', '+ pxlData[x * y][3] +')';
// context.fillRect(x, y, 1, 1);
}
}
};
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<script type="text/javascript" src="game.js"></script>
<title>Génération de terrain</title>
</head>
<body>
<canvas id="game" width="500" height ="500">Votre navigateur ne supporte pas les canvas.</canvas>
</body>
</html>
That's what it's looking like when i run it :
canvas
The error is how you index the pixels in the 32 bit float array.
You have data[x * y] that means the pixel at 0,0 will be at index 0 * 0 = 0and pixel at 0,100 will also be at 0 * 100 = 0 and all other indexes will be wrong. To get the correct pixel address use x + y * width when indexing from an array where one item is a pixel. If indexing into pixel data 'imageData.data' each pixel is 4 items (r,g,b,a) so you would use data[x * 4 + y * canvas.width * 4] or more simply imageData.data[x + y * canvas.width * 4]
Looking at your code you have create some common mistakes that will make you code run very slow compared to what it could do. I have simplified your code. It does the same but without all the overhead. I have added comments, removing your code and suggesting alternative methods of doing the same.
The biggest change is the rendering green and blue loops. You where setting each pixel with context.fillRect(x,y,1,1); this is very very slow. Rather than draw a rectangle for each pixel use the imageData you got and fill the colour after you read the height then just put that data back onto the canvas. I used two typeArray views to set and read the data this also improved the performance.
// convert r,g,b,a to 32 bit colour using correct little or big endian
function create32Pixel(r, g, b, a){ // dont call this inside loops as very slow
var endianConvert = new Uint8ClampedArray(4); // use to convert to correct endian
var endianConvert32 = new Uint32Array(endianConvert.buffer);
endianConvert[0] = r;
endianConvert[1] = g;
endianConvert[2] = b;
endianConvert[3] = a;
return endianConvert32[0];
}
window.onload = function()
{
var canvas = document.getElementById('game');
if(!canvas)
{
alert("Impossible de récupérer le canvas.");
return;
}
var context = canvas.getContext('2d');
if(!context)
{
alert("Impossible de récupérer le contexte du canvas.");
return;
}
var img = new Image();
img.src = "noise.png";
var size = 250000;
// Do you really need floats?? 16 bit unsigned int array can hold 255 * 3 and all javascript
// numbers are converted to 64 bit floats so you will not lose precision from original when manipulating the 16bit values.
// following array is not needed.
//var dataFloat = new Float32Array(size);
// following array is not needed.
//var pxlData = new Array(size); // bad way to create an array
//var pxlData = []; // create empty array and push onto it.
// can use dataFloat.fill()
/*for ( var i = 0; i < size; i ++ ) {
dataFloat[i] = 0
}*/
//dataFloat.fill(0); // but not needed as array is zeroed when created (not from an existing buffer)
// Very inefficient as you are creating a new array for every pixel. Use flat array instead.
/*for (var i = 0; i < size; i++)
{
pxlData[i] = new Array(4);
pxlData[i][0] = 0;
pxlData[i][1] = 0;
pxlData[i][2] = 0;
}*/
// should do
/*var i;
while(i < size * 4){
pxlData[i++] = 0; // array grows as you increase i;
}*/
img.onload = function()
{
context.drawImage(img, 0, 0);
var imgd = context.getImageData(0, 0, canvas.width, canvas.height);
// don't need to clear
// context.clearRect(0, 0, canvas.width, canvas.height);
// make two views one 8bit and the other 32bit. Both point to the same data change one
// changes the other
var pixChannels = imgd.data;
var pixels = new Uint32Array(pixChannels.buffer);
var j,x,y,j;
j = x = y = i = 0;
// Create pixel colours. Need to ensure correct order as some systems
// use little edian and others big endian
// see https://en.wikipedia.org/wiki/Endianness for info.
var green = create32Pixel(0,255,0,255);
var blue = create32Pixel(0,0,255,255);
// use j as 32bit pixel index and i as 8bit index
// read the height and set pixel colour accordingly.
while(j < pixels.length){
var height = pixChannels[i++] + pixChannels[i++] + pixChannels[i++];
if(height <= 300){ // no need to divide by 3 just test for 3 time 100
pixels[j++] = blue;
}else{
pixels[j++] = green;
}
i++; // skip alpha channel
}
context.putImageData(imgd,0,0); // put pixels back to canvas.
};
}
Related
I'm using nearest neighbor algorithm to zoom the image on canvas. But, when I move the scaling bar higher, the image have white line that create a square array
Original Image
After I move the scale bar
The zoom is work but the problem is only the white lines.
For the source code I will provide in bottom
1.html
<!DOCTYPE HTML>
<html>
<head>
<title>Prototype PC</title>
</head>
<body>
<canvas id='canvas1'></canvas>
<hr>
<button id='read'>READ IMAGE</button>
<hr>
Scale <input type='range' value='1' min='1' max='5' step='0.25' id='scale'>
<br><button id='default2'>Default Scalling</button>
<hr/>
</body>
<style>
body{
background : rgba(255,255,255,1);
}
</style>
<script src='imagine.js'></script>
<script>
var canvas = document.getElementById('canvas1')
var obj = new pc(canvas)
obj.image2canvas("565043_553561101348179_1714194038_a.jpg")
var tes = new Array()
document.getElementById('read').addEventListener('click',function(){
tes = obj.image2read()
})
document.getElementById('scale').addEventListener('change',function(){
var scaleval = this.value
var xpos = 0
var ypos = 0
var xnow = 0
var ynow = 0
var objW = obj.width
var objH = obj.height
tesbackup = new Array()
for(var c=0; c<tes.length; c++){
temp = new Array()
for(var d=0; d<4; d++){
temp.push(255)
}
tesbackup.push(temp)
}
//end of copy
for(var i=0; i<tes.length; i++){
xpos = obj.i2x(i)
ypos = obj.i2y(i)
xnow = Math.round(xpos) * scaleval)
ynow = Math.round(ypos) * scaleval)
if (xnow < objW && ynow < objH) {
for (var j=0; j<scaleval; j++) {
for (var k=0; k<scaleval; k++) {
var idxnow = obj.xy2i(xnow,ynow)
tesbackup[idxnow][0] = tes[i][0]
tesbackup[idxnow][1] = tes[i][1]
tesbackup[idxnow][2] = tes[i][2]
}
}
}
}
obj.array2canvas(tesbackup)
})
</script>
and, for imagine.js
function info(text){
console.info(text)
}
function pc(canvas){
this.canvas = canvas
this.context = this.canvas.getContext('2d')
this.width = 0
this.height = 0
this.imgsrc = ""
this.image2read = function(){
this.originalLakeImageData = this.context.getImageData(0,0, this.width, this.height)
this.resultArr = new Array()
this.tempArr = new Array()
this.tempCount = 0
for(var i=0; i<this.originalLakeImageData.data.length; i++){
this.tempCount++
this.tempArr.push(this.originalLakeImageData.data[i])
if(this.tempCount == 4){
this.resultArr.push(this.tempArr)
this.tempArr = []
this.tempCount = 0
}
}
info('image2read Success ('+this.imgsrc+') : '+this.width+'x'+this.height)
return this.resultArr
}
this.image2canvas = function(imgsrc){
var imageObj = new Image()
var parent = this
imageObj.onload = function() {
parent.canvas.width = imageObj.width
parent.canvas.height = imageObj.height
parent.context.drawImage(imageObj, 0, 0)
parent.width = imageObj.width
parent.height = imageObj.height
info('image2canvas Success ('+imgsrc+')')
}
imageObj.src = imgsrc
this.imgsrc = imgsrc
}
this.array2canvas = function(arr){
this.imageData = this.context.getImageData(0,0, this.width, this.height)
if(this.imageData.data.length != arr.length*4) {
return false
}
for(var i = 0; i < arr.length; i++){
this.imageData.data[(i*4)] = arr[i][0]
this.imageData.data[(i*4)+1] = arr[i][1]
this.imageData.data[(i*4)+2] = arr[i][2]
this.imageData.data[(i*4)+3] = arr[i][3]
}
this.context.clearRect(0, 0, this.width, this.height)
this.context.putImageData(this.imageData, 0, 0)
info('Array2Canvas Success ('+this.imgsrc+')')
}
this.i2x = function(i){
return (i % this.width)
}
this.i2y = function(i){
return ((i - (i % this.width))/ this.width)
}
this.xy2i = function(x,y){
return (y * this.width) + (x)
}
}
Thanks in advance for a solution of this problem
Rounding out pixels
Nearest pixel will result in some zoomed pixels being larger than otheres
It is a problem with the value of scaleval. It has a step of 0.25 and when you calculate each zoomed pixels address you use (and I am guessing as your code has syntax errors) Math.round(xpos * scaleval) but then you draw the pixel using only the fractional size eg 2.75 not the integer size eg 3.0
The size of each pixel is var xSize = Math.round((xpos + 1) * scaleval)-Math.round(xpos * scaleval) same for y. That way when the pixel zoom is not an integer value every so many zoomed pixels will be one pixel wider and higher.
The following is a fix of your code but as you had a number of syntax errors and bugs I have had to guess some of your intentions.
xpos = obj.i2x(i)
ypos = obj.i2y(i)
xnow = Math.round(xpos * scaleval)
ynow = Math.round(ypos * scaleval)
// pixel width and height
var pw = Math.round((xpos + 1) * scaleval) - xnow;
var ph = Math.round((ypos + 1) * scaleval) - ynow;
if (xnow < objW && ynow < objH) {
for (var y = 0; y < ph; y++) {
for (var x =0; x < pw; x++) {
var idxnow = obj.xy2i(xnow + x, ynow + y)
tesbackup[idxnow][0] = tes[i][0]
tesbackup[idxnow][1] = tes[i][1]
tesbackup[idxnow][2] = tes[i][2]
}
}
}
}
But you are not really doing a nearest neighbor algorithm. For that you iterate each of the destination pixels finding the nearest pixel and using its colour. That allows you to easily apply a transform to the zoom but still get every pixel and not skip pixels due to rounding errors.
Nearest neighbor
Example of using nearest neighbor lookup for a scale rotated and translated image
var scaleFac = 2.3; // scale 1> zoom in
var panX = 10; // scaled image pan
var panY = 10;
var ang = 1;
var w = ctx.canvas.width; // source image
var h = ctx.canvas.height;
var wd = ctx1.canvas.width; // destination image
var hd = ctx1.canvas.height;
// use 32bit ints as we are not interested in the channels
var src = ctx.getImageData(0, 0, w, h);
var data = new Uint32Array(src.data.buffer);// source
var dest = ctx1.createImageData(wd, hd);
var zoomData = new Uint32Array(dest.data.buffer);// destination
var xdx = Math.cos(ang) * scaleFac; // xAxis vector x
var xdy = Math.sin(ang) * scaleFac; // xAxis vector y
var ind = 0;
var xx,yy;
for(var y = 0; y < hd; y ++){
for(var x = 0; x < wd; x ++){
// transform point
xx = (x * xdx - y * xdy + panX);
yy = (x * xdy + y * xdx + panY);
// is the lookup pixel in bounds
if(xx >= 0 && xx < w && yy >= 0 && yy < h){
// use the nearest pixel to set the new pixel
zoomData[ind++] = data[(xx | 0) + (yy | 0) * w]; // set the pixel
}else{
zoomData[ind++] = 0; // pixels outside bound are transparent
}
}
}
ctx1.putImageData(dest, 0, 0); // put the pixels onto the destination canvas
I have to achieve the following task:
divides the image into tiles, computes the average color of each tile,
fetches a tile from the server for that color, and composites the
results into a photomosaic of the original image.
What would be the best strategy? the first solution coming to my mind is using canvas.
A simple way to get pixel data and finding the means of tiles. The code will need more checks for images that do not have dimensions that can be divided by the number of tiles.
var image = new Image();
image.src = ??? // the URL if the image is not from your domain you will have to move it to your server first
// wait for image to load
image.onload = function(){
// create a canvas
var canvas = document.createElement("canvas");
//set its size to match the image
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d"); // get the 2d interface
// draw the image on the canvas
ctx.drawImage(this,0,0);
// get the tile size
var tileSizeX = Math.floor(this.width / 10);
var tileSizeY = Math.floor(this.height / 10);
var x,y;
// array to hold tile colours
var tileColours = [];
// for each tile
for(y = 0; y < this.height; y += tileSizeY){
for(x = 0; x < this.width; x += tileSizeX){
// get the pixel data
var imgData = ctx.getImageData(x,y,tileSizeX,tileSizeY);
var r,g,b,ind;
var i = tileSizeY * tileSizeX; // get pixel count
ind = r = g = b = 0;
// for each pixel (rgba 8 bits each)
while(i > 0){
// sum the channels
r += imgData.data[ind++];
g += imgData.data[ind++];
b += imgData.data[ind++];
ind ++;
i --;
}
i = ind /4; // get the count again
// calculate channel means
r /= i;
g /= i;
b /= i;
//store the tile coords and colour
tileColours[tileColours.length] = {
rgb : [r,g,b],
x : x,
y : y,
}
}
// all done now fetch the images for the found tiles.
}
I created a solution for this (I am not getting the tile images from back end)
// first function call to create photomosaic
function photomosaic(image) {
// Dimensions of each tile
var tileWidth = TILE_WIDTH;
var tileHeight = TILE_HEIGHT;
//creating the canvas for photomosaic
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
canvas.height = image.height;
canvas.width = image.width;
var imageData = context.getImageData(0, 0, image.width, image.height);
var pixels = imageData.data;
// Number of mosaic tiles
var numTileRows = image.width / tileWidth;
var numTileCols = image.height / tileHeight;
//canvas copy of image
var imageCanvas = document.createElement('canvas');
var imageCanvasContext = canvas.getContext('2d');
imageCanvas.height = image.height;
imageCanvas.width = image.width;
imageCanvasContext.drawImage(image, 0, 0);
//function for finding the average color
function averageColor(row, column) {
var blockSize = 1, // we can set how many pixels to skip
data, width, height,
i = -4,
length,
rgb = {
r: 0,
g: 0,
b: 0
},
count = 0;
try {
data = imageCanvasContext.getImageData(column * TILE_WIDTH, row * TILE_HEIGHT, TILE_HEIGHT, TILE_WIDTH);
} catch (e) {
alert('Not happening this time!');
return rgb;
}
length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return rgb;
}
// Loop through each tile
for (var r = 0; r < numTileRows; r++) {
for (var c = 0; c < numTileCols; c++) {
// Set the pixel values for each tile
var rgb = averageColor(r, c)
var red = rgb.r;
var green = rgb.g;
var blue = rgb.b;
// Loop through each tile pixel
for (var tr = 0; tr < tileHeight; tr++) {
for (var tc = 0; tc < tileWidth; tc++) {
// Calculate the true position of the tile pixel
var trueRow = (r * tileHeight) + tr;
var trueCol = (c * tileWidth) + tc;
// Calculate the position of the current pixel in the array
var pos = (trueRow * (imageData.width * 4)) + (trueCol * 4);
// Assign the colour to each pixel
pixels[pos + 0] = red;
pixels[pos + 1] = green;
pixels[pos + 2] = blue;
pixels[pos + 3] = 255;
};
};
};
};
// Draw image data to the canvas
context.putImageData(imageData, 0, 0);
return canvas;
}
function create() {
var image = document.getElementById('image');
var canvas = photomosaic(image);
document.getElementById("output").appendChild(canvas);
};
DEMO:https://jsfiddle.net/gurinderiitr/sx735L5n/
Try using the JIMP javascript library to read the pixel color and use invert, normalize or similar property for modifying the image.
Have a look on the jimp library
https://github.com/oliver-moran/jimp
How to find the most repetitive pixel in the background-image and find out the color?
Help!
You don't have access to the pixel data of a background image via JavaScript. What you will have to do is to create a new Image object and set the source to the background image URL. Afterwards, you will have to do these steps:
Create an in-memory canvas object
Draw the image on the canvas
Get the image data, iterate through all pixels and store the colors in an Object (key = color, value = amount of repitition)
Sort the array by the amount of repitition, then select the first value
Here, I created an example. This loads the JSconf logo and sets the body's background color to the most repetitive color.
// Create the image
var image = new Image();
image.crossOrigin = "Anonymous";
image.onload = function () {
var w = image.width, h = image.height;
// Initialize the in-memory canvas
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
// Get the drawing context
var context = canvas.getContext("2d");
// Draw the image to (0,0)
context.drawImage(image, 0, 0);
// Get the context's image data
var imageData = context.getImageData(0, 0, w, h).data;
// Iterate over the pixels
var colors = [];
for(var x = 0; x < w; x++) {
for(var y = 0; y < h; y++) {
// Every pixel has 4 color values: r, g, b, a
var index = ((y * w) + x) * 4;
// Extract the colors
var r = imageData[index];
var g = imageData[index + 1];
var b = imageData[index + 2];
// Turn rgb into hex so we can use it as a key
var hex = b | (g << 8) | (r << 16);
if(!colors[hex]) {
colors[hex] = 1;
} else {
colors[hex] ++;
}
}
}
// Transform into a two-dimensional array so we can better sort it
var _colors = [];
for(var color in colors) {
_colors.push([color, colors[color]]);
}
// Sort the array
_colors.sort(function (a, b) {
return b[1] - a[1];
});
var dominantColorHex = parseInt(_colors[0][0]).toString(16);
document.getElementsByTagName("body")[0].style.backgroundColor = "#" + dominantColorHex;
};
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/600px-JavaScript-logo.png";
I've had problems with getting a rain effekt on my canvas. After some searching on google I found this
<script type="text/javascript">
var ctx;
var imgBg;
var imgDrops;
var x = 0;
var y = 0;
var noOfDrops = 50;
var fallingDrops = [];
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
imgBg = new Image();
imgBg.src = "http://lorempixel.com/600/600/sports/";
setInterval(draw, 36);
for (var i = 0; i < noOfDrops; i++) {
var fallingDr = new Object();
fallingDr["image"] = new Image();
fallingDr.image.src = "http://lorempixel.com/10/10/sports/";
fallingDr["x"] = Math.random() * 600;
fallingDr["y"] = Math.random() * 5;
fallingDr["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr);
}
}
}
function draw() {
drawBackground();
for (var i=0; i< noOfDrops; i++)
{
ctx.drawImage (fallingDrops[i].image, fallingDrops[i].x, fallingDrops[i].y); //The rain drop
fallingDrops[i].y += fallingDrops[i].speed; //Set the falling speed
if (fallingDrops[i].y > 450) { //Repeat the raindrop when it falls out of view
fallingDrops[i].y = -25 //Account for the image size
fallingDrops[i].x = Math.random() * 600; //Make it appear randomly along the width
}
}
}
function drawBackground(){
ctx.drawImage(imgBg, 0, 0); //Background
}
</script>
The strange thing is that the code works as long as I don't change the image source from the link to my png-files. All I get is copies of my file drawn over and over again til the canvas's is full of lines.
Help please!
It seems that for some reason your background is not rendered.
If you don't want to have any background, you have to clear the canvas before drawing drops at their new positions, or else your canvas will flood :)
Replace: ctx.drawImage(imgBg, 0, 0);
with: clearRect(0, 0, width, height)
See, also, this short demo.
I'm looking to build an image transform tool with Javascript. Something that utilizes handles around the image similar to Photoshop and allows the user to scale and rotate. I'm looking to make this work in IE 6 and up and Firefox 3+ and Safari 3+.
Does anyone know of a library or tool that could help with this? I've seen a lot of tools that utilize the Canvas element but that leaves out IT. I've also seen the Raphael library which might work. Any other options out there?
Have a look at this rotorzoom.
It rotates it zooms it's fast and i can do with a few more hits.
http://codepen.io/hex2bin/pen/tHwhF
var requestId = 0;
var animationStartTime = 0;
var img = new Image();
initimg(img);
dst = document.getElementById("dst").getContext("2d");
dst.drawImage(img, 0, 0, 256, 256);
// read the width and height of the canvas
i = 0;
var imageDataDst = dst.getImageData(0, 0, 1024, 512);
var bufDst = new ArrayBuffer(imageDataDst.data.length);
var buf8Dst = new Uint8ClampedArray(bufDst);
var data32Dst = new Uint32Array(bufDst);
var data32Src = new Uint32Array(256*256);
var scan1=0;
var scan4=0
// fill the source array with the image
for (var y = 0; y < 256; ++y) {
scan4=y*1024*4;
for (var x = 0; x < 256; ++x) {
data32Src[scan1++] =
(255 << 24) + // alpha
(imageDataDst.data[scan4+2] << 16) + // blue
(imageDataDst.data[scan4+1] << 8) + // green
imageDataDst.data[scan4]; // red
scan4=scan4+4;
}
}
animationStartTime = window.performance.now();
requestId = window.requestAnimationFrame(animate);
var j=0;
function animate(time) {
var height=512;
var width=1024;
j=j+1;
var timestamp = j / 100;
var pos;
var startY = 128;
var startX = 128;
var i=0;
var scaledHeight = 512 + Math.sin(timestamp*1.4) * 500;
var scaledWidth = 512 + Math.sin(timestamp*1.4) * 500
var angleRadians = timestamp;
var deltaX1 = Math.cos(angleRadians) * scaledHeight / 256;
var deltaY1 = Math.sin(angleRadians) * scaledHeight / 256;
var deltaY1x256=deltaY1*256;
var deltaX2 =Math.sin(angleRadians ) * scaledWidth / 256;
var deltaY2 =- Math.cos(angleRadians ) * scaledWidth / 256;
var h = height;
while (h--) {
var x =262144+ startX+deltaX1*-512+deltaX2*-256;
var y =262144+ startY+deltaY1*-512+deltaY2*-256;
var y256=y*256;
var w = width;
while (w--) {
//Optimised inner loop. Can it be done better?
pos =(y256>>0&0xff00)+(x>>0&0xff);
data32Dst[i++] =data32Src[pos];
x += deltaX1;
y256 += deltaY1x256;
//end of inner loop
}
startX += deltaX2
startY += deltaY2;
}
imageDataDst.data.set(buf8Dst);
dst.putImageData(imageDataDst, 0, 0);
requestId = window.requestAnimationFrame(animate);
}
function initimg(image1)
{
image1.src = 'data:image/jpeg;base64,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';
}
<body>
<canvas id="dst" width="1024", height="512">
Random Canvas
</canvas>
</body>
Check out Raphael library on Github: https://github.com/DmitryBaranovskiy/raphael