I want to take a source image and put its pixel data into a element with a CanvasRenderingContext2D grid.
I'm writing a javascript function to work with certain pixel points of data,
but I keep getting an error from this line:
ctx.putImageData(sourceImage, 0, 0);
Here is my current javascript function that accepts a class ID of an img element as its argument:
function mapMyImage(sourceImageID) {
// Declare variable for my source image
var sourceImage = document.getElementById(sourceImageID);
// Creates a canvas element in the HTML to hold the pixels
var canvas = document.createElement('canvas');
// Create a 2D rendering context for our canvas
var ctx = canvas.getContext('2d');
// After the image has loaded, put the source image data into the
// 2D rendering context grid
function imgToPixelArray() {
// In the context of the canvas, make an array of pixels
ctx.putImageData(sourceImage, 0, 0);
}
// Call the above function once the source image has loaded
sourceImage.onload = imgToPixelArray();
// Get Access to the pixel map now stored in our 2D render
var imageData = ctx.getImageData(0, 0, 400, 300);
}
Why am I getting an error when I am trying to put my source image's pixel data into a 2D rendering context grid?
It looks like you want to clip a 400x300 subsection of the image and draw it into the canvas.
You don't need .getImageData and .putImageData to accomplish that.
You can use the clipping version of .drawImage to do that:
context.drawImage(
img, // the image source
0,0, // start clipping from the source at x=0, y=0
400,300 // clip a subsection that's 400x300 in size
0,0 // draw that clipped subsection on the canvas at x=0,y=0
400,300 // make the drawing 400x300 (don't scale)
)
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/landscape2.jpg";
function start(){
ctx.drawImage(img, 0,0,400,300, 0,0,400,300);
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<h4>subsection clipped to the canvas</h4>
<canvas id="canvas" width=400 height=300></canvas>
<h4>The original image</h4>
<img src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/landscape2.jpg">
Related
Suppose I have an image and a div whose position is absolute and is above that image (z-index of div more than z-index of image).Something like this :
I want to take screenshot of what is visible through the div using JavaScript. At first I thought of changing the div to a canvas and then I wrote this code:
<div class="utility-btn">
<button class="enquiry-btn" onclick="openEnquiry()">?</button>
</div>
<div id="enquiry">
<button id="close" onclick="closeEnquiry()">X</button>
<div class="cover">
<canvas id="capture"></canvas>
<button class="btn" onclick="takeScreenshot()">
Click to enquiry
</button>
</div>
</div>
Function to take screenshot:
function takeScreenshot() {
var canvas = document.getElementById('capture');
ctx = canvas.getContext('2d');
var backCanvas = document.createElement('canvas');
backCanvas.width = canvas.width;
backCanvas.height = canvas.height;
var backCtx = backCanvas.getContext('2d');
backCtx.drawImage(canvas, 0, 0);
ctx.drawImage(backCanvas, 0, 0);
var dataURL = backCanvas.toDataURL();
console.log(dataURL);
}
But the image of dataURL was not what I expected it was just a blank image:
How can I implement this feature. How can I do it without using any external library?
There are two problems:
#1
If we look at your bit of code responsible for actually taking the screenshot
function takeScreenshot() {
var canvas = document.getElementById('capture');
ctx = canvas.getContext('2d');
var backCanvas = document.createElement('canvas');
backCanvas.width = canvas.width;
backCanvas.height = canvas.height;
var backCtx = backCanvas.getContext('2d');
backCtx.drawImage(canvas, 0, 0);
ctx.drawImage(backCanvas, 0, 0);
var dataURL = backCanvas.toDataURL();
console.log(dataURL);
}
we can see that canvas is the element you want to have the screenshot taken onto. Later on you're creating an empty new canvas backCanvas and make it the size of the first canvas. Afterwards you're drawing the empty first canvas on the second and finally the empty second canvas back to the first.
So that does not make too much sense.
Instead you need to take the actual canvas generated by threeJS. These lines of your code append a <canvas> element to the container <div>, threeJS is using:
const container = document.getElementById('container');
container.appendChild(renderer.domElement);
We can reference it using:
document.getElementById("container").children[0]
#2
As threeJS uses WebGL to draw stuff, it's rendering context is not the regular and for performance reasons the browser is clearing the drawing buffer after something has been drawn onto - so your screenshot would come up empty all the time. There is an option you need to pass to the THREE.WebGLRenderer constructor to keep the drawingbuffer called preserveDrawingBuffer.
So change this line:
renderer = new THREE.WebGLRenderer();
to this
renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true});
and your screenshot function to this:
function takeScreenshot() {
var canvas = document.getElementById('capture');
ctx = canvas.getContext('2d');
ctx.drawImage(document.getElementById("container").children[0], 0, 0);
var dataURL = canvas.toDataURL();
console.log(dataURL);
}
I am loading a picture into a canvas; I drawImage(), store getImageData() into a variable for manipulating. I would like to be able to manipulate the data many times for example: add/remove various filters. How can I store the data so that it updates every time I draw the picture with putImageData()?
Basically, I think I am misunderstanding the use of getImageData or using it incorrectly. My thought was that any manipulation that was done to the picture, I could run getImageData and update the variable that contained the information, and use it to "redraw" the picture.
Example:
In the snippet below Lets say I run a function that turn the picture black and white. I have another function that resizes the picture when it is clicked. When I resize the picture the the black and white filter disappears. What am I doing wrong to keep the information of the picture?
//Read in picture
var reader = new FileReader();
reader.onload = function leDraw(e){
imgObj = new Image();
picWidth = canvas.width/2;
picHeight = canvas.height/2;
imgObj.src = e.target.result;
newX = 0;
newY = 0;
ctx.drawImage(imgObj,0,0, picWidth, picHeight);
imageData = ctx.getImageData(newX,newY, canvas.width, canvas.height);
originalCopy = ctx.getImageData(newX,newY, picWidth, picHeight);
data = imageData.data;
function resize(val){ Resizes picture
userPicHeight = document.getElementById("cSelect").value;
userPicWidth = document.getElementById("cSelect").value;
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.drawImage(imgObj, newX, newY, userPicWidth, userPicHeight);
window['imageData'] = ctx.getImageData(newX,newY, userPicWidth, userPicHeight);
ctx.putImageData(imageData, newX, newY);
};
imageData is a snapshot of canvas pixel data. In your case it's the entire canvas's (colored--not B&W) pixel data.
So when you do .putImageData(imageData...) the unaltered snapshow is again displayed on the canvas.
If you want to rescale a B&W version of your picture:
Draw your color image on a new canvas created with var memCanvas = document.createElement. Size the canvas to the image size. The canvas can be left in-memory -- no need to appendChild it into the DOM.
Apply the filter to the new canvas with getImageData, modify pixel data, putImageData. Now you have an "image-canvas" that you can later use to resize, etc.
Draw the image-Canvas onto the visible canvas: context.drawImage(memCanvas,0,0). Yes, the memCanvas can be an image source for drawImage.
To scale the B&W version of the image, just clear the canvas, scale the canvas with context.scale & then draw the scaled B&W image with drawImage(memCanvas,0,0)
If you later want to re-rescale the B&W image, you can do Step#4 again.
Example code and a Demo using a grayscale filter:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/kingcard.png";
function start(){
// create a grayscale image-canvas
var grayImg=makeFilteredImageCanvas(img,grayscaleFilter);
// scale the visible canvas
ctx.scale(1.25,1.25);
// draw the grayscale imag-canvas on the canvas
// (the result will be scaled)
ctx.drawImage(grayImg,0,0);
}
function makeFilteredImageCanvas(img,filter){
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
iw=c.width=img.width;
ih=c.height=img.height;
cctx.drawImage(img,0,0);
filter(cctx);
return(c);
}
function grayscaleFilter(context){
var canvas=context.canvas;
var w=canvas.width;
var h=canvas.height;
var imageData=context.getImageData(0,0,w,h);
var data=imageData.data;
for(var i=0;i<data.length;i+=4){
var gray=data[i]*0.33+data[i+1]*0.5+data[i+2]*0.16;
data[i]=data[i+1]=data[i+2]=gray;
}
context.putImageData(imageData,0,0);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>Grayscale image scaled up by 25%</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Original Image:</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/kingcard.png' crossOrigin='anonymous'>
Colleagues,
I have designed a dashboard with HTML canvas and want to show on same page a flot graph, toggling between them with a button.
The problem that I am facing is that when I click to get the flot, the graph shows up under the canvas, and not in the same place (as I want).
This is the relevant code :
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="800" height="400" style="background-color:#ffffff"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radio = canvas.height / 2;
var ent_direc={{ent_direc}};
var ent_vel={{ent_vel}};
ctx.translate(radio,radio);
radio_direc = radio * 0.9;
......
function show_graph is called when I click the button
function show_graph(){
// create dynamic DIV to hold graph
var div = document.createElement('div');
div.id = "placeholder";
document.body.appendChild(div) document.getElementById("placeholder").setAttribute("style","width:600px;height:300px");
ctx.save();
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
ctx.restore();
data_g =[ [0,2],[1,4],[2,5]];
$(document).ready(function(){
$.plot($("#placeholder"), [
{
data: data_g ,
bars:
{
show: true
}
}
]);
});
Any idea on how to show the flot graph on the same canvas area?
What you try is not that simple. Flot takes a div element and creates its own canvas elements in this div (and some stuff around the canvas like axis labels).
The easiest solution would be to hide your original canvas when you create the Flot graph:
$('#canvas').hide();
I have this canvas here:
http://jsbin.com/soserubafe
and CODE javascript:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
var cw=canvas.width;
var ch=canvas.height;
var fov = 250;
var pts = [{x:32,y:59.45},{x:136,y:66},{x:170,y:99},{x:171,y:114},{x:183,y:125},{x:218,y:144},{x:218,y:165},{x:226,y:193},{x:254,y:195},{x:283,y:195},{x:292,y:202},{x:325,y:213},{x:341,y:134},{x:397,y:245},{x:417,y:548}];
mimicSvg(pts);
function mimicSvg(pts){
// make caps & joins round
//ctx.lineCap='round';
ctx.lineJoin='round';
// draw the outside line with red shadow
ctx.shadowColor='red';
ctx.shadowBlur='2';
ctx.lineWidth='40';
ctx.scale(3,3);
// draw multiple times to darken shadow
drawPolyline(pts);
drawPolyline(pts);
drawPolyline(pts);
// stop shadowing
ctx.shadowColor='transparent';
// refill the outside line with pink
ctx.strokeStyle='yellowgreen';
drawPolyline(pts);
// draw the inside line
ctx.lineWidth=2;
ctx.strokeStyle='blue';
drawPolyline(pts);
}
function drawPolyline(pts){
ctx.beginPath();
ctx.moveTo(pts[0].x,pts[0].y);
for(var i=1;i<pts.length;i++){
ctx.lineTo(pts[i].x,pts[i].y);
}
ctx.stroke();
}
and HTML:
<canvas id="canvas" width=1000 height=800></canvas>
How I can add 3d perspective view of this canvas witout using css3, webGL and similar.
Is it possible to add 3d view on 2d canvas?
If you can draw 2d and do math and combine the 2 you can create 3d image (not easy though)
A quick google let me to: http://www.kevs3d.co.uk/dev/phoria/
And this : Possible to run/create 3d animation without need for webgl in HTML5? (so duplicate)
I have a sprite sheet consisting of 12 frames.
I want to extract each individual frame from it and want to show it in different canvas like below.
what i have tried so far is posted below
//HTML code for define the canvas area .
<body onload="image_render();">
<div id="image_area"> <canvas id="image"></canvas></div>
<script src="sprite_demo.js"></script>
</body>
// javascript to slice the image and assign to the canvas
var canvasImage = new Image();
canvasImage.src = "image/sprite_xxdpi.jpg";
var can= document.getElementById("image");
can.width = 500;
can.height = 300;
function image_render()
{
coin.render();
}
var coin = sprite({
context: can.getContext("2d"),
width: 500,
height: 300,
image: coinImage
});
function sprite (options) {
var that = {};
that.context = options.context;
that.width = options.width;
that.height = options.height;
that.image = options.image;
that.render = function () {
// Draw the animation
that.context.drawImage(
that.image,
0, //X-axis starting position from where slicing begins
0, //y-axis starting position from where slicing begins
that.width, //width of slicing image
that.height,//height of slicing image
0, //X-axis starting position where image will be drawn
0, //y-axis starting position where image will be drawn
150, // width of the resulting image
150); //height of the resulting image
};
return that;
}
I am only able to get a single image ,But I want to get all the images to show in a grid.And also i want to get the image to show any where I want.
I also want to scale down big size images to show in a grid and while taping on it I want to show the original image.
Note: I don't want to animate my frames, I just want to show in grid. There are mostly examples of sprite animation available on internet.
You have the correct version of drawImage to clip individual sprites from the spritesheet, but you must alter the values in drawImage for each sprite.
The "faces" example spritesheet you show appear to have equal sized individual sprites (75px by 75px).
Assuming all your sprites are the same size, you would alter the 2nd & 3rd drawImage parameters which tell canvas the top-left x/y coordinate to begin clipping on the spritesheet.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/tVD2K/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var spriteWidth=75;
var spriteHeight=75;
var spriteCols=4;
var spriteRows=3;
var y=20-sprightHeight;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/spritesheet1.jpg";
function start(){
var canvasY=0;
for(var col=0;col<spriteCols;col++){
for(var row=0;row<spriteRows;row++){
var sourceX=col*spriteWidth;
var sourceY=row*spriteHeight;
// testing: calc a random position to draw this sprite
// on the canvas
var canvasX=Math.random()*150+20;
canvasY+=spriteHeight+5;
// drawImage with changing source and canvas x/y positions
ctx.drawImage(img,
sourceX,sourceY,spriteWidth,spriteHeight,
canvasX,canvasY,spriteWidth,spriteHeight
);
}}
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Draw individual sprites from a spritesheet</h4>
<canvas id="canvas" width=300 height=1000></canvas>
</body>
</html>