HTML Template
<html>
<form>
Image to resize: <input type="file" id="getImage"><br><br>
</form>
<img src="." id="image">
<html>
Java Script
<script>
document.getElementById('getImage').onchange = imageResize(60,60);
var imageResize = function (Width, Height) {
//-- GET FILE FROM FORM
var selectedFile = this.files[0];
//-- GET BASE 64
File.prototype.convertToBase64 = function (callback) {
var reader = new FileReader();
reader.onload = function (e) {
callback(e.target.result);
};
reader.readAsDataURL(this);
};
selectedFile.convertToBase64(function (base64) {
//-- MAKE IMAGE
var img = document.createElement('img');
img.src = base64;
//-- PUSH INTO CANVAS
img.onload = function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = Width; // If i change Width & Height to numbers it works!!
canvas.height = Height;
ctx.drawImage(this, 0, 0, Width, Height);
//-- SHOW IMAGE ON PAGE
document.getElementById("image").src = canvas.toDataURL();
};
});
};
</script>
Just above I'm setting the canvas width and height to 60x60 but i cant use the variables I've passed in without getting an error, and I cant figure out why. the error is
Uncaught TypeError: Cannot read property 'files' of undefined
here you should attach the event listener to input element.but instead you attached to img element
and you also want to access the files inside the event listener,so you should pass this reference to the listener
and the way you are attaching the event is not right.
your are doing this document.getElementById('getImage').onchange = imageResize(60,60);
this is wrong as it will execute the imageResize() and assigns the result to on change event.
actually you should attach reference of the function like below
document.getElementById('getImage').onchange = imageResize;
i edited your code a little.
try this snippet.
var imageResize = function(Width, Height, files) {
var selectedFile = files[0];
File.prototype.convertToBase64 = function(callback) {
var reader = new FileReader();
reader.onload = function(e) {
callback(e.target.result);
};
reader.readAsDataURL(this);
};
selectedFile.convertToBase64(function(base64) {
var img = document.createElement('img');
img.src = base64;
img.onload = function() {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = Width;
canvas.height = Height;
ctx.drawImage(this, 0, 0, Width, Height);
document.getElementById("image").src = canvas.toDataURL();
};
});
};
var file = document.getElementById('getImage');
file.onchange = function() {
imageResize(160, 160, this.files);
};
<form>
Image to resize:
<input type="file" id="getImage">
<br>
<br>
</form>
<img src="." id="image">
Related
PS: Is it not a research kind of question! I have been trying to do this from very long time.
I am trying to make web based an image editor where user can select multiple cropping area and after selection save/download all the image area. like below.
As of now I discovered two libraries
1.Cropper.JS where is only single selection feature is available.
2.Jcrop where only single selection area restrictions.
I am currently using cropper.Js but it seems impossible for me to make multiple selection cropping.
Any help is much appreciated.if any other method/library available in JavaScript, Angular or PHP or reactJS for multiple image area selection and crop and download in one go as in the image below.
As per #Keyhan Answer I am Updating my Jcrop library Code
<div style="padding:0 5%;">
<img id="target" src="https://d3o1694hluedf9.cloudfront.net/market-750.jpg">
</div>
<button id="save">Crop it!</button>
<link rel="stylesheet" href="https://unpkg.com/jcrop/dist/jcrop.css">
<script src="https://unpkg.com/jcrop"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
JavaScript
<script>
setImage();
var jcp;
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img, { multi: true });
});
// to fix security issue when trying to convert to Data URI
function setImage() {
document.getElementById('target').setAttribute('crossOrigin', 'anonymous');
document.getElementById('target').src = 'https://d3o1694hluedf9.cloudfront.net/market-750.jpg';
}
var link = document.getElementById('save');
link.onclick = function () {
//we check if at least one crop is available
if (jcp.active) {
var i = 0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for (area of jcp.crops) {
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width', area.pos.w);
canvas.setAttribute('height', area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area' + i + '.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
</script>
I tried to explain the code with comments:
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img,{multi:true});
});
//assuming you have a button with id="save" for exporting cropped areas
var link=document.getElementById('save');
link.onclick = function(){
//we check if at least one crop is available
if(jcp.active){
var i=0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for(area of jcp.crops){
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
EDIT: As you commented it would be nicer if we have local image loader, we can add a file input to our html
<img id="target" />
<br/>
<input type="file" id="imageLoader" name="imageLoader"/><!-- add this for file picker -->
<button id="save">save</button>
and a function to our js to handle it
var jcp;
var save=document.getElementById('save');
var imageLoader = document.getElementById('imageLoader');
var img = document.getElementById("target");
imageLoader.onchange=function handleImage(e){//handling our image picker <input>:
var reader = new FileReader();
reader.onload = function(event){
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
save.onclick = function(){
if(jcp&&jcp.active){
var i=0;
for(area of jcp.crops){
i++;
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(img, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
Jcrop.load('target').then(img => {
jcp = Jcrop.attach(img,{multi:true});
});
Yes, #keyhan was right <input type="file"> is another question, but still, I am giving you an idea of how to implement Kayhan's code above.
<div>
<input type="file" id="image-input" accept="image/*">
<!-- img id name should be "target" as it is also using by Jcrop -->
<img id="target"></img>
</div>
and Now you can put below JavaScript Code just above setImage()
<script>
let imgInput = document.getElementById('image-input');
imgInput.addEventListener('change', function (e) {
if (e.target.files) {
let imageFile = e.target.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("img");
img.onload = function (event) {
var MAX_WIDTH = 1600;
var MAX_HEIGHT = 800;
var width = img.width;
var height = img.height;
// Change the resizing logic
if (width > height) {
if (width > MAX_WIDTH) {
height = height * (MAX_WIDTH / width);
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width = width * (MAX_HEIGHT / height);
height = MAX_HEIGHT;
}
}
// Dynamically create a canvas element
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
// var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Actual resizing
ctx.drawImage(img, 0, 0, width, height);
// Show resized image in preview element
var dataurl = canvas.toDataURL(imageFile.type);
document.getElementById("target").src = dataurl;
}
img.src = e.target.result;
}
reader.readAsDataURL(imageFile);
}
});
</script>
Image is getting created in full original size, even last two arguments 150, 150 are height and width context.drawImage(img, 0, 0, 150, 150); in the code below:
function (file) { //uploaded files are always images
var reader = new FileReader(); //FileReader for uploading files from local stroge.
reader.onload = function () {
var links = document.createElement('a'); //link when image is clicked
var img = document.createElement('img');
img.src = reader.result; //src = url from uploaded file
img.className = 'images'; //css -> .images { margin-top: 30px; padding: 30px; }
img.onload = function () { //repaint image to 150 - 150 size with canvas, because setting width and height on image itself would just resize the image but I want to create new image with new size
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, 150, 150) //draw image with canvas
}
links.href = reader.result; // url from local storage needed when image is clicked -
links.target = "_blank"; // open new blank page with original image
links.appendChild(img); // image is appended to <a>
document.body.appendChild(links); // <a> is appended to body, that body contains image thumbnail with a link linked to the image source
}
if (file) {
reader.readAsDataURL(file); // read uploaded files url
}
}
img.onload does not making any sense here. result is the same even when I remove it.
You are not drawing back the cropped image to your <img> tag... you will have to create two image Objects, let's call the first originalImage, and the second one croppedImage.
The one you will append to the document is croppedImageand originalImage will just stay in the cache.
When originalImage has loaded, you will paint it to a canvas, and then set croppedImage to the result of the canvas' toDataURL() method.
var read = function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function() {
var links = document.createElement('a');
// this will be the appended image
var croppedImage = new Image();
// do your DOM stuff
croppedImage.className = 'images';
links.href = reader.result;
links.target = "_blank";
links.appendChild(croppedImage);
document.body.appendChild(links);
// create a buffer image object
var originalImage = new Image();
// set its load handler
originalImage.onload = function() {
// create a canvas
var canvas = document.createElement('canvas');
// set canvas width/height
canvas.width = canvas.height = 150;
var context = canvas.getContext('2d');
// draw the buffered image to the canvas at required dimension
context.drawImage(originalImage, 0, 0, 150, 150);
// set the appended to doc image's src to the result of the cropping operation
croppedImage.src = canvas.toDataURL();
}
originalImage.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
}
};
upload.onchange = read;
.images {
margin-top: 30px;
padding: 30px;
}
<input type="file" id="upload" />
You could also have used only a single image object, but this would have required to reset the onload event in the onload event, to avoid an infinite loop, which is a little bit less clear :
var read = function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function() {
var links = document.createElement('a');
var img = new Image();
img.className = 'images';
links.href = reader.result;
links.target = "_blank";
links.appendChild(img);
document.body.appendChild(links);
img.onload = function() {
//reset the onload event so it does fire in a loop
img.onload = function(){return;};
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 150;
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0, 150, 150);
this.src = canvas.toDataURL();
}
img.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
}
};
upload.onchange = read;
.images {
margin-top: 30px;
padding: 30px;
}
<input type="file" id="upload" />
var reader = new FileReader();
reader.onload = function () {
var links = document.createElement('a');
var img = new Image();
img.src = reader.result;
img.className = 'images';
img.onload = function () {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0, 150, 150);
this.src = canvas.toDataURL(); // convert the canvas back to the image
links.appendChild(this); // append the updated image to the document
}
links.href = reader.result;
links.target = "_blank";
document.body.appendChild(links);
}
if (file) {
reader.readAsDataURL(file); //reads the data as a URL
}
I'm trying to implement a feature in our project which will trigger the mobile camera when pressing a capture button from mobile browser, it will append the captured image as canvas to html page, but if we capture more than 2 image, the browser get's restart automatically and showing memory low warning. Please let me know is there any way to optimize the canvas size?.
Note:
I have tested only in mobile chrome.
I'm attaching the sample code below
html code:
<input type="file" id="camera" accept="image/*" capture>
<div id="MediaOutput"></div>
javascript:
var storedMediaList=[];
var mobile_picture = document.querySelector("#camera");
mobile_picture.onchange = function () {
var file = mobile_picture.files[0];
storedMediaList.push({id:(Math.floor(Math.random()*90000)+10000),data:file});
drawImage();
};
function drawImage()
{
$(".rc").remove().empty();
$("#MediaOutput").html("");
$("#MediaOutput").html("<div class='mediaWrapper'></div>");
storedMediaList.forEach(function(row,index,array)
{
$(".mediaWrapper").append("<div style='float:left;' class='ir' id='c"+row.id+"' class='pic'><div media-id="+row.id+" class='close-image' id='close-image' style='width:24px;background:url(images/close.png) no-repeat;height:25px;cursor:pointer;'></div><canvas id='cv"+row.id+"'></canvas> </div>");
var reader = new FileReader();
reader.onload = function (e) {
var dataURL = e.target.result,
c = document.querySelector("#cv"+row.id),
ctx = c.getContext('2d'),
img = new Image();
img.onload = function() {
c.width = img.width;
c.height = img.height;
ctx.drawImage(img, 0, 0);
};
img.src = dataURL;
};
reader.readAsDataURL(row.data);
});
function resizeImage(img, percentage) {
var coeff = percentage/100,
width = $(img).width(),
height = $(img).height();
return {"width": width*coeff, "height": height*coeff}
}
$('.ir canvas').each(function(){
var newDimensions = resizeImage( this, 70);
this.style.width = newDimensions.width + "px";
this.style.height = newDimensions.height + "px";
});
var width = 0;
$('#MediaOutput .mediaWrapper div').each(function() {
width += $(this).outerWidth( true );
});
$('#MediaOutput .mediaWrapper').css('width', width + "px");
}
Thanks in Advance!!
I am able to uploading the image over the canvas html control but what is the problem is when I uploading the image at first time, that image is not uploading in canvas html and again if I select that same image then that image is uploading in canvas very well.That means, in my scenario if user first upload the image over the canvas then they should upload the image twice but what I want when user first upload the image then that image should be display over the canvas.Please check the below script and html5 tag whether I am doing some mistake please suggest me how to resolve that kind of issue. Thanks in advance.
<!--HTML5 tags Implementation-->
<input type="file" id="imageLoader" name="imageLoader" onchange="readURL(this);"/>
<canvas id="imageCanvas"></canvas>
<!--JavaScript Implementation-->
<script type="text/javascript">
var imageLoader = '';
var canvas = '';
var ctx = '';
function readURL(input) {
//alert('test');
imageLoader = document.getElementById('imageLoader');
//imageLoader.addEventListener('change', handleImage,false);
imageLoader.addEventListener('change', this.handleImage.bind(this), false);
canvas = document.getElementById('imageCanvas');
ctx = canvas.getContext('2d');
};
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
var img = new Image();
console.log(img);
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
};
</script>
I found the solution about this issue.Actually, I was implementing the javascript and it calls change event is twice which creates the problem when user upload the image over the canvas at first time.So, I am familiar with jquery so I was implementing the jquery and solve this issue please check the below code thoroughly then you will understood.
<input type="file" id="imageLoader" name="imageLoader" />
<canvas id="imageCanvas"></canvas>
<!--JQuery Implementation-->
<script type="text/javascript>
$(document).ready(function () {
$('#imageLoader').on('change', function (e) {
imageLoader = document.getElementById('imageLoader');
canvas = document.getElementById('imageCanvas');
ctx = canvas.getContext('2d');
handleImage(e);
})
});
function handleImage(e) {
alert('check');
var reader = new FileReader();
reader.onload = function (event) {
var img = new Image();
//console.log(img);
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
};
</script>
I would like to draw an image opened with the HTML5 File API on a canvas.
In the handleFiles(e) method, I can access the File with e.target.files[0] but I can't draw that image directly using drawImage. How do I draw an image from the File API on HTML5 canvas?
Here is the code I have used:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script>
window.onload = function() {
var input = document.getElementById('input');
input.addEventListener('change', handleFiles);
}
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.drawImage(e.target.files[0], 20,20);
alert('the image is drawn');
}
</script>
</head>
<body>
<h1>Test</h1>
<input type="file" id="input"/>
<canvas width="400" height="300" id="canvas"/>
</body>
</html>
You have a File instance which is not an image.
To get an image, use new Image(). The src needs to be an URL referencing to the selected File. You can use URL.createObjectURL to get an URL referencing to a Blob (a File is also a Blob): http://jsfiddle.net/t7mv6/86/.
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image;
img.onload = function() {
ctx.drawImage(img, 20,20);
alert('the image is drawn');
}
img.src = URL.createObjectURL(e.target.files[0]);
Note: be sure to revoke the object url when you are done with it otherwise you'll leak memory. If you're not doing anything too crazy, you can just stick a URL.revokeObjectURL(img.src) in the img.onload function.
References:
https://developer.mozilla.org/en/DOM/File
http://html5demos.com/file-api
Live Example
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 20, 20);
}
img.src = url;
}
window.URL.createObjectUrldocs
You could also use the FileReader instead to create the object URL.
The FileReader has slightly better browser support.
The FileReader approach works in FF6 / Chrome. I'm not certain whether setting Img.src to a Blob is valid and cross-browser though.
Creating object urls is the correct way to do it.
Edit:
As mentioned in the commment window.URL support whilst offline seems unavailable in FF6/Chrome.
Here is a complete example (Fiddle) using FileReader (which has better browser support as mentioned by Raynos). In this example I also scale Canvas to fit the image.
In real life example you might scale the image to some maximum so that your form will not blow up ;-). Here is an example with scaling (Fiddle).
var URL = window.webkitURL || window.URL;
window.onload = function() {
var input = document.getElementById('input');
input.addEventListener('change', handleFiles, false);
// set original canvas dimensions as max
var canvas = document.getElementById('canvas');
canvas.dataMaxWidth = canvas.width;
canvas.dataMaxHeight = canvas.height;
}
function handleFiles(e) {
var ctx = document.getElementById('canvas').getContext('2d');
var reader = new FileReader();
var file = e.target.files[0];
// load to image to get it's width/height
var img = new Image();
img.onload = function() {
// setup scaled dimensions
var scaled = getScaledDim(img, ctx.canvas.dataMaxWidth, ctx.canvas.dataMaxHeight);
// scale canvas to image
ctx.canvas.width = scaled.width;
ctx.canvas.height = scaled.height;
// draw image
ctx.drawImage(img, 0, 0
, ctx.canvas.width, ctx.canvas.height
);
}
// this is to setup loading the image
reader.onloadend = function () {
img.src = reader.result;
}
// this is to read the file
reader.readAsDataURL(file);
}
// returns scaled dimensions object
function getScaledDim(img, maxWidth, maxHeight) {
var scaled = {
ratio: img.width / img.height,
width: img.width,
height: img.height
}
if (scaled.width > maxWidth) {
scaled.width = maxWidth;
scaled.height = scaled.width / scaled.ratio;
}
if (scaled.height > maxHeight) {
scaled.height = maxHeight;
scaled.width = scaled.height / scaled.ratio;
}
return scaled;
}
canvas {
border:1px solid black
}
<input type="file" id="input"/>
<div>
<canvas width="400" height="300" id="canvas"/>
</div>