Retrieve image data from file input without a server - javascript

For context, I'm trying to create a "click image" file uploader. Initially there is a default image, which I then click. I trigger a file upload, and the user picks an image file they want. Then I will set the image to replace the default (and do other things with it later). Right now, the front end looks something like this:
<div class="right-preview">
<input type="image" src="img/logo.png" height="240px" width="240px" ng-click="uploadImage('right-image')" id="upload-right-image"/>
<input type="file" id="upload-right" style="visibility: hidden">
</div>
When the image is clicked, it triggers an upload action.
$scope.uploadImage = function(side) {
$image = $('#upload-' + side);
$fileInput = $('#upload-right');
$fileInput.change(function(changeEvent) {
var files = changeEvent.target.files;
for(var i = 0; i < files.length; i++) {
file = files[i];
console.log(file);
}
});
$fileInput.trigger('click');
}
When the change event is fired after the user finishes picking their file, I have the changeEvent and I know they've selected their file. Each of the files has some properties (like name and size) but I'm not seeing anything for accessing the raw data so I can set the src on my other element.
Am I just completely missing how to get the image data, or is there a better way to do this? I have no server (right now) to post this to. Perhaps there is a better way to approach this?

This link may be helpful to you - https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
I took one method from that page and added some additional functionality to hide the file upload button and have the image placeholder trigger its click event.
$('#placeholder').click(function() {
$('#img-upload').trigger('click');
});
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
preview.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img width="250" height="250" id="placeholder" src="http://place-hold.it/250x250&text='click to upload'">
<input class="hidden" type="file" onchange="previewFile()" id="img-upload">

Related

Differentiate a video or image on file upload JS

I've searched whether it is possible for JavaScript to differentiate whether the file is a video or image. However there were just multiple sites showing how to accept those types on the input tag.
However, what I need is how can JS determine the file type, then display the file URL in either an image or the video HTML tag.
Currently when a user is to upload a file, I have used this as my file upload input:
<input accept="image/*,video/*" multiple="multiple" onchange='openFile(event)' style="display: none" type="file" id="selectedFile" />
But instead of the user having to "select" whether it is a video or image, the browser can find the file type and assign to file source to the right source element.
My current code which uploads the file creates a data:url for the image or video that the user uploads and sends it through a socket which displays to others presently on the site as shown below:
var openFile = function(file) {
var input = file.target;
var reader = new FileReader();
reader.onload = function() {
try {
var file = reader.result;
Toast.fire({
title: 'Uploading your File...',
text: " ",
didOpen: () => {
Swal.showLoading()
},
})
socket.emit('message', `
//
//
// However how can it differentiate which tag to use and use the uploaded data URL??
//
//
<video controls autoplay="1" alt="Video Uploaded" style="cursor: zoom-in; border-radius: 4px; width: 16rem" src="${file}">
<img alt="Image Uploaded" style="cursor: zoom-in; border-radius: 4px; width: 16rem" src="${file}">
`);
}
catch (err) {
}
};
reader.readAsDataURL(input.files[0]);
};
*I'm not using a blob for the file as it will not show for other users when sent through the socket. I also would rather use on file input button as I'm trying to keep things as simple for the user as possible.
TL;DR:
User clicks a "Upload file" button
User can upload either video or image files from the same input button
JS create a dataURL link and finds the file format
JS assigns which attribute tag ( or ) the file will display in
Sends through socket for others to see
Really appreciate if anyone can help! Thanks.
the reader.result contains MIME type of the file, from it you can detect if it's image or video or something else:
var openFile = function(file) {
var input = file.target;
var reader = new FileReader();
reader.onload = function() {
try {
var file = reader.result;
Toast.fire({
title: 'Uploading your File...',
text: " ",
didOpen: () => {
Swal.showLoading()
},
})
var match = reader.result.match(/^data:([^/]+)\/([^;]+);/) || [];
var type = match[1];
var format = match[2];
if (type == "video")
{
socket.emit('message', `
<video controls autoplay="1" alt="Video Uploaded" style="cursor: zoom-in; border-radius: 4px; width: 16rem" src="${file}">
`);
}
else if (type == "image")
{
socket.emit('message', `
<img alt="Image Uploaded" style="cursor: zoom-in; border-radius: 4px; width: 16rem" src="${file}">
`);
}
}
catch (err) {
}
};
reader.readAsDataURL(input.files[0]);
};
With it, you also can fine tune it by filtering based on format (it's not exactly a file extension, but rather a type of image/video, for example .mov = quicktime).

Is it possible to display an image that has been selected by an input element?

I wish to display an input element's selected image. Can this be performed on a local file, accessing the image client side, or would I need to upload the image to a server?
Here's my attempt in React. I can access the correct file name from the input element using inputElem.files[0].name. As soon as I am trying to set an image element to it, the broken image icon is displayed, and no error is surfaced.
const App = () => {
// state to keep track of img elements src. The default works fine.
const [imgSrc, setImgSrc] = useState('/images/test.jpg')
function handleImgUpload() {
const url = '/images/' + e.target.files[0].name
setImgSrc(url)
console.log(url) // /images/26e3e793-98f5-4720-9f82-8963276d5e27.JPG
}
function handleImgLoadSuccess() {
console.log('image loaded!')
}
function handleImgLoadError() {
console.log('image not loaded')
}
return (
<div>
<div>
<label htmlFor="img">Select an image:</label>
<input
type="file"
id="img"
name="img"
accept="image/png, image/jpeg"
onChange={(e) => handleImgUpload(e)}
/>
</div>
<img
src={imgSrc}
alt="Your upload"
onLoad={handleImgLoadSuccess}
onError={handleImgLoadError}
/>
</div>
)
}
In the console, however, the url seems to be correct.
<img src="/images/26e3e793-98f5-4720-9f82-8963276d5e27.JPG" height="100" width="200" alt="Input" class="jsx-855240488">
Hey – I see what you're trying to do, but it doesn't look like this will work. You need to create a new file reader.
const showTempImage = (e) => {
const file = e.target.files[0];
const img = document.createElement("img");
const reader = new FileReader();
reader.addEventListener('load', (e) => {
img.src = e.target.result;
});
reader.readAsDataURL(file);
// Append the img tag to the dom somewhere
}
This did the trick by creating a correct blob url.
const inputImg = e.target.files[0]
const url = URL.createObjectURL(inputImg)
// blob:http://localhost:3000/test-img.jpg
The resulting file stays in memory and needs to be removed in order to create memory leaks.
URL.revokeObjectURL(url)
This also seems to be accomplishable with FileReader, though there are differences.

Angular upload image and display to user

Id like to implement a UI where the user selects an image and that image is instantly displayed back to them for review. The user would have to click "submit" to upload/save the image to their profile.
I am having issues with the "instantly display back to the user part".
I am using angular FormData with the following markup & controller:
MARKUP
<input id="chooseFile" type="file" file-model="picFile" />
<img src="{{uploadedImage}}" /> <!-- this populates with filename but what is the path?? -->
CONTROLLER
angular.element('#chooseFile').change(function(){
var file = $scope.picFile; // this comes up "undefined" since file is still uploading when this is fired
$scope.uploadedImage = file.name;
});
I have 2 primary issues with the above code (described in comments):
1) In the controller, file comes up undefined obviously because even the smallest file takes >0s to upload while the callback is fired pretty much instantaneously. I got it work using $timeout but thats a bit of a lame hack. How can I have the callback wait until the file is uploaded??
2) The idea is to upload the file and display it in the img tag using Angular's data-binding. This works in that src is populated with the filename, but what is the path of the img. Some temporary location in cache or something?? Obviously I havent set a path to move the file yet.
Any help appreciated!
I also needed this feature, some how I manage to display image instantly.
angular.module('HelloWorldApp', [])
.controller('HelloWorldController', function($scope) {
$scope.uploadavtar = function(files) {
//var fd = new FormData();
//Take the first selected file
//fd.append("file", files[0]);
var imagefile = document.querySelector('#file');
if (imagefile.files && imagefile.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#temp_image')
.attr('src', e.target.result);
};
reader.readAsDataURL(imagefile.files[0]);
this.imagefile = imagefile.files[0];
}else{
console.log("Image not selected");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="HelloWorldApp">
<div ng-controller="HelloWorldController">
<input type="file" id="file" onchange="angular.element(this).scope().uploadavtar(this.files)"/>
</div>
<img src="" id="temp_image" width="100">
<div>
</div>
</div>
I was using laravel + Angularjs so another related post to store image is : https://stackoverflow.com/a/34830307/2815635

How to insert multiple instances of an image into html using FileReader.readAsDataURL()?

I want to insert an image that a user selects from their local machine using FileReader.readAsDataURL() into multiple <img> elements on a single html page.
Using the example code provided by the MDN docs for FileReader.readAsDataURL(), the image only gets inserted into the first img element, not the rest.
I thought the reason the image is only inserted into the first <img> instance is because the example code uses document.querySelector('img'). However, when I use document.querySelectorAll('img'), it still does not work.
The MDN docs provide a working codepen example that you can see in action. Here is their static code:
<!--html-->
<input type="file" onchange="previewFile()"><br>
<img src="" height="200" alt="Image preview...">
and
//js
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
preview.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
Here is a working codepen of my code, and below is my static code.
<div>
<label>Select an Image</label>
<input type="file" onchange="previewFile()">
</div>
<div>
<img id="small" src="http://placehold.it/900x900"/>
<img id="med" src="http://placehold.it/1200x1200"/>
<img id="large" src="http://placehold.it/1500x1500"/>
</div>
<script>
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
preview.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
</script>
Can anyone offer some help to get the user selected image to populate all of the <img> elements on the page instead of just the first element?
Not quite sure to correctly understand your need.
If it's like this:
you expect only one file (image) to be selected through your <input>
and you want this unique image to be the same source of all your <img>s
Then below is the way to go:
function previewFile() {
var preview = document.querySelectorAll('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
for (var img in preview) {
preview[img].src = reader.result;
}
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
<div>
<label>Select an Image</label>
<input type="file" onchange="previewFile()">
</div>
<div>
<img id="small" src="http://placehold.it/100x100"/>
<img id="med" src="http://placehold.it/200x200"/>
<img id="large" src="http://placehold.it/300x300"/>
</div>
The main points are:
preview gets all <img>s (as you already tried)
then we use a for() loop to process each of them (here was your lack)
The code will need to iterate over all the files in the file list and then assign each (via Object-URL) to separate image element.
I would suggest the following changes as there is really no need for FileReader at this point. The URL.createObjectURL() can be used with File blobs as well and save us from some headache:
document.querySelector("input[type=file]").onchange = previewFile;
function previewFile() {
var files = this.files; // "this" = input element
var parent = document.querySelector(".imageList"); // parent element
var i = 0, file;
while(file = files[i++]) { // iterate over file list
var img = new Image(); // create new image instance
img.src = (URL || webkitURL).createObjectURL(file); // use File blob directly
parent.appendChild(img); // insert image in DOM
};
}
<div>
<label>Select an Image
<input type="file" multiple> <!-- make sure multiple is enabled -->
</label>
</div>
<div class="imageList"></div>
If you want to replace an image list simply obtain the list of images using querySelectorAll() instead of querySelector(), then replace the sources from the list until one run dry:
//... as before
var img, images = document.querySelectorAll("img");
while((file = files[i]) && (img = images[i++])) { // loop until one runs dry
img.src = (URL || webkitURL).createObjectURL(file); // use File blob directly
};
document.querySelector("input[type=file]").onchange = previewFile;
function previewFile() {
var files = this.files; // "this" = input element
var parent = document.querySelector(".imageList"); // parent element
var i = 0, file;
var img, images = document.querySelectorAll("img");
while((file = files[i]) && (img = images[i++])) { // loop until one runs dry
img.src = (URL || webkitURL).createObjectURL(file); // use File blob directly
};
}
<div>
<label>Select an Image
<input type="file" multiple> <!-- make sure multiple is enabled -->
</label>
</div>
<div class="imageList">
<img id="small" src="http://placehold.it/100x100"/>
<img id="med" src="http://placehold.it/200x200"/>
<img id="large" src="http://placehold.it/300x300"/>
</div>

upload a file using imageUpload (javascript), probably sthg simple

Today I upload a picture using a simple button (id: "imageUpload") to upload a file. Evthg works perfectly. A thumb of the picture is then visible in "thumb1".
I would like to upload a picture also by clicking the div "preview1".
Here is my code with what I tried :
<input type="file" id="imageUpload">
<div class="preview1 slide" onclick="document.getElementById('imageUpload').click();">
<div id="thumb1" class="thumb"></div>
</div>
and the js :
new AjaxUpload('imageUpload', {
action: "upload",
name: 'userfile',
onSubmit : function(file, extension){
do some work..
},
onComplete: function(file, response) {
do some work..
}
});
Result :
When I click on "preview1", a window open to select a file : OKAY
but then the file is not uploaded (no thumb preview), and only the name of the file appear on the right of "imageUpload" :
Any idea ?
If I am understanding you correctly, you are looking to have a picture thumbnail appear on file upload. This might help you
How to generate a thumbnail image after adding an image inside an input type="file" in a form and submitting them both on the same form
Recycled from user: Che-azeh:
function previewFile() {
var preview = document.querySelector('img');
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
<input type="file" onchange="previewFile()"><br>
<img src="" height="200" alt="Image preview...">

Categories