Draw array of images in separate canvas - javascript

Im working with canvas
I want to load images in different canvas but the problem is all the images are drawn in the same canvas
I want the images to be loaded separately in each canvas dynamically
I have shared the js fiddle below along with the code
https://jsfiddle.net/ewhom2db/
HTML
<canvas id="canvas"></canvas>
JS
let sampleData = [
{"imageWidth":3000,"imageHeight":2000,"imagePrefix":"https://swall.teahub.io/photos/small/","thumbPath":"291-2915301_crculos-gradiente-desvanecidos-degradado-3000-x-2000.jpg","x1":200,"x2":150,"y1":150,"y2":200},
{"imageWidth":2000,"imageHeight":2000,"imagePrefix":"https://swall.teahub.io/photos/small/","thumbPath":"281-2819581_2000-x-2000-wallpapers-25238i6-anime-photos-2000.jpg","x1":200,"x2":150,"y1":150,"y2":200}
];
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < sampleData.length; i++) {
let base_image = new Image();
base_image.src = sampleData[i].imagePrefix + sampleData[i].thumbPath;
let x1 = sampleData[i].x1;
let x2 = sampleData[i].x2;
let y1 = sampleData[i].y1;
let y2 = sampleData[i].y2;
let imageWidth = sampleData[i].imageWidth;
let imageHeight = sampleData[i].imageHeight;
canvas.width = imageWidth;
canvas.height = imageHeight;
base_image.onload = function () {
// base_image.src = this.sampleData[i].imagePrefix + this.sampleData[i].thumbPath;
ctx.drawImage(base_image, 0, 0);
ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
// base_image.src.push(this.sampleData[i].imagePrefix + this.sampleData[i].thumbPath);
};
}
Help will be appreciated thanks

You are drawing over the same canvas context every time you draw an image. If you want to draw each image to a separate canvas then you need to have separate canvases to draw them to.
You could create an array of canvases and then draw to the context of each canvas.
let sampleData = [
{
imageWidth: 3000,
imageHeight: 2000,
imagePrefix: "https://swall.teahub.io/photos/small/",
thumbPath:
"291-2915301_crculos-gradiente-desvanecidos-degradado-3000-x-2000.jpg",
x1: 200,
x2: 150,
y1: 150,
y2: 200
},
{
imageWidth: 2000,
imageHeight: 2000,
imagePrefix: "https://swall.teahub.io/photos/small/",
thumbPath:
"281-2819581_2000-x-2000-wallpapers-25238i6-anime-photos-2000.jpg",
x1: 200,
x2: 150,
y1: 150,
y2: 200
}
];
let canvas = [];
let ctx = [];
for (let i = 0; i < sampleData.length; i++) {
canvas.push(document.createElement("canvas"))
ctx.push(canvas[i].getContext('2d'));
document.body.appendChild(canvas[i]);
let base_image = new Image();
base_image.src = sampleData[i].imagePrefix + sampleData[i].thumbPath;
let x1 = sampleData[i].x1;
let x2 = sampleData[i].x2;
let y1 = sampleData[i].y1;
let y2 = sampleData[i].y2;
let imageWidth = sampleData[i].imageWidth;
let imageHeight = sampleData[i].imageHeight;
canvas[i].width = imageWidth;
canvas[i].height = imageHeight;
base_image.onload = function () {
// base_image.src = this.sampleData[i].imagePrefix + this.sampleData[i].thumbPath;
ctx[i].drawImage(base_image, 0, 0);
ctx[i].strokeRect(x1, y1, x2 - x1, y2 - y1);
// base_image.src.push(this.sampleData[i].imagePrefix + this.sampleData[i].thumbPath);
};
}
Your image appear to be so far apart because your canvases are huge but the image doesn't fill the canvas.

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.

How to generate bezier curve of image pixel into predefined shape

I have such type of image:
and I have this texture:
I want to generate such curves that it should get fit in collar shape. I tried this snippet code but unable to do so. Help me
var ctx = c.getContext("2d"); // just some inits for demo
var img = new Image;
img.onload = slice;
img.src = "//i.stack.imgur.com/UvqUP.gif";
function slice() {
var w = c.width = this.width;
var h = c.height = this.height;
var step = Math.PI*0.8/h; // full circle / width of canvas
var scale =250; // max displacement on y
for(var x = 0; x < w; x++) {
ctx.drawImage(this,
x, 0, 1, h, // source line from image
x, Math.sin(step*x)*scale, 1, h); // displaced line
}
}
canvas{
transform:rotate(90deg)
}
<canvas id=c></canvas>
I had implemented this kind of curve into collar structure.Some of the changes in the step and scale value and I got my solution.
var ctx = c.getContext("2d"); // just some inits for demo
var img = new Image;
img.onload = slice;
img.src = "//i.stack.imgur.com/UvqUP.gif";
function slice() {
var w = c.width = this.width;
var h = c.height = this.height;
var step = Math.PI*2.3/w/2; // full circle / width of canvas
var scale =-180 // max displacement on y
for(var x = 0; x < w; x++) {
ctx.drawImage(this,
x, 0, 1, h, // source line from image
x, Math.sin(step*x)*scale, 1, h); // displaced line
}
}
<canvas id=c></canvas>

Javascript array of images move across canvas randomely

I am new to javascript and am trying to make an animation of snow for an assignment.
So far I have been able to create some small background snow (randomly sized circles) but I want to use some snowflake png files for more moving snow. This is what I have but I am pretty sure the image parts are pretty wrong.
Really not sure how to make this work so any tips would be greatly appreciated.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var colours = ["white", "azure", "floralwhite", "#EAEDED"];
var r = 3.5;
var snow = [];
for (var i=0;i<1000;i++){
var s = {
x : i*2,
y : 0,
colour : colours[Math.round(Math.random()*colours.length)],
dx : Math.random(),
dy : Math.random()*3,
}
snow.push(s);
}
var flakes = ["flak1", "flak2", "flak3"];
flak1 = new Image();
flak1.src = "snow1.png";
flak2 = new Image();
flak2.src = "snow2.png";
flak3 = new Image();
flak3.src = "snow3.png";
for (var e=0;e<10;e++){
var f = {
x: e*2,
y: 0,
image: flakes[Math.round(Math.random()*flakes.length)],
dx: Math.random(),
dy: 1,
}
flakes.push(f);
}
var grd = context.createLinearGradient(0,0,0,500);
grd.addColorStop(0, "#85C1E9");
grd.addColorStop(1, "#EBF5FB");
function itSnows(){
//draw background
context.fillStyle = grd;
context.fillRect(0,0,canvas.width,canvas.height);
context.fillStyle = "white";
context.fillRect(0,650,canvas.width,50);
house = new Image();
house.src = "house.png";
context.drawImage(house, 10, 490,200,200);
context.drawImage(house, 200, 490,300,200);
context.drawImage(house, 480, 490,250,200);
context.drawImage(house, 740, 490,200,200);
context.drawImage(house, 950, 490,250,200);
sun = new Image();
sun.src = "sun.png";
context.drawImage(sun,0,0,600,350);
//draw snow
for(var i=0;i<snow.length;i++){
context.fillStyle = snow[i].colour;
context.beginPath();
context.arc(snow[i].x,snow[i].y,r*Math.random(),0,2*Math.PI);
context.fill();
snow[i].y = (snow[i].y + snow[i].dy) % 700;
snow[i].x = (snow[i].x + snow[i].dx) % canvas.width;
//draw flakes
for (var e=0;e<flakes.length;e++){
context.drawImage(flakes[e], flakes[e].x, flakes[e].y, 30, 30);
flakes[e].y = (flakes[e].y + flakes[e].dy) % 700;
flakes[e].x = (flakes[e].x + flakes[e].dx) % canvas.width;
}
}
}
setInterval(itSnows, 25);

Merge a png overlay and image into single file

I got it working using crop as recommended. Here is how I got it with the plugin. The if statement is only because I have multiple crop sizes, the circular crop is only for square images.
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
if (width==height){
context.globalCompositeOperation='destination-in';
context.beginPath();
context.arc(width/2,height/2,height/2,0,Math.PI*2);
context.closePath();
context.fill();
}
var imageData = canvas.toDataURL('image/png');
return imageData;
},
-- Original Question --
I'm using a jQuery plugin called CropBox which I have set up to export a 300x300 image. I am trying to take the square image and add an overlay that will make the image appear round, adding white corners or subtracting the overlay and have transparent corners.
What I'm going for.
The plugin uses a portion of the canvas to create the image. Once the image is captured I'm looking to add the overlay.
Adding my image and trying to draw the image.
var overlay = new Image();
overlay.src = 'MyOverlay.png';
context.drawImage(overlay, 0, 0);
Then I get lost on how to add this to imageData. It should start at 0, 0 too, any input would be appreciated.
Part of the plugin:
(function ($) {
var cropbox = function(options, el){
var el = el || $(options.imageBox),
obj =
{
state : {},
ratio : 1,
options : options,
imageBox : el,
thumbBox : el.find(options.thumbBox),
spinner : el.find(options.spinner),
image : new Image(),
getDataURL: function ()
{
var width = this.thumbBox.width(),
height = this.thumbBox.height(),
canvas = document.createElement("canvas"),
dim = el.css('background-position').split(' '),
size = el.css('background-size').split(' '),
dx = parseInt(dim[0]) - el.width()/2 + width/2,
dy = parseInt(dim[1]) - el.height()/2 + height/2,
dw = parseInt(size[0]),
dh = parseInt(size[1]),
sh = parseInt(this.image.height),
sw = parseInt(this.image.width);
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
var imageData = canvas.toDataURL('image/png');
return imageData;
},
getBlob: function()
{
var imageData = this.getDataURL();
var b64 = imageData.replace('data:image/png;base64,','');
var binary = atob(b64);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
},

Categories