How can you let a user change a picture in html? - html

I have an img src="example.jpg", and I also have an input type="file". I would like to know if there was a way to make the input type="file" change the img to whatever the user chooses off of his/her computer.

Here is a basic example with what you're asking, although it doesn't handle persistence, login sessions, or anything else you'll need for this to work in a production environment.
document.addEventListener('DOMContentLoaded', init);
function init() {
var input = document.querySelector('input');
var reader = new FileReader();
// When the FileReader "load" event fires, update the image.
reader.onload = function (e) {
document.getElementById("image").src = e.target.result;
};
// Listen for when the input changes.
input.addEventListener('change', onInputChange)
function onInputChange(e) {
reader.readAsDataURL(this.files[0]);
}
}
<img src="//placehold.it/200x200" id="image" height="200">
<input type="file">
Sidenote: Welcome to StackOverflow. You're getting downvotes as you're not including anything you've tried. SO is a place to get help with existing code, not to do research or write it for you.

Related

How to check for changes in file after it has been selected in a <input type="file">?

To upload I file in Angular, I am doing this:
<input type="file" (change)="onFileSelected($event.target.files)"/>
<button (click)="onStartUpload()"</button>
public onFileSelected(files: File[]) {
this.file = files[0];
}
public onStartUpload() {
// Upload the file
}
This works perfectly. But when I select a file, then change its content and save it, and then upload it, my backend response is this:
Unexpected end of Stream, the content may have already been read by
another component.
This only happens with Firefox. It works fine in Chrome.
Update: With Chrome's latest update, it does not send the request
anymore.
How can I check if the file has been changed after I selected it in the browser?
If you use an instance of the FileReader object, you can take advantage of the fact that it wont load a file that's been altered after having been selected. In order to upload the file successfully, it must remain the same as it was when it was chosen.
Here's a short example that will demonstrate. Tested on the current iteration of Chrome x64 under windows.
window.addEventListener('load', onLoaded, false);
function onLoaded(evt) {
document.querySelector('button').addEventListener('click', onBtnClicked, false);
}
function onBtnClicked(evt) {
let fileToUpload = document.querySelector('input').files[0];
const fileReader = new FileReader();
fileReader.onload = fileLoaded;
fileReader.onerror = fileError;
fileReader.readAsText(fileToUpload);
// fileReader.readAsArrayBuffer(fileToUpload);
// fileReader.readAsBinaryString(fileToUpload);
// fileReader.readAsDataURL(fileToUpload);
function fileLoaded(evt) {
let fileToUpload = evt.target.result;
}
function fileError(evt) {
console.log('Error loading file');
console.log(evt.target.error);
}
}
<input type='file' /><br>
<button>Go</button>

How to process image input to Angular app in an <img> element?

I am trying to create an Angular PWA that is able to take a picture, and after taking it to display it in an img element.
The first step I succeeded in: I now have an FAB button that opens the camera viewfinder (using the html input tag) with this small piece of code:
const element: HTMLElement = document.getElementById('imageCapturer') as HTMLElement;
element.click();
This simulates a click on the following HTML element:
<input type="file" accept="image/*" capture="environment" id="imageCapturer"">
However, after taking a picture I then want to use the image to render it in an img element (and also sending the image to a database with an API call)
I have tried multiple solutions including trying to add the file.name as src to the img element, and trying to create a new img HTML element with an attribute that uses the file. But I am still unable to process the image to be used in the img tag. Can somebody explain to me what the proper way to process the file is to be able to do this?
Cheers!
I solved this problem in the following way:
First, I changed the HTML to this:
<input type="file" accept="image/*" id="imageCapturer" style="display: none;" (change)="useImage($event)">
<img *ngIf="URL" [src]="URL" id="imageViewer">
Then the function useImage looks like this:
useImage(event) {
if (event.target.files && event.target.files[0]) {
const reader = new FileReader();
reader.readAsDataURL(event.target.files[0]); // Read file as data url
reader.onloadend = (e) => { // function call once readAsDataUrl is completed
this.URL = e.target['result']; // Set image in element
this._changeDetection.markForCheck(); // Is called because ChangeDetection is set to onPush
};
}
}
Now whenever a new image is captured or selected it is updated in the view
You can use event change of input file.
This example:
$('#imageCapturer').on('change', function () {
var input = $(this)[0];
if (input.files && input.files[0]) {
var fileName= input.files[0].name;
var reader = new FileReader();
reader.onload = function (e) {
var buffer = e.target.result;
var fileSize = input.files[0].size / 1024 / 1024; // in MB
// SET IMG DISPLAY
$('#image-display').attr('src', buffer).css({
'max-height': '170px',
'max-width': '170px',
};
reader.readAsDataURL(input.files[0]);
}
});
Note: You add more attribute [enctype="multipart/form-data"] in tag form when sumbit form it will send file byte[].
<form id="process_form" method="POST" enctype="multipart/form-data" autocomplete="off" role="form" data-parsley-focus="none">

Setting local image as EaselJS background

I am building an EaselJS app, and I want the user to be able to select an image from their hard drive to be the background for the app. Once they are done interacting with the app and choose to submit I want to upload the image, but not before then. Is there a way I can do this? I am using Rails if that makes any difference.
You can use the method readAsDataURL from Filereader,then pass the result to an Image object and finally pass that image as parameter of a new easeljs.Bitmap object.
function previewFile(){
var file = input.files[0];
var reader = new FileReader();
reader.onloadend = function () {
image.src = reader.result;
var bitmap = new createjs.Bitmap(image);
stage.addChild(bitmap);
}
if (file) {
reader.readAsDataURL(file);
} else {
alert("fail");
}
}
I created a fiddle that does something like that:
https://jsfiddle.net/vampaynani/b5maj7nd/

html5 drag and drop file uploads

I have a bunch of file uploads on my website and I was looking into making them into drag and drop fields. However I seem to be having an issue with them.
Is there any way to accomplish a drag and drop system without the use of javascript or plugins? I'm trying to make this as light as possible and with the least amount of code.
I have looked at several different methods of doing this such as http://html5demos.com/dnd-upload but they all include javascript.
At the moment I just have regular inputs that look like this
<input type="file" multiple="true" name="" value="" />
Afaik there is not a way to do this without the use of javascript. However, here is a simple example that does use javascript. If you drag an image over the red div it appends the image to the body. I've confirmed it works in IE11, Chrome 38, and Firefox 32. See the Html5Rocks article for a more detailed explanation.
<div id="dropZone" style="width: 100px; height: 100px; background-color: red"></div>
<script>
var dropZone = document.getElementById('dropZone');
// Optional. Show the copy icon when dragging over. Seems to only work for chrome.
dropZone.addEventListener('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
// Get file data on drop
dropZone.addEventListener('drop', function(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files; // Array of all files
for (var i=0, file; file=files[i]; i++) {
if (file.type.match(/image.*/)) {
var reader = new FileReader();
reader.onload = function(e2) {
var img = document.createElement('img');
img.src= e2.target.result;
document.body.appendChild(img);
}
reader.readAsDataURL(file);
} } });
</script>

In HTML5 is there any way to make Filereader's readAsBinaryString() synchronous

How to wait till onload event completes
function(){
var filedata=null;
reader.onload=function(e){
filedata=e.target.result;
};
reader.readAsBinaryString(file);
//I need code to wait till onload event handler gets completed.
return filedata;
}
Typical solution to this is to separate your code so, that the part which uses the loaded data is in a separate function, which is then called from the event.
Pseudo-code'ish:
function load() {
//load here
reader.onload = function(e) {
process(e.target.result);
}
}
function process(result) {
//finish working here
}
You can read synchronously using threads (Webworkers in Javascript).
http://www.w3.org/TR/FileAPI/#readingOnThreads
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<form><input type="file" id="files" name="file" onchange="upload()" /></form>
function readFile(dfd) {
bytes = [];
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
var content = evt.target.result;
//bytes = stringToBytes(content);
dfd.resolve(content);
}
};
reader.readAsBinaryString(file);
}
function upload() {
var dfd = new $.Deferred();
readFile(dfd);
dfd.done(function(content){
alert("content:" + content);
});
}
The answer by Jani is correct, but in the case of dropping multiple files at once in a droparea, there are not separate events for each file (as far as I know). But the idea may be used to load the files synchronously by recursion.
In the code below I load at number of files and concatenate their content into a single string for further proccesing.
var txt="", files=[];
function FileSelectHandler(e) {
e.preventDefault();
files = e.target.files || e.dataTransfer.files;
txt="";
readFile(0);
}
function readFile(n) {
file=files[n];
var reader = new FileReader();
reader.onload = function() {
txt += reader.result;
}
reader.readAsText(file);
if (n<files.length-1) { readFile(n+1); }
else { setTimeout(doWhatEver, 100);}
}
function doWhatEver(){
outtext.innerHTML=txt;
}
The last file also needs a bit of extra time to load. Hence the "setTimeout".
"outtext" is the handle to a textarea where the entire string is displayed. When outputting in at textarea the browser wont' parse the string. This makes it possible to view not only text but also html, xml etc.
No there is not. All IO operations must be asynchronous in Javascript.
Making file operation synchronous would effectively block the browser UI thread freezing the browser. The users don't like that.
Instead you need to design your script in asynchronous manner. It is quite easy with Javascript.