Background acting odd html5 canvas - javascript

I have an 800 by 100 image for the background and I am trying to pull sections from it (like a sprite sheet) to generate a background because I am under the impression that it is an efficient way of doing it(also seems like one that I can toy with and learn to generate backgrounds in the future!)
It is not working though, int he first animation frame ( I found this from slowing it down) it shows half of the entire background image(not the sections that I want to use) then it moves it down presumably 800 pixels and shows it and by the third frame it is gone!
please help :/ thank you!
var bricks = [0, 1, 1, 1, 1, 2];
function createBackground() {
for(var i = 0; i < bricks.length; i++) {
drawBackground(bricks[i]);
}
}
var bg = new Image();
bg.src = 'bgsheet2.png';
var srcX, srcY = 0,srcW = 100,srcH = 100,destX = 0,destY = canvas.height-100,destW = 100,destH = 100;
function drawBackground(type) {
switch(type) {
case 1:
srcX = 0;
ctx.drawImage(bg,srcX,srcY,srcW,srcH,destX,destY,destW,destH);
destX+=100;
break;
case 2:
srcX = 100;
ctx.drawImage(bg,srcX,srcY,srcW,srcH,destX,destY,destW,destH);
destX+=100;
break;
case 3:
srcX = 200;
destX+=100;
ctx.drawImage(bg,srcX,srcY,srcW,srcH,destX,destY,destW,destH);
break;
default:
srcX = 300;
ctx.drawImage(bg,srcX,srcY,srcW,srcH,destX,destY,destW,destH);
destX+=100;
break;
}
}
//this is in my main animation loop
createBackground();

For the efficiency, you have the following common solutions.
If the background is static (no moving parts like water or any interaction with it) then you can draw it to an on-screen canvas (a visible canvas) just the one time, but don't clear that canvas. That way your tiles are only processed and drawn the once.
The second method, a little more difficult than the first, is to draw sections to an offscreen canvas with the goal of limiting your (re)draws calls.
You can also get in to using "dirty rectangles" which is basically the practice of only updating the changed parts of your display. This is by far the hardest solution for efficiency.

Related

Canvas cannot draw accurate color [duplicate]

A client required help with a program that extracts the dominant color of a product image.
I was able to quickly implement this in Javascript; the algorithm below only samples the central square of a 3x3 grid on the image for a quick estimate of the t-shirt color in the image.
var image = new Image();
image.onload = function() {
try {
// get dominant color by sampling the central square of a 3x3 grid on image
var dominantColor = getDominantColor();
// output color
$("#output").html(dominantColor);
}
catch(e) {
$("#output").html(e);
}
};
image.src = "sample_image.jpg";
function getDominantColor() {
// Copy image to canvas
var canvas = $("<canvas/>")[0];
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
// get pixels from the central square of a 3x3 grid
var imageData = canvas.getContext("2d").getImageData(canvas.width/3, canvas.height/3, canvas.width/3, canvas.height/3).data;
var colorOccurrences = {};
var dominantColor = "";
var dominantColorOccurrence = 0;
for(var i = 0; i < imageData.length; i += 4) {
var red = imageData[i];
var green = imageData[i+1];
var blue = imageData[i+2];
//var alpha = imageData[i+3]; // not required for this task
var color = RGBtoHEX({"red": red, "green": green, "blue": blue});
if(colorOccurrences[color] == undefined) {
colorOccurrences[color] = 1;
}
else {
colorOccurrences[color] ++;
if(colorOccurrences[color] > dominantColorOccurrence) {
dominantColorOccurrence = colorOccurrences[color];
dominantColor = color;
}
}
}
return dominantColor;
}
function RGBtoHEX(rgb) {
var hexChars = "0123456789ABCDEF";
return "#"
+ (hexChars[~~(rgb.red/16)] + hexChars[rgb.red%16])
+ (hexChars[~~(rgb.green/16)] + hexChars[rgb.green%16])
+ (hexChars[~~(rgb.blue/16)] + hexChars[rgb.blue%16]);
}
The image in question is this (preview below).
However, the results when this image is processed in the code above are varied across machines/browsers: #FF635E is what I see on my machine, running Windows7 and using Firefox 32. My client running Mac gets a result of #FF474B on Safari and #FF474C on Firefox 33.
Though the results are close, why are they ideally not the exact same? Does getImageData indeed vary depending on the local setup, or is the JPG data being interpreted differently on different machines?
Edit: This image isn't a one-off case. Such color variations were noticed across a range of the image that the client requested to process. My client and I obtained different results for the same set of images.
Yes. This fact is exploited by canvas fingerprinting:
The same HTML5 Canvas element can
produce exceptional pixels on a different web browsers, depending on
the system on which it was executed.
This happens for several reasons: at the image format level — web
browsers uses different image processing engines, export options,
compression level, final images may got different hashes even if they
are pixel-perfect; at the pixmap level — operating systems use
different algorithms and settings for anti-aliasing and sub-pixel
rendering. We don't know all the reasons, but we have already
collected more than a thousand unique signatures.

Javascript canvas images are coming out blocky when stacking on top of each other

So I'm randomly generating two types of clouds, and the clouds are intended to stack on top of each other a bit and move slowly (like clouds irl would).
So essentially I'm drawing a cloud image, clearing the area, moving the image over (by recreating it in a different position), and creating another cloud and repeating the process, but when the clouds are stacking on top of each other I'm getting a square area in between the stacked clouds. Not sure how to fix it.
Check this out: (see how the clouds have a block-like look as they stack over eachother)
http://testcloudsmc.bitballoon.com
Here's the full code:
https://repl.it/FTo8/3
And here's the most relevant parts of the code:
------------------------------------------------
var canvas; var ctx; var frameRate; var assets = [];
window.onload = function(){
canvas = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
frameRate = 1000/30; //30 fps
//Decides on a x position for clouds:
for(var f = 0;f<Math.floor(Math.random()*40)+10;f++){
cloudsarrayxpos[f] = Math.floor(Math.random()*800)+10;
}
/* Move/Render images */
for (var a = 0; a < 21; a++){
assets[a] = document.getElementById(a);
console.log(assets[a]);
};
/* CREATE OBJECTS FUNCTIONS: */
var clouds = function(x,y,h,w){
ctx.clearRect(x,y,w,h);
if((x>300)||(x<100)){
ctx.drawImage(assets[7],x,y,w,h);
}else{
ctx.drawImage(assets[20],x,y,w,h);
}
} //end of clouds function
function animate(){
for(var g = 0; g<cloudsarrayxpos.length;g++){
clouds(cloudsarrayxpos[g],(5*g),300,200);
cloudsarrayxpos[g]+=(Math.random()*.1)+.05; //changing the x position of each cloud in the array making it appear to be moving
}
window.requestAnimationFrame(animate);
}
}//end of window.onload
The problem is that you are clearing the canvas in each cloud spot before drawing it.
That means that the transparency (alpha) values of the cloud images don't come into play as each resulting pixel is composed only of the last image that was drawn on it.
To fix this, only clear the canvas once per animation cycle.
Specifically:
Remove ctx.clearRect from clouds function
Add this at the top of the animate function:
ctx.clearRect(0, 0, 1300, 600);

Rendering too many points on Javascript-player

As part of a project, I have to render a video on a JS-player from a text file which has the points - all the changed coordinates along-with the color in each frame. Below is the code I'm using to draw these point on the screen.
But the issue is that the number of changed pixels in each frame are as high as ~20,000 and I need to display these in less than 30ms (inter-frame time difference). So, when I run this code the browser hangs for almost each frame. Could someone suggest an improvement for this?
Any help is really appreciated.
c.drawImage(img,0,0,800,800);
setInterval(
function(){
while(tArr[index]==time) {
var my_imageData = c.getImageData(0,0,width, height);
color(my_imageData,Math.round(yArr[index]),Math.round(xArr[index]),Math.round(iArr[index]),255);
c.putImageData(my_imageData,0,0);
index=index+1;
}
time = tArr[index];
}
,30);
xArr, yArr, iArr, tArr are arrays of x-coordinate, y-coordinate, intensity value and time of appearance respectively for the corresponding point to be rendered
function color(imageData,x,y,i,a){ //wrapper function to color the point
var index = (x + y * imageData.width) * 4;
imageData.data[index+0] = i;
imageData.data[index+1] = i;
imageData.data[index+2] = i;
imageData.data[index+3] = a;
}

Canvas pixel manipulation optimization

I'm trying to do some real-time pixel manipulation (mode7-like transformations if you are interested) with canvas.
It works so: it takes a source image data that works like a frame buffer, it does some transformations and writes the result into a another 320x240 destination image data.
function transform() {
var src_pointer, dest_pointer;
var destData = dest_context.getImageData(0,0, 320, 240);
var imgdata = destData.data;
var sourceData= source_context.getImageData(0,0,320,240).data;
for (var y = 0; y< 240; y++) for (var x = 0; x< 320; x++) {
//*** DOING SOME TRANSFORMATIONS HERE, AND WRITE THE RESULT AT SX AND SY
//... Doesn't have impact in perfomance. Suspicious, huh?
dest_pointer = getPointer(x,y);
src_pointer = getPointer(sx, sy);
imgdata[dest_pointer] = sourceData[src_pointer];
imgdata[dest_pointer +1] = sourceData[src_pointer +1];
imgdata[dest_pointer +2] = sourceData[src_pointer +2];
// Alpha? Sad thing that canvas just handle 32bit image data. I don't really need it.
imgdata[dest_pointer +3] = sourceData[src_pointer +3];
}
dest_context.putImageData(destData,0,0);
}
//Function to help map a coordinate into image data array
function getPointer(x,y) {
return ( ( y * 320 ) + x ) * 4;
}
That have a poor perfomance if you execute it continuously (about 12 frames per second). Doing some profiling I discard an specific method bottleneck (getImageData and putImageData have a really little load time).
I used to think that issue was in the transformation section but the profiling throws me that the bottle neck was specifically in the pixel assignment. Maybe optimizing math operations can be possible (think that's hard, because that's in the border line between pure javascript and browser engine), but in array assignment is possible to optimize?

Is canvas getImageData method machine/browser dependent?

A client required help with a program that extracts the dominant color of a product image.
I was able to quickly implement this in Javascript; the algorithm below only samples the central square of a 3x3 grid on the image for a quick estimate of the t-shirt color in the image.
var image = new Image();
image.onload = function() {
try {
// get dominant color by sampling the central square of a 3x3 grid on image
var dominantColor = getDominantColor();
// output color
$("#output").html(dominantColor);
}
catch(e) {
$("#output").html(e);
}
};
image.src = "sample_image.jpg";
function getDominantColor() {
// Copy image to canvas
var canvas = $("<canvas/>")[0];
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
// get pixels from the central square of a 3x3 grid
var imageData = canvas.getContext("2d").getImageData(canvas.width/3, canvas.height/3, canvas.width/3, canvas.height/3).data;
var colorOccurrences = {};
var dominantColor = "";
var dominantColorOccurrence = 0;
for(var i = 0; i < imageData.length; i += 4) {
var red = imageData[i];
var green = imageData[i+1];
var blue = imageData[i+2];
//var alpha = imageData[i+3]; // not required for this task
var color = RGBtoHEX({"red": red, "green": green, "blue": blue});
if(colorOccurrences[color] == undefined) {
colorOccurrences[color] = 1;
}
else {
colorOccurrences[color] ++;
if(colorOccurrences[color] > dominantColorOccurrence) {
dominantColorOccurrence = colorOccurrences[color];
dominantColor = color;
}
}
}
return dominantColor;
}
function RGBtoHEX(rgb) {
var hexChars = "0123456789ABCDEF";
return "#"
+ (hexChars[~~(rgb.red/16)] + hexChars[rgb.red%16])
+ (hexChars[~~(rgb.green/16)] + hexChars[rgb.green%16])
+ (hexChars[~~(rgb.blue/16)] + hexChars[rgb.blue%16]);
}
The image in question is this (preview below).
However, the results when this image is processed in the code above are varied across machines/browsers: #FF635E is what I see on my machine, running Windows7 and using Firefox 32. My client running Mac gets a result of #FF474B on Safari and #FF474C on Firefox 33.
Though the results are close, why are they ideally not the exact same? Does getImageData indeed vary depending on the local setup, or is the JPG data being interpreted differently on different machines?
Edit: This image isn't a one-off case. Such color variations were noticed across a range of the image that the client requested to process. My client and I obtained different results for the same set of images.
Yes. This fact is exploited by canvas fingerprinting:
The same HTML5 Canvas element can
produce exceptional pixels on a different web browsers, depending on
the system on which it was executed.
This happens for several reasons: at the image format level — web
browsers uses different image processing engines, export options,
compression level, final images may got different hashes even if they
are pixel-perfect; at the pixmap level — operating systems use
different algorithms and settings for anti-aliasing and sub-pixel
rendering. We don't know all the reasons, but we have already
collected more than a thousand unique signatures.

Categories

Resources