colorize a png on the canvas - javascript

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/

Related

DrawImg on canvas takes more clicks to draw

It's a tic tac toe game using canvas, used the onclick and draw image when clicked but sometimes it needs more than 2 clicks to draw the image I think it's because the other functions are outside the $(function()...) but puting them in cause errors .Sorry I'm new.
$(function(){
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d');
ctx.beginPath();ctx.moveTo(200,0);ctx.lineTo(200,600);ctx.stroke();
ctx.beginPath();ctx.moveTo(100,0);ctx.lineTo(100,600);ctx.stroke(); //Lineas deljuego
ctx.beginPath();ctx.moveTo(0,100);ctx.lineTo(600,100);ctx.stroke();
ctx.beginPath();ctx.moveTo(0,50);ctx.lineTo(600,50);ctx.stroke();
});
var turns=0;
function marcar(e){
var x= e.pageX;
console.log(e.pageX);
var y= e.pageY;
cuadranteX=0;
cuadranteY=0;
if(x>=7&&x<=203)
cuadranteX=0;
else{
if(x>=211&&x<=404)
cuadranteX=105;
else
cuadranteX=205;
}
if(y>=7&&y<=198)
cuadranteY=0;
else{
if(y>=212&&y<=398)
cuadranteY=53;
else
cuadranteY=105;
}
console.log(e.pageY);
console.log(cuadranteX);
console.log(cuadranteY);
draw(cuadranteX,cuadranteY);
}
function draw(x,y){
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var img = new Image();
if(turns%2==0)
img.src ="./img/blackcat.png"
else
img.src ="./img/whitecat.png"
ctx.drawImage(img,x,y,90,45);
console.log("pintado");
turns++;
}
<canvas id="canvas" onclick="marcar(event)"></canvas>
What you are doing to draw the image:
var img = new Image();
if(turns%2==0)
img.src ="./img/blackcat.png"
else
img.src ="./img/whitecat.png"
ctx.drawImage(img,x,y,90,45);
... that does not guarantee the image has been fully loaded,
look at some examples of how to use that correctly:
https://www.rgraph.net/canvas/reference/drawimage.html
But for something this simple I would not use images, just draw a letter ( X or O ).
And your math/if conditions are overly complicated for this, see sample below
let size = 60 // square_size
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size * 3;
let ctx = canvas.getContext('2d');
ctx.font = '48px serif';
ctx.beginPath();ctx.moveTo(size*2,0); ctx.lineTo(size*2,size*3); ctx.stroke();
ctx.beginPath();ctx.moveTo( size,0); ctx.lineTo( size,size*3); ctx.stroke();
ctx.beginPath();ctx.moveTo(0,size*2); ctx.lineTo(size*3,size*2); ctx.stroke();
ctx.beginPath();ctx.moveTo(0, size); ctx.lineTo(size*3, size); ctx.stroke();
var turns=0;
function marcar(e){
var x= e.pageX;
var y= e.pageY;
cuadranteX = Math.floor(x / size) % 3;
cuadranteY = Math.floor(y / size) % 3;
draw(cuadranteX,cuadranteY);
}
function draw(x,y){
ctx.fillStyle = turns%2==0? "red": "blue"
ctx.fillText(turns%2==0? "X": "O", x*size + 10, y*size + 45)
turns++;
}
<canvas id="canvas" onclick="marcar(event)"></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>

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>

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