here is the jsfiddle
i have this as my source canvas
HTML
<h1>Source Canvas</h1>
<canvas id="source" width=436 height=567></canvas>
<h1>Destination Canvas</h1>
<canvas id="destination" width=436 height=567></canvas>
javascript
var sourceImage, ctx, sourceCanvas, destinationCanvas;
//get the canvases
sourceCanvas = document.getElementById('source');
destinationCanvas = document.getElementById('destination');
//draw the source image to the source canvas
ctx = sourceCanvas.getContext('2d');
function start() {
ctx.drawImage(img1, 0, 0);
ctx.globalCompositeOperation = "source-atop";
var pattern = ctx.createPattern(img, 'repeat');
ctx.rect(0, 0, sourceCanvas.width, sourceCanvas.height);
ctx.fillStyle = pattern;
ctx.fill();
ctx.globalAlpha = .10;
ctx.drawImage(img1, 0, 0);
ctx.drawImage(img1, 0, 0);
ctx.drawImage(img1, 0, 0);
//ctx.globalAlpha = 1;
}
var img1 = new Image();
var img = new Image();
img.onload = function () {
img1.onload = function () {
start();
}
img1.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/4jiSz1.png";
}
img.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/BooMu1.png";
i want to to show what is in source canvas in my destination canvas.
i tired
var image, destinationCtx;
//create the image
image = new Image();
//get the base64 data
image.src = sourceCanvas.toDataURL('image/png');
//get the destination context
destinationCtx = destinationCanvas.getContext('2d');
//copy the data
destinationCtx.drawImage(image, 0, 0);
//done
but having no luck. am i missing something?
Copy via imageData,Copy via Base64 data,Copy via direct draw any method will do my job.
when i try with
http://jsperf.com/copying-a-canvas-element
it copies but when i put my source canvas writer it does not work ? am i missing something?
You can directly copy one canvas over other. Like this...
var destinationCtx;
//get the destination context
destinationCtx = destinationCanvas.getContext('2d');
//copy the data
destinationCtx.drawImage(sourceCanvas, 0, 0);
You can use getImageData from the source canvas and putImageData to the destination canvas.This is the fastest one compare to other ways.
var sourceCtx, destinationCtx, imageData;
sourceCtx = sourceCanvas.getContext('2d');
destinationCtx = destinationCanvas.getContext('2d');
imageData = sourceCtx.getImageData(0, 0, sourceCanvas.width - 1, sourceCanvas.height - 1);
destinationCtx.putImageData(imageData, 0, 0);
source:/ https://jsperf.com/copying-a-canvas-element
Related
I'm creating a maze application with Canvas and having a token traverse the maze from start to finish.
I completed the maze generation and am trying to generate a token at grid (0,0). I've created a button to select a token and throwing a debugger at the end does show that the icon is created in the right position, but it is not persisting after I continue. I've tried adding the image.onload to the drawImage function, but it is still not working.
This was what I originally had that rendered the image on Canvas while in debugger
function selectIcon(){
let body = document.querySelector("body")
let image = document.createElement("img")
image.src = "image.jpg"
body.prepend(image)
// debugger
}
function clickHandler(){
document.addEventListener("click", (e) => {
button = e.target
console.log(button)
if(button.matches(".choose-token")){
renderIconToCanvas()
}
})
}
function renderIconToCanvas(){
const myCanvas = document.querySelector("canvas")
myCanvas.setAttribute("id", "maze-canvas")
const image = new Image;
image.src = "maze/image.jpg"
let ctx = myCanvas.getContext("2d");
ctx.drawImage(image, 0, 0);
}
All of the solutions that I've read say to add image.onload to the drawImage, but when I put it in, my image no longer renders in debugger.
function renderIconToCanvas(){
const myCanvas = document.querySelector("canvas")
myCanvas.setAttribute("id", "maze-canvas")
const image = new Image;
image.src = "maze/image.jpg"
image.onload = function (){
let ctx = myCanvas.getContext("2d");
ctx.drawImage(image, 0, 0);
}
}
Is there something else that I might be missing? Another way that I tried:
let canvas = document.querySelector("canvas")
let ctx = canvas.getContext("2d");
const image = new Image(20,20);
image.src = "./image.jpg"
function draw(ctx, image){
if (!image.complete){
setTimeout(function(){
draw(ctx, image);
}, 50);
return
}
ctx.drawImage(image, 0, 0, this.width, this.height);
}
draw(ctx, image)
I had an image of Canada and manually recolored its pixels to shades of blue. I then tried to make a script that would do the same(into red) without me going through all the hassle.
But for some reason, the canvas simply repaints the same image of the blue Canada in Mozilla and Chrome(sometimes not even draws it).
Mozilla says accessing ImageData is a security error. What did I get wrong and how do I fix it?
Snippet right here:
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
var imgPath = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Copper_sulfate.jpg/234px-Copper_sulfate.jpg";
var imgObj = new Image();
imgObj.crossOrigin = "anonymous";
imgObj.src = imgPath;
imgObj.onload = function() {
context.drawImage(imgObj, 0, 0);
map = context.getImageData(0, 0, 234, 240);
imagedata = map.data;
for (p = 0; p < imagedata.length; p += 4) {
imagedata[p] = imagedata[p + 2];
imagedata[p + 2] = 0;
imagedata[p + 3] = 255;
};
context.putImageData(map, 0, 0);
};
<img id="Canada" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Copper_sulfate.jpg/234px-Copper_sulfate.jpg" />
<canvas id='canvas' width='234px' height='240px'></canvas>
I am trying to show previews of uploaded images in a canvas. The preview should be a square version of image.
What I have:
var img = new Image;
img.src = imageSrc;
var c = document.getElementById('file-preview-' + data.response.id);
var ctx = c.getContext("2d");
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
And the preview:
So how can I draw on the canvas a 150x150 square with maintained ratio cropped version of the image?
For example for this image:
I should get:
Here's a method that yields precisely the result you desire, cropped, resized and centered (with commented out lines that yield a left based cropping instead)...
var ctx;
function init(event) {
ctx = document.getElementById('canvas').getContext('2d');
// Your preview is actually 120x120,
// but I've stuck with the textual description of
// your requirements here.
ctx.canvas.width = 150;
ctx.canvas.height = 150;
loadBackground('http://i.stack.imgur.com/PCKEo.png');
}
function loadBackground(path) {
var img = new Image();
img.onload = drawBackground;
img.src = path;
}
function drawBackground(event) {
var img = event.target;
var imgSize = Math.min(img.width, img.height);
// The following two lines yield a central based cropping.
// They can both be amended to be 0, if you wish it to be
// a left based cropped image.
var left = (img.width - imgSize) / 2;
var top = (img.height - imgSize) / 2;
//var left = 0; // If you wish left based cropping instead.
//var top = 0; // If you wish left based cropping instead.
ctx.drawImage(event.target, left, top, imgSize, imgSize, 0, 0, ctx.canvas.width, ctx.canvas.height);
}
window.addEventListener('load', init, false);
<canvas id="canvas"></canvas>
Based on information from this question: SO Question
I was able to modify what was done to create a square cropped image in canvas:
var img = new Image;
img.src = "http://cdn.bmwblog.com/wp-content/uploads/2016/02/M-Performance-Parts-BMW-M2-3.jpg"; //Or whatever image source you have
var c= document.getElementById('file-preview');
var ctx=c.getContext("2d");
img.onload = function(){
ctx.drawImage(img, img.width/2, img.height/2, img.width, img.height, 0, 0, img.width, img.height);
};
You just have to modify the arguments you are passing to the drawImage function as well as add some more.
You can see a fiddle here: https://jsfiddle.net/4d93pkoa/3/
Remember that the first two parameters specify the image's top left coordinates within the canvas element.
Remember to set the width and height of the canvas element in HTML to a square shape.
I have a problem displaying one canvas to another. I do everything according to this solution
<script>
var source = document.getElementById('hiddenCanvas');
var source_ctx = source.getContext('2d');
var img = new Image();
img.onload = function(){
source.width = img.width;
source.height = img.height;
source_ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = 'icon.jpg';
var destination = document.getElementById('visibleCanvas');
var destin_ctx = destination.getContext('2d');
destin_ctx.drawImage(source, 0, 0);
</script>
Well, first canvas element displays picture correctly, but whatever I do, the second canvas does not want to display a picture.
<script>
function init()
{
var source = document.getElementById('hiddenCanvas');
var source_ctx = source.getContext('2d');
var destination = document.getElementById('visibleCanvas');
var destin_ctx = destination.getContext('2d');
var img = new Image();
img.onload = function(){
source.width = img.width;
source.height = img.height;
source_ctx.drawImage(img, 0, 0, img.width, img.height);
destin_ctx.drawImage(source, 0, 0);
}
img.src = 'arun.jpg';
}
</script>
</head>
<body onload="init();">
<canvas id="hiddenCanvas" />
<canvas id="visibleCanvas" />
Your code is not working because you are trying to access canvas element before it is loaded to dom
The way you've currently structured the code, img.onload is executed after the destin_ctx.drawImage line. That means that your program flow currently looks something like this:
Image is told to start loading
Destination canvas is drawn using (currently blank) source canvas
Image finishes loading
Image's onload executes, causing the source canvas to be drawn to. The destination canvas is NOT updated, because the destin_ctx.drawImage operation is a one-time copy.
What you need to do is move the destin_ctw.drawImage call to a place in the execution flow where you know the source canvas will definitely contain the appropriate contents. In this simple case, moving it to inside the image's onload would work.
Here's a full (but simplified) HTML file that works for me in Chromium, with a changed image url:
<script>
function load() {
var source = document.getElementById('hiddenCanvas');
var source_ctx = source.getContext('2d');
var destination = document.getElementById('visibleCanvas');
var destin_ctx = destination.getContext('2d');
var img = new Image();
img.onload = function(){
source.width = img.width;
source.height = img.height;
source_ctx.drawImage(img, 0, 0, img.width, img.height);
destin_ctx.drawImage(source, 0, 0);
}
img.src = 'ship360_32.png';
}
</script>
<body onload="load()">
<canvas id="hiddenCanvas"></canvas>
<canvas id="visibleCanvas"></canvas>
</body>
You are trying to draw the image from source before the image is loaded and the source even have the image.
Move the last draw operation inside the onload handler. Also remember to set the size for destination canvas:
var source = document.getElementById('hiddenCanvas');
var source_ctx = source.getContext('2d');
var destination = document.getElementById('visibleCanvas');
var destin_ctx = destination.getContext('2d');
var img = new Image();
img.onload = function(){
source.width = img.width;
source.height = img.height;
source_ctx.drawImage(img, 0, 0, img.width, img.height);
destination.width = source.width;
destination.height = source.height;
destin_ctx.drawImage(source, 0, 0);
}
img.src = 'icon.jpg';
This is working, but I feel this code is lengthy.
I'm looking for better idea.
var clone = function(imageData) {
var canvas, context;
canvas = document.createElement('canvas');
canvas.width = imageData.width;
canvas.height = imageData.height;
context = canvas.getContext('2d');
context.putImageData(imageData, 0, 0);
return context.getImageData(0, 0, imageData.width, imageData.height);
};
The ImageData constructor accepts the image data array.
const imageDataCopy = new ImageData(
new Uint8ClampedArray(imageData.data),
imageData.width,
imageData.height
)
With TypedArray.prototype.set() you can directly copy the data.
var imageDataCopy = new Uint8ClampedArray(originalImageData.data);
imageDataCopy.data.set(originalImageData.data);
This sets the content of imageDataCopy to be identical to originalImageData.
Most times it should be sufficient to simply assign the imageData to a new variable, just like:
myImgData=ctx.getImageData(0,0,c.width,c.height); //get image data somewhere
imgDataCopy = myImgData; // clone myImgData
...now imgDataCopy contains a separate copy of myImgData. 🤷♂️
Demo
The snippet below creates 4 "frames" in an array of ImageData's and then loop through them.
const c = document.getElementById('canvas'),
ctx = c.getContext("2d");
var wh=70, iDatas=[], i=0,
lines=[[10,10,wh-10,wh-10], [wh/2,5,wh/2,wh-5], // ⤡,↕
[wh-10,10,10,wh-10], [5,wh/2,wh-5,wh/2]]; // ⤢,↔
c.width=wh;
c.height=wh;
ctx.strokeStyle='blue'; //setup to draw
ctx.lineWidth=9;
ctx.lineWidth='round';
for(var [x1,y1,x2,y2] of lines){
ctx.beginPath();
ctx.moveTo(x1,y1); //draw something
ctx.lineTo(x2,y2);
ctx.stroke();
var d=ctx.getImageData(0,0,c.width,c.height); //get imgdata
iDatas.push( d ); //save imgdata to array
ctx.clearRect(0, 0, c.width, c.height); //clear canvas
}
ctx.strokeStyle='green'; //❌has no effect:
// ↑ shows that color data comes from the source (can't be changed)
ctx.lineWidth='round'; //❌has no effect:
// ↑ shows that non-color styling does NOT come from source (CAN'T be changed)
//now you can refer to the image data as iData[i] where i= 0 to 3
drawFrame();
function drawFrame(){
ctx.putImageData( iDatas[i],0,0); //draw imgData from array
i=(i==3?0:i+1); //set next iteration #
setTimeout(function(){ drawFrame() }, 100); //schedule next frame
}
canvas{ border:2px dotted salmon; }
<canvas id='canvas'></canvas>