putImageData will not draw to the canvas - javascript

After splitting up the tileset http://mystikrpg.com/images/all_tiles.png
It still will not draw onto the <canvas> I know it gets put into the tileData[] because it outputs ImageData in the console.log(tileData[1]).
$(document).ready(function () {
var tileWidth, tileHeight
ImageWidth = 736;
ImageHeight = 672;
tileWidth = 32;
tileHeight = 32;
console.log("Client setup...");
canvas = document.getElementById("canvas");
canvas.width = 512;
canvas.height = 352;
context = canvas.getContext("2d");
canvas.tabIndex = 0;
canvas.focus();
console.log("Client focused.");
var imageObj = new Image();
imageObj.src = "./images/all_tiles.png";
imageObj.onload = function() {
context.drawImage(imageObj, ImageWidth, ImageHeight);
var allLoaded = 0;
var tilesX = ImageWidth / tileWidth;
var tilesY = ImageHeight / tileHeight;
var totalTiles = tilesX * tilesY;
for(var i=0; i<tilesY; i++)
{
for(var j=0; j<tilesX; j++)
{
// Store the image data of each tile in the array.
tileData.push(context.getImageData(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
allLoaded++;
}
}
if (allLoaded == totalTiles) {
console.log("All done: " + allLoaded); // 483
console.log(tileData[1]); // > ImageData
startGame();
}
};
});
also
var startGame = function () {
console.log("Trying to paint test tile onto convas...");
try {
context.putImageData(tileData[0], 0, 0);
} catch(e) {
console.log(e);
}
}

When you draw the image to the canvas initially, why are you:
context.drawImage(imageObj, ImageWidth, ImageHeight);
Looks like you may have the parameters confused and are trying to fill the area with ImageWidth, ImageHeight... instead, draw it to 0,0
context.drawImage(imageObj, 0, 0);
Here's your code adjusted a little bit:
var tileData = [];
var tileWidth, tileHeight
var ImageWidth = 736;
var ImageHeight = 672;
var tileWidth = 32;
var tileHeight = 32;
var tilesX;
var tilesY
var totalTiles;
canvas = document.getElementById("canvas");
canvas.width = ImageWidth;
canvas.height = ImageHeight;
context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.src = "all_tiles.png";
imageObj.onload = function() {
context.drawImage(imageObj, 0, 0);
// draw the image to canvas so you can get the pixels context.drawImage(imageObj, 0, 0);
tilesX = ImageWidth / tileWidth;
tilesY = ImageHeight / tileHeight;
totalTiles = tilesX * tilesY;
for(var i=0; i<tilesY; i++) {
for(var j=0; j<tilesX; j++) {
// Store the image data of each tile in the array.
tileData.push(context.getImageData(j*tileWidth, i*tileHeight, tileWidth, tileHeight));
}
}
// test it...
// blank the canvas and draw tiles back in random positions
context.fillStyle = "rgba(255,255,255,1)";
context.fillRect(0,0,canvas.width, canvas.height);
for ( i = 0; i < 20; i++ ) {
context.putImageData(tileData[ i ], Math.random() * canvas.width, Math.random() * canvas.height );
}
};
There's no need to test 'all loaded' since it's just one image that you're splitting apart.

Related

Canvas for image clipping - context.drawImage()

I want to show four canvas from the same image
I'm working with an image which I need to be splitted into four pieces. I don't know the actual dimensions of the image so I need it to be dynamic. I already get this far, and I think the first piece is working fine, but I don't know why it is not working for the rest of the pieces. Could you point where the error could be?
I am new working with canvas, so my code is based on this answer:
https://stackoverflow.com/a/8913024/6929416
var image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
image.onload = cutImageUp;
function cutImageUp() {
var natW = image.width / 2;
var natH = image.height / 2;
var widthOfOnePiece = jQuery(window).width() / 2;
var heightOfOnePiece = jQuery(window).height() / 2;
var imagePieces = [];
for (var x = 0; x < 2; ++x) {
for (var y = 0; y < 2; ++y) {
var canvas = document.createElement('canvas');
canvas.width = widthOfOnePiece;
canvas.height = heightOfOnePiece;
var context = canvas.getContext('2d');
context.drawImage(image,
x * natW, y * natH,
natW, natH,
x * canvas.width, y * canvas.height,
canvas.width, canvas.height
);
/*drawImage(image,
sx, sy,
sWidth, sHeight,
dx, dy,
dWidth, dHeight);*/
imagePieces.push(canvas.toDataURL());
}
}
// imagePieces now contains data urls of all the pieces of the image
// load one piece onto the page
var anImageElement = document.getElementById('testing');
var anImageElement2 = document.getElementById('testing2');
var anImageElement3 = document.getElementById('testing3');
var anImageElement4 = document.getElementById('testing4');
anImageElement.src = imagePieces[0];
anImageElement2.src = imagePieces[1];
anImageElement3.src = imagePieces[2];
anImageElement4.src = imagePieces[3];
}
img{ border: 1px solid; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<img id="testing" src="">
<img id="testing2" src="">
<img id="testing3" src="">
<img id="testing4" src="">
</section>
I expect the canvas dimensions to fit on the screen, so I set them to half of the windows width and height.
The parameters for drawImage are
drawImage(
source,
sourceX, sourceY, sourceWidth, sourceHeight,
destinationX, destinationY, destinationWidth, destinationHeight
)
In your code, you are setting destinationX to x * canvas.width and destinationY to y * canvas.height. This means that for every iteration where either x or y are not 0, you are drawing outside of the destination area, that is for every parts but the first one.
Simply hard-code destinationX-Y to 0and you'll be good.
var image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
image.onload = cutImageUp;
function cutImageUp() {
var natW = image.width / 2;
var natH = image.height / 2;
var widthOfOnePiece = jQuery(window).width() / 2;
var heightOfOnePiece = jQuery(window).height() / 2;
var imagePieces = [];
for (var x = 0; x < 2; ++x) {
for (var y = 0; y < 2; ++y) {
var canvas = document.createElement('canvas');
canvas.width = widthOfOnePiece;
canvas.height = heightOfOnePiece;
var context = canvas.getContext('2d');
context.drawImage(image,
x * natW, y * natH,
natW, natH,
0, 0,
canvas.width, canvas.height
);
/*drawImage(image,
sx, sy,
sWidth, sHeight,
dx, dy,
dWidth, dHeight);*/
imagePieces.push(canvas.toDataURL());
}
}
// imagePieces now contains data urls of all the pieces of the image
// load one piece onto the page
var anImageElement = document.getElementById('testing');
var anImageElement2 = document.getElementById('testing2');
var anImageElement3 = document.getElementById('testing3');
var anImageElement4 = document.getElementById('testing4');
anImageElement.src = imagePieces[0];
anImageElement2.src = imagePieces[1];
anImageElement3.src = imagePieces[2];
anImageElement4.src = imagePieces[3];
}
img{ border: 1px solid; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<img id="testing" src="">
<img id="testing2" src="">
<img id="testing3" src="">
<img id="testing4" src="">
</section>
But note that toDataURL should almost never be used. Instead one should always prefer faster non-blocking and memory friendly toBlob().
Also, no need to create 4 canvases here, you can reuse the same at every round.
And finally, you might want to preserve your image's aspect ratio:
var image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
image.onload = cutImageUp;
function cutImageUp() {
var natW = image.width / 2;
var natH = image.height / 2;
var widthOfOnePiece = jQuery(window).width() / 2 - 20;
// preserve aspect ratio
var heightOfOnePiece = widthOfOnePiece * (natH / natW);
var canvas = document.createElement('canvas');
canvas.width = widthOfOnePiece;
canvas.height = heightOfOnePiece;
var context = canvas.getContext('2d');
var promises = [];
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < 2; ++x) {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(image,
x * natW, y * natH,
natW, natH,
0, 0,
canvas.width, canvas.height
);
promises.push(new Promise(function(resolve, reject) {
canvas.toBlob(function(blob) {
if (!blob) reject();
resolve(blob);
});
}));
}
}
return Promise.all(promises).then(function(blobs) {
// imagePieces now contains data urls of all the pieces of the image
// load one piece onto the page
var anImageElement = document.getElementById('testing');
var anImageElement2 = document.getElementById('testing2');
var anImageElement3 = document.getElementById('testing3');
var anImageElement4 = document.getElementById('testing4');
anImageElement.src = URL.createObjectURL(blobs[0]);
anImageElement2.src = URL.createObjectURL(blobs[1]);
anImageElement3.src = URL.createObjectURL(blobs[2]);
anImageElement4.src = URL.createObjectURL(blobs[3]);
})
}
img {
border: 1px solid;
display: inline-block;
}
body{margin: 0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<img id="testing" src="">
<img id="testing2" src="">
<img id="testing3" src="">
<img id="testing4" src="">
</section>

Fitting Multiple Images on a web page that update from an API

I am Trying to Build a simple web page to display a feed from my cameras that pulls a still image from the camera via the cameras api and then regrabs the image with the API (so i can configure the frame rate of the cameras to cut down on mobile data)
I have managed to build a simple website with just one of the displays, but i want to be able to display all 8 of my cameras, IP addresses 192.168.0.157 - 165
My current code is
<html>
<head>
<script type="text/JavaScript">
var refreshInterval = 1000;
var url1 = "http://192.168.0.157/api/still?passwd=pass&"
var drawDate = true;
var img1;
function init() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
img = new Image();
img.onload = function() {
canvas.setAttribute("width", img.width)
canvas.setAttribute("height", img.height)
context.drawImage(this, 0, 0);
if(drawDate) {
var now = new Date();
var text = now.toLocaleDateString() + " " + now.toLocaleTimeString();
var maxWidth = 100;
var x = img.width-10-maxWidth;
var y = img.height-10;
context.strokeStyle = 'black';
context.lineWidth = 2;
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
}
};
refresh();
}
function refresh()
{
img.src = img.src = url1 + "t=" + new Date().getTime();
setTimeout("refresh()",refreshInterval);
}
</script>
<title>Test4</title>
</head>
<body onload="JavaScript:init();">
<canvas id="canvas"/>
</body>
</html>
Thanks in advance
I'm thinking make an array for every camera IP, and do all the API stuff for each of those.
var ip = [
"192.168.0.157",
"192.168.0.158",
"192.168.0.159",
"192.168.0.160",
"192.168.0.161",
"192.168.0.162",
"192.168.0.163",
"192.168.0.164",
"192.168.0.165"
];
var img = [];
function init() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
for (var i = 0; i < ip.length; i++) {
img[i] = new Image();
img[i].onload = (function() {
canvas.setAttribute("width", img[i].width);
canvas.setAttribute("height", img[i].height);
context.drawImage(this, 0, 0);
if (drawDate) {
var now = new Date();
var text = now.toLocaleDateString() + " " + now.toLocaleTimeString();
var maxWidth = 100;
var x = img[i].width - 10 - maxWidth;
var y = img[i].height - 10;
context.strokeStyle = 'black';
context.lineWidth = 2;
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
}
})();
}
refresh();
};
function refresh() {
for (var i = 0; i < img.length; i++) {
img[i].src = "http://" + ip[i] + "/api/still?passwd=pass&t=" + new Date().getTime();
}
setTimeout("refresh()",refreshInterval);
}

Draw SVG on canvas [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I have a set of coordinates and for every pair I'd like to place a SVG on the canvas. The problem is in getCircle function. The SVG doesn't work, but if I draw a circle(see commented code) it works.
function getCircle() {
var circle = document.createElement("canvas"),
ctx = circle.getContext("2d"),
r2 = radius + blur;
circle.width = circle.height = r2 * 2;
/*
ctx.shadowOffsetX = ctx.shadowOffsetY = r2 * 2;
ctx.shadowBlur = blur;
ctx.shadowColor = "purple";
ctx.beginPath();
ctx.arc(-r2, -r2, radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
*/
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.src = "https://upload.wikimedia.org/wikipedia/en/0/09/Circle_Logo.svg";
return circle;
}
var radius = 5;
var blur = 1;
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 200;
var circle = getCircle();
ctx.clearRect(0, 0, canvas.width, canvas.height);
var data = [[38,20,2]];
for (var i = 0, len = data.length, p; i < len; i++) {
p = data[i];
ctx.drawImage(circle, p[0] - radius, p[1] - radius);
}
#c {
width: 400px;
height: 200px;
}
<canvas id="c"></canvas>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 200;
var data = [[0,20,2],[125,20,2],[250,20,2]];
drawImage();
function drawImage() {
var img = new Image();
img.onload = function() {
for (var i = 0, len = data.length, p; i < len; i++) {
p = data[i];
ctx.drawImage(this, p[0] , p[1] , 150, 150);
}
};
img.src = "https://upload.wikimedia.org/wikipedia/en/0/09/Circle_Logo.svg";
}
#c {
width: 400px;
height: 200px;
}
<canvas id="c"></canvas>
in img.onload() draw your image in specified position with widht and height using drawImage().

Picture background for canvas particle

I'm trying to create background for every created particle.
Canvas pattern is not working properly. I'm getting this error >> "SyntaxError: An invalid or illegal string was specified"
HTML
<canvas id="canvas"></canvas>
JS
(function(){
window.onload = function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'),
particles = {},
particleIndex = 0,
particleNum = 1;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.width);
function Particle(){
this.x = canvas.width / 2;
this.y = 0;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.2;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.test = 0;
this.maxLife = 100;
}
Particle.prototype.draw = function(){
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.test++;
if ( this.test >= this.maxLife ) {
delete particles[this.id];
};
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(this.x, this.y, 20, 20);
};
setInterval(function(){
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
};
for(var i in particles) {
particles[i].draw();
}
},30)
}})();
I was trying to do this also with ctx.drawImage(), but picture was displayed one time only.
Any tips?:)
Fiddle
I think the issue is the image being loaded later than its used.
Inside your draw() you have:
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,20,20);
It is a bad idea to create new images everytime you want to draw. I strongly suggest you create the img variable outside of the draw loop. Once you set the .src of an image, you have to wait until it is loaded to use it. There is an onload event you can use to let you know when its ready.
Here is an example:
var imgLoaded = false;
var img = new Image();
img.src = 'img/aaa.png';
img.onload = function() { imgLoaded = true; };
function draw() {
...
if (imgLoaded) {
var pattern = ctx.createPattern(img, 'repeat');
...
}
...
}

Shattering image using canvas

I'm trying to shatter image to pieces using canvas , this is my code :
var image = new Image();
image.src = 'koals.jpg';
image.onload = cutImageUp;
var imagePieces = [];
function cutImageUp() {
for(var x = 0; x < 5; x++) {
for(var y = 0; y < 5; y++) {
var canvas = document.createElement('canvas');
canvas.width = 50+"px";
canvas.height = 50+"px";
var context = canvas.getContext('2d');
context.drawImage(image, x *50, y * 50, 50, 50, 0, 0, 50, 50);
imagePieces.push(canvas.toDataURL());
}
}
var anImageElement = document.getElementById('img');
anImageElement.src = imagePieces[0];
}
the problem is that image is returning "blank image" (a.k.a its not loaded);
Console ain't throwing any error.
I'm opening it as local html file , both image and html document are in the same folder so there shouldn't be problem with toDataURL() not returning data due to image being on another domain.
Your problem is with the 50+"px" for canvas width and height, remove the +"px" part and your good.
From w3Specs:
The canvas element has two attributes to control the size of the coordinate space: width and height. These attributes, when specified, must have values that are valid non-negative integers.
var image = new Image();
image.src = 'koals.jpg';
image.onload = cutImageUp;
var imagePieces = [];
function cutImageUp() {
for(var x = 0; x < 5; x++) {
for(var y = 0; y < 5; y++) {
var canvas = document.createElement('canvas');
canvas.width = 50;
canvas.height = 50;
var context = canvas.getContext('2d');
context.drawImage(image, x *50, y * 50, 50, 50, 0, 0, 50, 50);
imagePieces.push(canvas.toDataURL());
}
}
var anImageElement = document.getElementById('img');
anImageElement.src = imagePieces[0];
}
jsfiddle

Categories

Resources