How to generate bezier curve of image pixel into predefined shape - javascript

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>

Related

JavaScript - Take Center of Image

I got an image, it could be of every size but I need to take the center area of 86x86. Also I've to do that in javascript when a new image is loaded, replacing the old one.
At the end of the code I need to have my 's src updated with the new image.
function loadedImage(elem,gCount){
var crop = { //just messing with numbers
top : 10,
left : 10,
right : 20,
bottom : 20,
};
var file = elem.files[0]; //I take the loaded image
var img = document.getElementsByName('imag')[gCount]; //I take the interessed <img>
var canvas = document.createElement("canvas"); //create canvas
canvas.width = crop.right - crop.left; //set dimensions
canvas.height = crop.bottom - crop.top;
var ctx = canvas.getContext("2d"); // so we can draw
var image = new Image();
image.setAttribute('crossOrigin', 'anonymous');
image.width = img.width;
image.height = img.height;
image.src = window.URL.createObjectURL(file);
ctx.drawImage(image, -crop.left, -crop.top);
image.src = canvas.toDataURL("image/png");
img.src = image.src;
}
No image is shown
Use a load event listener to wait for your image to load. Once it's ready, you can then start drawing.
To draw the center part of your image, the source x-coordinate should be half the width of your image, minus half the width of the crop. (The source y-coordinate can be calculated in a similar way.)
var input = document.getElementsByName('input')[0];
input.addEventListener('change', function (e) {
var file = e.target.files[0];
drawCroppedImage(file, 86, 86);
});
function drawCroppedImage(file, w, h) {
var canvas = document.getElementById('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
var image = new Image();
image.addEventListener('load', function (e) {
var sx = (image.width / 2) - (w / 2), // Source X
sy = (image.height / 2) - (h / 2), // Source Y
dx = 0, // Destination X
dy = 0; // Destination Y
ctx.drawImage(image, sx, sy, w, h, dx, dy, w, h);
});
image.src = URL.createObjectURL(file);
}
<input type="file" name="input">
<br><br>
<canvas id="canvas" width="86" height="86"></canvas>

Canvas background hide the rects that I added

I am new here, so please be consider.
I've created a new canvas and created a rects in the canvas , when I set a background to the canvas I have a terrible problem that The background is on the shapes
Here is the code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var background = new Image();
background.src = "url_to_image";
// Make sure the image is loaded first otherwise nothing will draw.
background.onload = function(){
ctx.drawImage(background,0,0);
}
<canvas id="canvas" width=450 height=700></canvas>
Thanks
Edit:
I found in my code a function of fillStyle that change my background,
so I delete it and instead of this I put this:
var w = canvas.width;
var h = canvas.height
var img = new Image();
img.src = "http://www.girija.info/wp-content/uploads/2015/08/Paznja-Sabranost-450x700.png";
img.onload = function () {
var pattern = ctx.createPattern(img, "repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, w, h);
};
//ctx.fillStyle = "#FAF7F8";
rect(0, 0, WIDTH, HEIGHT);
// redraw each rect in the rects[] array
for (var i = 0; i < rects.length; i++) {
var r = rects[i];
ctx.fillStyle = 'red';
rect(r.x, r.y, r.width, r.height);
}
But every drag of the rect (the rects loaded from stack and can be draggable) the background color of the rect change
You can set the background using the css property
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
ctx.rect(10, 10, 100, 100);
ctx.fill();
canvas.style.backgroundImage = 'url(https://picsum.photos/450/700)';
<canvas id="canvas" width=450 height=700></canvas>
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
background_image();
function background_image()
{
background_image = new Image();
background_image.src = 'https://image.ibb.co/kmV8kz/photodune_2359510_smiles_l_22.png';
background_image.onload = function(){
context.drawImage(background_image, 0, 0);
}
}
<canvas id="canvas" width=450 height=700></canvas>

Drawing multiple offscreen canvases into onscreen canvas

I am having an issue when I'm trying to render multiple offscreen canvases into onscreen canvas. I do get one offscreen canvas rendered but the problem is that there should be two other rendered before. In other words, only last canvas is rendered. The expected result would be three overlapping rectangles (or squares :) in red, green and blue. Here's the code:
function rectangle(color) {
var offScreenCanvas = document.createElement('canvas');
var offScreenCtx = offScreenCanvas.getContext('2d');
var width = offScreenCanvas.width = 150;
var height = offScreenCanvas.height = 150;
switch(color) {
case 1:
offScreenCtx.fillStyle='rgb(255,0,0)';
break;
case 2:
offScreenCtx.fillStyle='rgb(0,255,0)';
break;
case 3:
offScreenCtx.fillStyle='rgb(0,0,255)';
break;
}
offScreenCtx.fillRect(0,0,width,height);
return offScreenCanvas;
}
function draw(offScreenCanvas, x , y) {
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
ctx.drawImage(offScreenCanvas, x, y);
}
var images = [];
var color = 1;
for (var i=0; i<3; i++) {
var img = new rectangle(color);
images.push(img);
color++;
}
var x = 0;
var y = 0;
for (var i = 0; i < images.length; i++) {
draw(images[i], x, y);
x += 100;
y += 100;
}
I did some searching and it seems that I'm not the first with this issue, but I could not get this working properly.
Setting canvas height or width clears the canvas.
The problem with your code is that you are causing the onscreen canvas to be cleared when you set it size in the function draw
Setting the canvas size, even if that size is the same, will cause the canvas context to reset and clear the canvas. All the other canvases are rendered, but erased when you set the onscreen canvas size.
Your draw function
function draw(offScreenCanvas, x , y) {
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
// The cause of the problem ===================================
// Either one of the following lines will clear the canvas
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
//=============================================================
ctx.drawImage(offScreenCanvas, x, y);
}
To avoid this just set the canvas size once. If you need to resize the canvas and keep its content you first need to create a copy of the canvas, then resize it, then render the copy back to the original.
Demo shows 5 offscreen canvases being rendered onto one onscreen canvas.
const colours = ['#f00', '#ff0', '#0f0', '#0ff', '#00f'];
const ctx = can.getContext('2d');
can.width = innerWidth - 4; // sub 4 px for border
can.height = innerHeight - 4;
function createCanvas(color, i) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 150;
canvas.height = 150;
ctx.font = "24px arial";
ctx.fillStyle = color;
ctx.fillRect(0, i * 30, canvas.width, 30);
ctx.fillStyle = "black";
ctx.fillText("Canvas "+i,10,(i + 0.75) * 30);
return canvas;
}
colours.forEach((c, i) => {
ctx.drawImage(createCanvas(c, i), 0, 0);
})
canvas {
border: 2px solid black;
position : absolute;
top : 0px;
left : 0px;
}
<canvas id="can"></canvas>

HTML5 Canvas - Fastest way to display an array of pixel colors on the screen

Given a 40x30 array of colors what would be the fastest way to display them on the screen in a 400x300 canvas? That is, each color would require 100 pixels in the canvas element.
Using the canvas element in HTML5 I created 4 possible ways to do it. http://jsperf.com/pixel-plotting
Random pixel data is loaded into the 40x30 array. It is then displayed in a canvas of size 400x300 such that each logical pixel is represented by 100 pixels on the screen.
The fastest way (using Chrome 38.0) was to create the image data in a hidden canvas and copy it using toDataURL into the canvas that is displayed on the screen. The property imageSmoothingEnabled is set to false to stop the pixels blurring when they are scaled upwards.
Is there any other method of doing this? I tried using small canvas dimensions and just scaling it up in CSS but this led to the pixels being blurred.
I'd like to know how the test stands in other web browsers; especially mobile phone ones.
Drawing the pixel data onto the screen is quite important as it needs to happen at least 30 times a second so even a small tweak could improve efficiency a lot.
Here is the code for the four ways I tested.
Method 1
var png = document.createElement("img");
var c2 = document.getElementById("myCanvas");
var ctx2 = c2.getContext("2d");
var c1 = document.createElement("canvas");
c1.width = 40;
c1.height = 30;
var ctx1 = c1.getContext("2d");
var imgData = ctx1.createImageData(40, 30);
for (var i=0; i<imgData.data.length; i+=4) {
var x = (i/4)%40;
var y = Math.floor(i/160);
imgData.data[i] = pixelData1[x][y].r;
imgData.data[i+1] = pixelData1[x][y].g;
imgData.data[i+2] = pixelData1[x][y].b;
imgData.data[i+3] = 255;
}
ctx1.putImageData(imgData, 0, 0);
png.src = c1.toDataURL("image/png");
c2.width = 400;
c2.height = 300;
ctx2.imageSmoothingEnabled = false;
ctx2.drawImage(png, 0, 0, 400, 300);
Method 2
var c = document.getElementById("myCanvas");
c.width = 400;
c.height = 300;
var ctx = c.getContext("2d");
var imgData = ctx.createImageData(400, 300);
for (var i=0; i<imgData.data.length; i+=4) {
var x = Math.floor(((i/4)%400)/10);
var y = Math.floor(i/16000);
imgData.data[i] = pixelData1[x][y].r;
imgData.data[i+1] = pixelData1[x][y].g;
imgData.data[i+2] = pixelData1[x][y].b;
imgData.data[i+3] = 255;
}
ctx.putImageData(imgData, 0, 0);
Method 3
var png = document.createElement("img");
var c2 = document.getElementById("myCanvas");
var ctx2 = c2.getContext("2d");
var c1 = document.createElement("canvas");
c1.width = 40;
c1.height = 30;
var ctx1 = c1.getContext("2d");
for (var x = 0; x < 40; x++) {
for (var y = 0; y < 30; y++) {
ctx1.fillStyle = pixelData2[x][y];
ctx1.fillRect(x, y, 1, 1);
}
}
png.src = c1.toDataURL("image/png");
c2.width = 400;
c2.height = 300;
ctx2.imageSmoothingEnabled = false;
ctx2.drawImage(png, 0, 0, 400, 300);
Method 4
var c = document.getElementById("myCanvas");
c.width = 400;
c.height = 300;
var ctx = c.getContext("2d");
for (var x=0; x<40; x++) {
for (var y=0; y<30; y++) {
ctx.fillStyle = pixelData2[x][y];
ctx.fillRect(x*10, y*10, 10, 10);
}
}
Thanks for the response in the comments.
From Ken Frystenberg's comment I updated the tests on jsperf: http://jsperf.com/pixel-plotting/5
It seems that the fastest way is to edit the image data of a canvas not visible on the screen. Then, on the second canvas's context, set the property imageSmoothingEnabled to false. Finally call drawImage passing the first canvas as the source of the image.
To support this method in most browsers the appropriate prefixes were added to the imageSmoothingEnabled property of the canvas's context.
Here is the final code:
var c2 = document.getElementById("myCanvas");
var ctx2 = c2.getContext("2d");
var c1 = document.createElement("canvas");
c1.width = 40;
c1.height = 30;
var ctx1 = c1.getContext("2d");
var imgData = ctx1.createImageData(40, 30);
for (var i=0; i<imgData.data.length; i+=4) {
var x = (i/4)%40;
var y = Math.floor(i/160);
imgData.data[i] = pixelData1[x][y].r;
imgData.data[i+1] = pixelData1[x][y].g;
imgData.data[i+2] = pixelData1[x][y].b;
imgData.data[i+3] = 255;
}
ctx1.putImageData(imgData, 0, 0);
c2.width = 400;
c2.height = 300;
ctx2.mozImageSmoothingEnabled = false;
ctx2.webkitImageSmoothingEnabled = false;
ctx2.msImageSmoothingEnabled = false;
ctx2.imageSmoothingEnabled = false;
ctx2.drawImage(c1, 0, 0, 400, 300);

colorize a png on the canvas

I want to colorize a png on the canvas by adding a canvas called tint which will assign the color to the png on the main canvas. But nothing is drawn at all:
js fiddel code
js
var tint = document.createElement('canvas');
tint.width = 20;
tint.height = 20;
var tintCtx = tintCanvas.getContext('2d');
var canvas = document.getElementById('canvasA');
var ctx = canvas.getContext('2d');
var pic = new Image();
pic.src = 'http://i3.minus.com/jUyvRw7sMVxJL.png';
var x =0;
var y=0;
tintCtx.fillStyle = #ff3633;
tintCtx.fillRect(x,y,20,20);
tintCtx.globalCompositeOperation = "destination-atop";
tintCtx.drawImage(pic, x, y);
ctx.drawImage(pic, x, y);
ctx.globalAlpha = 0.5;
ctx.drawImage(tint, x, y);
I think I see this problem 2-3 times a week. You need to draw the image from the pic.onload event as it loads the image async - your code below pic.src executes before image is loaded.
I'm just re-arranging the code to show where you need to draw:
var tint = document.createElement('canvas');
tint.width = 20;
tint.height = 20;
var tintCtx = tintCanvas.getContext('2d');
var canvas = document.getElementById('canvasA');
var ctx = canvas.getContext('2d');
var pic = new Image();
pic.onload = function() {
tintCtx.fillStyle = #ff3633;
tintCtx.fillRect(x,y,20,20);
tintCtx.globalCompositeOperation = "destination-atop";
tintCtx.drawImage(pic, x, y);
ctx.drawImage(pic, x, y);
ctx.globalAlpha = 0.5;
ctx.drawImage(tint, x, y);
}
pic.src = 'http://i3.minus.com/jUyvRw7sMVxJL.png';
var x =0;
var y=0;
In any case you try to load an image in the fiddle that is not from the same origin so that won't work (I replaced the image url in the following fiddle so you can verify that it now draws to the canvas).
Working example:
http://jsfiddle.net/AbdiasSoftware/Br3SB/5/

Categories