Canvas/Photo - getImageData not working - javascript

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'>

Related

Split parts from a regular sized image sheet into separate images with JS

I am trying to display parts from an image sheet into separate images.
There's a way to do it with CSS, as in how Reddit Flairs work on the old version of Reddit.
Below is an image that acts as a sheet. I am going to call it unicode_page_00.png
body {
background-color: rgb(20, 20, 20);
}
<body>
<div>
<div style="background: url(https://i.stack.imgur.com/GxJOx.png); image-rendering: pixelated; width: 64px; height: 64px; background-size: 1024px; background-position: -64px 0px;">
</div>
</div>
<br>
<div>
<img src="https://i.stack.imgur.com/GxJOx.png">
</div>
</body>
https://jsfiddle.net/0ztpr5cq/1/
 
The first part displays an image taken from the image sheet. For this example, the sheet is 256x256 pixels and each character is 16x16 pixels.
I took it and zoomed it in by 4. So the first image shows as 64x64. Then I've shifted the position to display the second character on the sheet from left to right.
And below is the entire image sheet for demonstration.
This is done with CSS. The issue is that you can not save the image the way it was cropped and modified with CSS. Even if it would be made possible with CSS, it would take the entire image sheet and save that instead.
I am trying to display every character on the image sheet as separate images. That you could then freely zoom in with the pixelated effect.
 
The idea that I have is to turn them into Base64 or something and make the modifications there or before. And at the end, display the final result back into an image, as base64 or blob or other. And that all with the help of JavaScript.
But how would it work? What would the actual process be?
A good solution I came up with was this https://jsfiddle.net/1rmya08u/
You would have to use the canvas element. Here's the solution:
<canvas id="canvas" width="64" height="64"></canvas>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false; // For pixelated drawing
var sheet = new Image();
sheet.src = "https://i.stack.imgur.com/GxJOx.png";
sheet.onload = function () {
var sx = 0;
var sy = 0;
var sWidth = 16;
var sHeight = 16;
var dx = 0;
var dy = 0;
var dWidth = 64;
var dHeight = 64;
ctx.drawImage(sheet, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
};
We're taking a 16x16 sample from the image sheet and rendering it at 64x64. For a better understanding of these arguments, take a look at the reference for ctx.drawImage()
And finally, you can get the result as an image with HTMLCanvasElement.toDataURL()

How to convert dataurl back to image and display on canvas

I have 3 canvases. I crop a region from canvas1 and display it on canvas 2 . Then I want to convert canvas 2 image to a URL and to see if can convert that URL back to a image. I want it to be displayed in canvas c4.Any help is appreciated.
// image is drawn here , I want this image to be converted to a dataURL
//then back to image and display it in canvas c4
var c2 = document.getElementById("area_c2");
var ctx = c.getContext("2d");
var ctx2 = c2.getContext("2d");
image_src.width = c2.width;
image_src.height = c2.height;
ctx2.drawImage(image_src, 0, 0,image_src.width, image_src.height);
var c4 = document.getElementById("area_c4");
var ctx4 = c4.getContext("2d");
var dataURL = c2.toDataURL();
var myImg = new Image;
myImg.src = dataURL;
myImg.width = c4.width;
myImg.height = c4.height;
ctx4.drawImage(myImg, 0, 0, image_src.width, image_src.height); //Image //is not displayed here , I want the image to take the size of the canvas
<canvas id ="area_c2" style="width:300px;height:300px;border:3px solid
black;z-index:1" >
</canvas>
<canvas id ="area_c4" style="width:300px;height:300px;border:3px solid
black;z-index:1;background:red">
</canvas>
The reason your solution did not work is because you did not wait for the onload event. Before the onload event the image will not render.
To convert a canvas to a data URL is simple, use the .toDataURL(); method of the canvas element.
Then to convert the data URL back to an canvas image, you would first have to create an Image element and set its source as the dataURL. After getting the image onload event you can draw the image onto the canvas. This could be accomplished as shown:
Assuming the data URL is in a variable called dataURL, the canvas context is in a variable called ctx.
var img = new Image;
img.onload = () => { ctx.drawImage(img, 0, 0); };
img.src = dataURL;
The final solution would go like this:
var cdata2 = c2.toDataURL();
var cimg2 = new Image;
cimg2.onload = () => { ctx4.drawImage(cimg2, 0, 0, c4.width, c4.height); };
PS: You don't have to scale the image object by specifying the width and height, the canvas will do that when you specify the destination width and height.

CreateJs Canvas resize Bitmap

I'm currently working with createJS canvas. I have an image with a predefined size into a Json file and boxes that are link to an eventListener on "mouseout" and "mouseover").
var stage = new createjs.Stage("testCanvas");
createjs.Touch.enable(stage);
stage.enableMouseOver(10);
Bitmap for the image:
var image = new Image();
image.onload = function () {
var img = new createjs.Bitmap(event.target);
stage.addChild(img);
then i draw my boxes (rectangles):
angular.forEach(..., function(value){
var rectGreen = new createjs.Shape();
rectGreen.graphics.beginFill("green")
.drawRect(
value.shapeDimension....,
value.shapeDimension....,
value.shapeDimension....,
value.shapeDimension....
);
rectGreen.alpha = 0.01;
stage.addChild(rectGreen);
my mouse events:
rectGreen.addEventListener("mouseover", function (event) {
var target = event.target;
target.alpha = 0.35;
stage.update();
});
rectGreen.addEventListener("mouseout", function (event) {
var target = event.target;
target.alpha = 0.01;
stage.update();
});
So, it's working but I have some difficulties with the canvas/image size.
If I don't set any width/heigth to the canvas Html, it results in a
300*150 canvas but the image is not resized so it displays only a
slight piece of the real image.
If i set width and height in the canvas html, (real size is 1700*1133), the image appears only 842*561 and the canvas takes place).
I tried different solution with Setting DIV width and height in JavaScript
but nothing enabled me to set my image correctly, and responsive so that the size of my rectangles adpt to the screen size of the image.
In order to dynamically resize the Canvas to the exact size of the image, you can do this:
//to get a variable reference to the canvas
var canvas = document.getElementById("testCanvas");
//supposing the Bitmap is the variable named 'img'
canvas.width = img.image.width;
canvas.height = img.image.height;
If you have more elements on the screen and the total size is bigger than the image itself, you can add everything on the screen in a container, and then scale the container itself to fit the canvas perfectly, like this:
var container = new createjs.Container();
container.addChild(img, [your other rectangle elements here]);
stage.addChild(container);
//will downscale or upscale the container to fit the canvas
container.scaleX = container.scaleY = canvas.width / img.image.width;

On Load event for getImageData

Hello I have this script that checks for transparent pixels and non transparent pixels. Now i made it so the result is coming from 100px by 100px rectangle on mouse over:
var data = ctx.getImageData(100,100, canvas.width, canvas.height).data;
And right now it shows on mouse of over the result of Opague area and Transparent area.
I would like somehow to visualise this rectangle on load with a grid overlaying the image and the oppaque boxes and transparent one to have different colours like oppaque is green transparent is red. I need probably on load function? But how should it look?
I am stuck here and need someone to direct me in the right position
and here is my current progress:
https://jsfiddle.net/kdichev/Lnp3k5re/
Since you probably want the game console to still show, you can draw your 100x100 boxes with a reduced alpha (globalAlpha).
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 boxWidth=100;
var boxHeight=100;
var boxRows=Math.ceil(865/boxHeight);
var boxCols=Math.ceil(1152/boxWidth);
var boxes=new Array(boxRows*boxCols);
for(var i=0;i<boxes.length;i++){boxes[i]=false;}
var img=new Image();
img.onload=start;
img.crossOrigin='anonymous';
img.src="http://i.imgur.com/RrHayx8.png?1";
function start(){
ctx.drawImage(img,0,0);
var d=ctx.getImageData(0,0,cw,ch).data;
for(var i=0;i<d.length;i+=4){
if(d[i+3]>200){
var px=parseInt(i/4);
var pixelY=parseInt(px/cw);
var pixelX=px-pixelY*cw;
var boxX=parseInt(pixelX/boxWidth);
var boxY=parseInt(pixelY/boxHeight);
boxes[boxY*boxCols+boxX]=true;
}
}
ctx.globalAlpha=0.25;
ctx.fillStyle='red';
for(var i=0;i<boxes.length;i++){
var y=parseInt(i/boxCols);
var x=i-y*boxCols;
if(boxes[i]==true){
ctx.fillRect(x*boxWidth,y*boxHeight,boxWidth,boxHeight);
}
}
ctx.globalAlpha=1.00;
ctx.fillStyle='black';
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=1152 height=865></canvas>

Javascript - Putting ImageData Onto a Canvas Element - CanvasRenderingContext2D

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">

Categories

Resources