Modify pixels in remote image in plain html/js - javascript

I am new to Javascript, I would like to modify the brightness of any remote image given in an input form.
I have tried to use Canvas but I got this issue.
I want the following code to work directly via "file:///test.html". How can I simply achieve that ?
<html>
<head>
<script type="text/javascript">
function readImg() {
img = new Image();
url = document.getElementById('url').value;
document.getElementById('showImg').innerHTML='<img src="'+ url +'" />';
img.src = url;
canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
img.crossOrigin = "Anonymous";
imgData = ctx.getImageData(0,0,canvas.width,canvas.height); // not working !!
brightness(imgData);
}
function brightness(imgData) {
var dataimg = imgData.data;
for (var i = 0; i < dataimg.size; i += 4 ) {
dataimg[i] += 10;
dataimg[i+1] += 10;
dataimg[i+2] += 10;
}
}
</script>
</head>
<body>
<input id="url" type="text" onChange="readImg()"></input>
<div id='showImg'></div>
</body>
</html>

You have to give Chrome explicit access to local files from local html files.
You have to run Chrome with --allow-file-access-from-files flag.
"C:\PathTo\Chrome.exe" --allow-file-access-from-files
You can find more info about it here as it was already discussed:
https://stackoverflow.com/a/18587027/4103991
#EDIT://
Execute commands related to img element inside img.onload event handler.
Your code should look somewhat like that:
<html>
<head>
<script type="text/javascript">
function readImg() {
img = new Image();
url = document.getElementById('url').value;
document.getElementById('showImg').innerHTML='<img src="'+ url +'" />';
canvas = document.createElement("canvas");
img.onload = function(){
canvas.width = img.width;
canvas.height = img.height;
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
brightness(imgData);
}
img.src = url;
img.crossOrigin = "Anonymous";
}
function brightness(imgData) {
var dataimg = imgData.data;
for (var i = 0; i < dataimg.size; i += 4 ) {
dataimg[i] += 10;
dataimg[i+1] += 10;
dataimg[i+2] += 10;
}
}
</script>
</head>
<body>
<input id="url" type="text" onChange="readImg()"></input>
<div id='showImg'></div>
</body>
</html>

Related

getImageData returns white image

I need to read the image data from an image object in javascript.
But my code returns always a blank array (set to 255)
<html>
<header>
</header>
<body>
<input type="file" id="imgfile" onchange="testImageData(event);" />
<canvas id="canvas1" width="640" height="480"></canvas>
<script src="./../scripts/cam.js" ></script>
</body>
</html>
Here is the script
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');
function getImageData(image){
/*
returns Uint8ClampedArray object
takes an image obj
*/
var canvas = document.createElement("canvas");
canvas.height = image.height;
canvas.width = image.width;
var ctx = canvas.getContext("2d");
ctx.width = image.width;
ctx.height = image.height;
ctx.drawImage(image,0,0);
return ctx.getImageData(0, 0, ctx.width, ctx.height);
}
function testImageData(event){
var selectedFile = event.target.files[0];
var reader = new FileReader();
var img = new Image();
reader.onload = function(event) {
console.log('onload');
img.src = event.target.result;
img.onload = function(){
context1.drawImage(img, 0,0, img.width, img.height);
var imgData = getImageData(img);
// console.log(imgData);
var data = imgData.data;
for(var i = 0; i<data.length;i+=4){
console.log(data[i],data[i+1],data[i+2],data[i+3]);
}
}
};
In my understanding, the console.log should return me the data in RGBA.
But I'm just getting 255.
console.log output
EDIT:
Okay I found a work around but I don't understand why this is working.
Instead using getImageData, I get the data directly from the drawn context1.
function testImageData(event){
var selectedFile = event.target.files[0];
var reader = new FileReader();
var img = new Image();
reader.onload = function(event) {
console.log('onload');
img.src = event.target.result;
img.onload = function(){
context1.drawImage(img, 0,0, img.width, img.height);
var imgData = context1.getImageData(0,0,img.width,img.height);
var data = imgData.data;
for(var i = 0; i<data.length;i+=4){
console.log(data[i],data[i+1],data[i+2],data[i+3]);
}
}
};
So the problem must lie in creating a new canvas.
You should wait for the image to load img.onload you are waiting for the readers onload event...
you also forget to read the file... missed reader.readAsDataURL
but you don't need the filereader.
window.URL = window.URL || webkitURL
var img = new Image();
img.src = URL.createObjectURL(file)
img.onload = function(){
// put your image on the canvas
}

HTML Canvas Images - Drawing multi canvas image in a page

i have a problem with canvas.
i can draw a canvas with single image, but i can't draw each canvas with image separate.
- if data just have one image it's working fine, but data have multiple image it's not working
can you help me ?
<script>
var h_notepad = 500;
var w_notepad = 737;
var data = [
{dataImageURL: "1_sat_1.png"},
{dataImageURL: "1_sat_2.png"},
{dataImageURL: "1_sat_3.png"},
{dataImageURL: "1_sat_4.png"}
];
for(var i = 0; i < data.length ; i++){
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
canvas.width = w_notepad;
canvas.height = h_notepad;
img.crossOrigin = 'anonymous';
img.width = w_notepad;
img.height = h_notepad;
console.log(img);
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
img.src = data[i].dataImageURL;
$('body').append(canvas);
}
</script>
<html>
<head>
<meta charset="utf-8">
<title>DRAWING</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<meta charset="utf-8">
</head>
<body>
</body>
</html>
I guess you only get the last one.
It's a closure problem.
When the load event fires, img and ctx only refer to the last ones created.
So you draw data.length time on the same canvas.
To avoid it, you can use this and wrap the canvas creation in the onload handler:
var imgs = ['http://lorempixel.com/200/300/', 'http://lorempixel.com/500/300/', 'http://lorempixel.com/200/100/'];
for (var i = 0; i < imgs.length; i++) {
var img = new Image();
var width = 500;
var height = 300;
img.onload = function() {
var c = document.createElement('canvas');
c.width = width;
c.height = height;
document.body.appendChild(c);
var ctx = c.getContext('2d');
ctx.drawImage(this, 0,0, width, height);
};
img.src = imgs[i];
}
Problem is that onload is asynchronous. So all your code runs before any of onload functions will be called. That is why your function
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
uses the latest ctx and renders all images in this context.
What you can do is cover this asynchronous call with a synchronous function scope:
(function(ctx, img, w_notepad, h_notepad) {
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
})(ctx, img, w_notepad, h_notepad);
This isolates the variables and keeps there values until you receive the image.

HTML5 canvas javascript: toDataURL generates empty dataurl

I have the following form:
<form style="margin:5px;" id="submit-image" method="post" action="/site/recognize" enctype="multipart/form-data">
<input name="photo" id="upload-image" type="file" accept="image/*;capture=camera" >
<input name="photo-resized" id="upload-image-resized" type="hidden">
</form>
Then I have the following javascript:
<script>
var myInput = document.getElementById('upload-image');
function sendPic() {
//var file = myInput.files[0];
// functionality to rezise image BEFORE upload needs to go here
// from an input element
var filesToUpload = document.getElementById("upload-image").files;
var file = filesToUpload[0];
console.log(file);
var canvas = document.createElement('canvas');
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);
console.log(img); // This still outputs a proper image
var MAX_WIDTH = 1000;
var MAX_HEIGHT = 1000;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
//var ctx = canvas.getContext("2d");
var dataurl;
img.onload = function () {
canvas.getContext("2d").drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL();
console.log(dataurl); // Somehow this STILL outputs an empty dataurl, need to find out why
};
document.getElementById('upload-image-resized').value= dataurl;
document.getElementById('submit-image').submit();
var loader = document.getElementsByClassName('ui-loader');
loader[0].style.display = "block";
loader[0].style.opacity = 0.7;
}
myInput.addEventListener('change', sendPic, false);
</script>
As you can see there I have several console.log() statements to help me understand where things are going wrong. I've put a comment there saying "// Somehow this outputs an empty dataurl, need to find out why". That's the point where I'm lost.
I don't understand why the dataurl variable is empty. It just contains "data: , " or something like that.
Any help appreciated.

Dynamically adding image source

I have problems regarding printing an image and adding the image source. I have to do it dynamically. I need a random number from 0 to 9 generated and use that number to show that image. I have 10 images
(number0.jpg, number1.jpg, number2.jpg…).
The code is this:
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="258" height="187"></canvas>
<script>
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
var whichImg;
var randNum;
var img = new Image();
img.onload = function(){
randNum = Math.floor(Math.random() * 10);
can.width = img.width;
can.height = img.height;
whichImg="number" + randNum + ".jpg" ;
ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = whichImg; //having problems with this row
</script>
</body>
</html>
The last line doesn’t work. If I call that as is
img.src = “number1.jpg”,
it shows the image. This way it doesn’t. What can I do to show the image?
Thanks
You need to populate whichImg right after initializing it:
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
var whichImg;
var randNum;
randNum = Math.floor(Math.random() * 10);
whichImg="number" + randNum + ".jpg" ;
var img = new Image();
img.onload = function(){
randNum = Math.floor(Math.random() * 10);
can.width = img.width;
can.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = whichImg; //having problems with this row

Array of images in canvas not working

Could someone please help to make the below code work. also is there any other way to display the images without using onload?
<head id="Head1" runat="server">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title></title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var c = document.getElementById("myCanvas");
c.width = $(document).width();
c.height = $(document).height();
var ctx = c.getContext("2d");
var imgArray = new Array();
imgArray[0] = new Image();
imgArray[1] = new Image();
imgArray[0].src = "1.png";
imgArray[1].src = "2.png";
var x = 30;
var y = 40;
for (var i = 0; i < 2; i++) {
imgArray[i].onload = function () {
ctx.drawImage(imgArray[i], x, y);
}
x = x + 20;
}
});
</script>
</head>
I want images to be displayed on canvas using array. it works fine if i use array without for loop. please help in fixing the issue.
<body style="margin:0; height:100%; width:100%; overflow:hidden;" >
<canvas id="myCanvas" style="display:block; " >
Your browser does not support the HTML5 canvas tag.
</canvas>
</body>
</html>
It's bad practice to define a function within a loop. Try defining it outside of the loop with a named function. Also it'd probably be better to set the src of the img after the onload function is attached. Something like:
$(document).ready(function () {
var c = document.getElementById("myCanvas");
c.width = $(document).width();
c.height = $(document).height();
var ctx = c.getContext("2d");
var imgArray = new Array();
imgArray[0] = new Image();
imgArray[1] = new Image();
var x = 30;
var y = 40;
function onImageLoad() {
ctx.drawImage(this, x, y);
x = x + 20;
}
for (var i = 0; i < 2; i++) {
imgArray[i].onload = onImageLoad;
}
imgArray[0].src = "1.png";
imgArray[1].src = "2.png";
});
If you must have the loop in the function (which you don't), you would need to wrap it within a closure so that each image gets it's own onload function instead of defining the same function which is what happens in your case.
Something similar to the following would probably work:
for (var i = 0; i < 2; i++) {
imgArray[i].onload = (function(idx) {
return function() {
ctx.drawImage(imgArray[idx], x, y);
x = x + 20;
}
})(i)
}
This is how you could do it:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
// Source
var imgArray = new Array();
imgArray[0] = new Image();
imgArray[1] = new Image();
imgArray[0].src = "http://png-2.findicons.com/files/icons/963/very_emotional_emoticons/64/64_18.png";
imgArray[1].src = "http://png-3.findicons.com/files/icons/963/very_emotional_emoticons/64/64_30.png";
// Draw Images
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var startX = 0;
for (var i = 0; i < imgArray.length; i++) {
ctx.drawImage(imgArray[i], startX, 0);
startX += 74;
}
});
</script>
<canvas id="myCanvas" style="display:block;">
Your browser does not support the HTML5 canvas tag.
</canvas>
Outputs:
P.S. The images are 64x64 (width x height). So to draw them next to each other with 10px spacing, I add 10 to 64 (width), hence I do startX += 74; and the images draw like that.
You should be able to modify this code to meet your own needs.

Categories

Resources