HTML5 video frame capture to bitmap - javascript

I got this script:
function capture(video, scaleFactor) {
if(scaleFactor == null){
scaleFactor = 1;
}
var w = video.videoWidth * scaleFactor;
var h = video.videoHeight * scaleFactor;
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
return canvas;
}
function shoot(){
var video = document.getElementById(videoId);
var output = document.getElementById('output');
var canvas = capture(video, scaleFactor);
canvas.onclick = function(){
window.open(this.toDataURL());
};
snapshots.unshift(canvas);
output.innerHTML = '';
for(var i=0; i<1; i++){
output.appendChild(snapshots[i]);
}
}
What I want to do is export the snapshot to a bitmap image. I read that I could use this line:
canvas.toDataURL('image/jpeg');
But I don't know where to add it.
Any ideas?

ctx.drawImage(video, 0, 0, w, h);
canvas.toDataURL(...)
toDataURL will return you a string which is usually base64 encoded image (file) content. You can display it in image tag by < img src="the string"/>. Or you can use javascript to do whatever you want...

Pass it to window.open
canvas.onclick = function () {
window.open(canvas.toDataURL('image/png'));
};
Full Example : http://www.nihilogic.dk/labs/canvas2image/

Related

Rotating dynamic canvas image with javascript

I have the following code that allows the user to upload an image which gets put into a canvas, but once it has been drawn I want users to be able to rotate the image with the click of a button, but I don't know how to re-access the image object to be able to rotate the canvas. The code below is what works:
onFilePicked (e) {
const files = e.target.files;
for (let file of files) {
if(file !== undefined) {
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
this.loadImage(file, image);
}
}
},
loadImage(file, image) {
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
}
})
},
resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
},
And seen below is the function I built out to rotate the image- it works in that if I replace the code inside of the resizeImage function with the code below that the image is drawn in a way that is rotated correctly, but I don't know how to access the origImg object to be able to redraw the canvas in a separate function.
rotateImage(origImg, maxWidth, maxHeight){
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.height * scale;
canvas.height= origImg.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(origImg, 0, 0, canvas.height, canvas.width);
return canvas.toDataURL("image/jpeg");
},
Running this function as-is triggers the following console error:
Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
How do I get/reuse the origImg object from the resizeImage function so I can use it in the rotateImage function?
you can try with this code:
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.drawImage(origImg,0,0); // Or at whatever offset you like
};
And apply your code insede onload function of img and finally transform img source to date URL
Try this code, based on one file picker, two buttons. The first one resize image and the second one rotete the image
function resizeImg()
{
var oPicker = document.getElementById('avatar');
var oImage = document.getElementById('imgOut');
var file = oPicker.files[0];
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
oImage.thumbnail = this.resizeImage(img, 400, 300);
oImage.src = this.resizeImage(img, 1280, 960);
}
})
}
function rotateImg()
{
var imgOut = document.getElementById('imgOut');
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let scale = 1;
canvas.width = imgOut.height * scale;
canvas.height= imgOut.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(imgOut, 0, 0, canvas.height, canvas.width);
imgOut.src = canvas.toDataURL("image/jpeg");
}
function resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
}
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Image test</h1>
<img src="" id="imgOut" />
<label for="avatar">Choose a profile picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">
<input type="button" id="resImg" onclick="resizeImg()" value="Resize" />
<input type="button" id="rotImg" onclick="rotateImg()" value="Rotate" />
</body>
</html>
As you have a part in onFilePicked() where you store something about the images:
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
and later update the same objects in loadImage() (well, an event handler in it) as
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
It could be simply extended to
image.original = img;
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
Starting from this point, the objects in your images array would have an original field, storing the original, non-resized variant of the image.

Determining the brightness of an image using canvas

I have a function that loops through an image's pixels to determine the average "brightness" of the image as a number between 0 (black) - 255 (white).
The problem is during testing I found that while an image that's entirely black (#000000) will correctly return 0, an image that's entirely white (#FFFFFF) returns a number around 200 instead of 255. Am I missing something?
Here's my function, any help would be appreciated!
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
}
Sorry, but as the snippet below proves, the result for the image you mentioned is 255.
Maybe you want to check out what file you were using in the tests ? you're probably using a wrong file...
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.crossOrigin = 'anonymous';
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
};
getBrightness(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Solid_white.svg/768px-Solid_white.svg.png',
(b)=>console.log(b));
I just included the line img.crossOrigin = 'anonymous'; in order to avoid the cors security message.

Converting images to base64 within a loop before adding to jspdf - javascript

I have researched issues with the base64 conversion and jspdf function quite a bit. ( PS this is my first question on stackoverflow, please bare with any rookie mistakes ).
All seems to work fine with the below code except that the pdf is generated and saved before the loop where the images are converted to base64 and placed to the document is finished. I added a couple alerts to check timing. Would the solution be to check when the loop is finished, the images placed before continuing with the pdf function? if so, how? please help.
$(document).ready(function(){
$("a#getdoc").click(function(){
var doc = new jsPDF('landscape, in, legal');
var myimages = 'img1.jpg|img2.jpg|img3.png';
var myimgarray = myimages.split('|');
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/jpeg");
var dataURL = canvas.toDataURL("image/jpeg");
callback(dataURL);
canvas = null;
}
for(var i = 0; i < myimgarray.length; i++)
{
icount.count = i;
var img = new Image();
alert(checkoutimgarray);
img.src = '/Portals/0/repair-images/' + myimgarray[i];
img.onload = function(){
newData = convertImgToBase64(img);
alert(newData);
doc.addImage(newData, 'JPEG', (icount * 100), 10, 70, 15); // would doc be undefined here? out of scope?
};
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
});
});
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
function convertImgToBase64(img, outputFormat){
// clear canvas
canvas.width = img.width;
canvas.height = img.height;
// draw image
ctx.drawImage(img, 0, 0);
// get data url of output format or defaults to jpeg if not set
return canvas.toDataURL("image/" + (outputFormat || "jpeg"));
}
var images = [];
for(var i = 0; i < myimgarray.length; i++) {
var img = new Image();
img.onload = function() {
images.push({
base64: convertImgToBase64(this),
width: this.width,
height: this.height
});
// all images loaded
if(images.length === myimgarray.length) {
for(var j = 0; j < images.length; j++) {
doc.addImage(images[j].base64, 'JPEG', (j * 100), 10, 70, 15);
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
}
};
img.src = '/Portals/0/repair-images/' + myimgarray[i];
}

canvas imageData manipulation

I am playing with canvases imageData and I am having some issues with speed. What I am doing is
$(document).ready(function(){
loadCanvas();
myImageData();
});
function loadCanvas(){
canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d')
image = new Image();
image.src = '/static/images/teeth1.jpg';
image.onload = function (){
imageWidth = image.width;
imageHeight = image.height;
context.drawImage(image, 0, 0, image.width, image.height);
imageData = myImageData(context, image);
pixels = imageData.data;
console.log(pixels);
console.log(pixels.length);
console.log(imageData);
//Changing the value of each pixel
for (var y=0; y<=imageHeight; ++y){
for (var x=0; x<=imageWidth; ++x){
index = (y*imageWidth + x) * 4;
pixels[index] += 30;
pixels[++index] += 30;
pixels[++index] += 30;
}
}
}
}
function myImageData(context){
console.log("width: "+image.width+", height:"+image.height)
return context.getImageData(0, 0, image.width, image.height);
}
When I execute the above code outside the onload function from chrome's console it works very fast. But when executing the double for's inside the onload function (as it is right now) it hangs. Why is that? Is it because it is inside the onload? How can I make sure the image was fully loaded before executing the double fors(so to put them seperatelly outside the onload function)?
// Define functions before using them (Good to)
function loadCanvas(){
var canvas = document.getElementById('myCanvas'); // Define variables!
var context = canvas.getContext('2d');
var image = new Image();
image.onload = function (){
var imageWidth = image.width; // Variables again!
var imageHeight = image.height;
context.drawImage(image, 0, 0, imageWidth, imageHeight );
var imageData = myImageData(context, image); // Variables!
var pixels = imageData.data;
console.log(pixels);
console.log(pixels.length);
console.log(imageData);
//Changing the value of each pixel
for (var y=0; y<=imageHeight; ++y){
for (var x=0; x<=imageWidth; ++x){
var index = (y*imageWidth + x) * 4;
pixels[index] += 30;
pixels[++index] += 30;
pixels[++index] += 30;
}
}
};
image.src = '/static/images/teeth1.jpg'; // Set src here
}
function myImageData(ctx, img){ // Pass the actual image as argument
console.log("width: "+img.width+", height:"+img.height);
return ctx.getImageData(0, 0, img.width, img.height);
}
$(document).ready(function(){
loadCanvas(); // has myImageData() so...
//myImageData(); // why??
});

How to rotate Image using native javascript

I'm developing a game using HTML5 canvas element and native javascript. I have different sprites for game objects. Is it possible to rotate sprites using native javascript?
For example, I have a sprite image like this:
I use Image for this sprite:
var image = new Image(...);
image.src = "...";
After loading I want to rotate this image and save different projections in local variables:
var sprite_left = rotate(image, 0),
sprite_top = rotate(image, 90),
sprite_right = rotate(image, 180),
sprite_right = rotate(image, 270);
The rotate function should look like this:
function rotate(sourceImage, angle){
...
}
Could anybody help me to write the rotate function?
EDIT:
I have decided to share my code, which I used to test my sprites:
var wait = function (image, completed, count) {
if (count == null) count = 0;
if (!image.complete && count < 1000) {
count++;
window.setTimeout(function () {
wait(image, completed, count);
console.log('waiting...');
}, 10);
}
else {
completed();
}
},
rotateW = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var p = document.createElement("p");
p.innerText = "W: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(Math.PI);
context.translate(-canvas.width / 2, -canvas.height / 2);
context.drawImage(image, 0, 0);
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateE = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var p = document.createElement("p");
p.innerText = "E: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateS = function (image, frameCount) {
var canvas = document.createElement("canvas");
canvas.width = image.height * frameCount;
canvas.height = image.width / frameCount;
var p = document.createElement("p");
p.innerText = "S: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(image.height / 2, image.width / (2 * frameCount));
context.rotate(Math.PI / 2);
var i = frameCount;
while (i--> 0) {
context.drawImage(image, - image.width / 2 , - ( 0.5 + i ) * image.height);
}
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateN = function (image, frameCount) {
var canvas = document.createElement("canvas");
canvas.width = image.height * frameCount;
canvas.height = image.width / frameCount;
var p = document.createElement("p");
p.innerText = "N: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(image.height / 2, image.width / (2 * frameCount));
context.rotate( 3 * Math.PI / 2);
var i = frameCount;
while (i-- > 0) {
context.drawImage(image, -image.width / 2, (frameCount - i - 1.5) * image.height);
}
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
};
/*
N
|
W----O----E
|
S
*/
getSprites = function (image, frameCount) {
var sprite = {
N: rotateN(image, frameCount),
S: rotateS(image, frameCount),
W: rotateW(image, frameCount),
E: rotateE(image, frameCount)
};
return [
sprite.W, // left
sprite.N, // up
sprite.E, // right
sprite.S] // down
};
$.sprite = {
register: function (options) {
var image = new Image();
image.src = options.src;
wait(image, function () {
var sprites = getSprites(image, options.frameCount);
});
}
};
The final result is:
the following function will create a new Canvas out
of img (which might be an image or a canvas).
Give it an angle in radian, or 'N', 'S', 'W' for
the corresponding rotation.
function createRotatedImage(img, angle) {
angle = (angle == 'N') ? -Math.PI/2 :
(angle == 'S') ? Math.PI/2 :
(angle == 'W') ? Math.PI :
angle ;
var newCanvas = document.createElement('canvas');
newCanvas.width = img.width ;
newCanvas.height = img.height ;
var newCtx = newCanvas.getContext('2d') ;
newCtx.save () ;
newCtx.translate ( img.width / 2, img.height / 2) ;
newCtx.rotate (angle);
newCtx.drawImage ( img, - img.width / 2, - img.height / 2) ;
newCtx.restore () ;
}
Use a <canvas> to pre-render the different rotations
Store these in memory using via toBlob, optionally converting these blobs to URLs with window.URL.createObjectURL
Swap URLs as desired.
See this MDN page for canvas options
Absolutely! It's not as simple as rotating the image, though. You need to rotate the context from the canvas, and draw that image on the rotated context, and then restore it.
context.save();
context.rotate(angle);
//DRAW IT!
context.restore();
How about having a function like :
Image.prototype.rotate = function(angle) {
var c = document.createElement("canvas");
c.width = this.width;
c.height = this.height;
var ctx = c.getContext("2d");
ctx.rotate(angle);
var imgData = ctx.createImageData(this.width, this.height);
ctx.putImageData(imgData);
return new Image(imgData);
}
var img1 = new Image();
var img2 = img1.rotate(90);
Ofcourse it's just a quick sample to give you an idea.

Categories