I am working on a web page for uploading photos from a mobile device, using the <input type="file" accept="image/*"/> tag. This works beautifully on iphone and on chrome on the android, but where we are running into issues is with the stock android browser.
The issue arises when you select a file from your gallery (it works fine when you use the camera to take a photo). And we have narrowed it down even further to seeing that the data MIME type isn't available when taken from the gallery on the stock browser (the photos below show the first 100 characters of the data URL being loaded. The goal was to force JPEG, but without the MIME type we cannot know for sure how to fix this. See code below for how the images are being rendered.
How can an image be rendered without the type? Better yet, does anybody know why the type is not available on the stock android browser?
EDIT
Firstly, these are not the same image, they were taken near the same time, and that's not the issue, that's why the data is different (The MIME type doesn't appear on any images on the stock browser, so that's not the problem.
Update
I confirmed that the MIME type is the issue by inserting image/jpeg into the stock browser where it is on chrome. Unfortunately, we have no way of guaranteeing that it's going to be jpeg, so we again really can't do it that way
_readInputFile: function (file, index) {
var w = this, o = this.options;
try {
var fileReader = new FileReader();
fileReader.onerror = function (event) {
alert(w._translate("There was a problem opening the selected file. For mobile devices, some files created by third-party applications (those that did not ship with the device) may not be standard and cannot be used."))
$('#loadingDots').remove();
return false;
}
fileReader.onload = function (event) {
var data = event.target.result;
//alert(data.substring(0,100));
//var mimeType = data.split(":")[1].split(";")[0];
alert("Load Image"); //I get to this point
$('#' + w.disp.idPrefix + 'hiddenImages').append($('<img />', {
src: data,
id: "dummyImg" + index,
load: function(){
var width = dummy.width();
var height = dummy.height();
$('#dummyImg' + index).remove();
alert("Render"); // I don't get here
var resized = w._resizeAndRenderImage(data, null, null, biOSBugFixRequired, skewRatio, width, height);
alert("Image Rendered"); // I don't get here
}
}));
}
fileReader.readAsDataURL(file);
}
catch (e) {
}
}
Chrome
Stock Browser
Since the issue is probably browser-related, and you can't really fix the browser(you could report a bug to Google though), I'd suggest taking a different path.
Have a look Here:
In Node.js, given a URL, how do I check whether its a jpg/png/gif?
See the comments of the accepted answer, which suggests a method to check the file type using the file stream. I'm pretty sure this would work on browser-implemented Javascript and not only in Node.js.
Related
I'm using exif-js library to extract the orientation from images uploaded to my web app.
I need the exif orientation to rotate incorrectly rotated android images.
The problem is that images uploaded from android device always return 0 as their orientation.
I've tried transfering image taken from the same android device to desktop, and uploading it from there, everything works fine in that case and I get the orientation 6.
localforage.getItem('photo').then(function(value) {
alert('inside forage');
image = value;
alert(image); // i get the image object
url = window.URL.createObjectURL(image);
alert(url); // url is correct
let preview = document.getElementById('camera-feed');
preview.src = url;
// const tags = ExifReader.load(image);
console.log( tags );
EXIF.getData(image, function() {
myData = this;
if (myData.exifdata.Orientation) {
orientation = parseInt(EXIF.getTag(this, "Orientation"));
alert(orientation); // on desktop 6, on android always 0
}
});
....
I'm using chrome browser on android.
After a lot of changes in my project, I used
this library to handle image rotation on the frontend
I know you already solved this, but I would still like to recommend exifr library if you need more than orientation. Or if performance is important to you. Exifr is fast and can handle hundreds of photos without crashing the browser or taking a long time :). Plus there's neat simple API and you feed it with pretty much anything - element, URL, Buffer, ArrayBuffer, even base64 url or string and more.
exifr.orientation(file).then(val => {
console.log('orientation:', val)
})
Would anyone be able to point me in the right direction, I'm trying to write a small application for a web-site, where by the user can choose either an image, or choose to capture an image with their phone camera.
We can then display (preview) the image to them, and they can confirm it and carry on, or restart and take the image again.
I've found a few ways to do this using jQuery, which seemed to work well on a computer, However on a phone (tested using a Samsung S5 running the latest chrome) i frequently receive error messages saying that the previous operation could not be completed due to low memory.
Here is an example of the current code i'm using, this is stripped down somewhat just to show a basic example, but you can see the method doesn't seem very efficient:
$(function() {
$("#prev-img-file").on("change", function()
{
var files = !!this.files ? this.files : [];
if (!files.length || !window.FileReader) return; // no file selected, or no FileReader support
if (/^image/.test( files[0].type)){ // only image file
var reader = new FileReader(); // instance of the FileReader
reader.readAsDataURL(files[0]); // read the local file
reader.onloadend = function(){ // set image data as background of div
$(".up-pic-preview").css("background-image", "url("+this.result+")");
}
}
});
});
http://jsfiddle.net/fish_r/vnu7661c/
Would anyone know of anything that doesn't hog as much resources?
Thanks!
Try WebcamJS.
One of the demo pages - test it on my android 4.4 phone minute ago - works fine :-)
This library allows you to:
display preview;
capture image;
upload captured image to server;
fallback to flash if HTML5 getUserMedia() is not supported;
Hello we are having issues with File Upload on Chrome and Safari on IOS 8.1.2. Some photo upload shows data with an empty string, others are displaying OK. Anyone knows a workaround so the uploaded photos can be consistently displayed? Thanks so much.
Initially we thought that it was a known issue with File Upload featuring broken on iOS 8 Safari. "http://blog.uploadcare.com/you-cannot-upload-files-to-a-server-using-mobile-safari/". However, It appeared to be problem with 8.0.0 and has supposedly been fixed. Also, the problem is not limited to Safari and appears in Chrome iOS as well.
Specifically, when a photo chosen was taken directly from the iPHONE camera, the data appears to be empty (see log in console)
[Log] Object (controllers.js, line 228)
src: "data:,"
However, when a photo chosen is either a Screen Shot or a photo saved from an email, the image is in fact displayed and the data is sent
[Log] Object (controllers.js, line 228)
src: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/7QA4UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAA4QklNBCUAAAAAABDUHYzZjwCyBOmACZjs+EJ+/8AAEQgGYATIAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBh...."
Has anyone encountered a similar issue? Why does it work with some photos but not others? Anyone knows any workaround to display images that have been taken from the Camera itself?
Snippets of codes here:
$scope.getAlbumPicture = function() {
Camera.getAlbumPicture().then(function(fileURI) {
$scope.normalisePicture(fileURI, function(dataURL) {
Local.setTemp(dataURL);
$state.go('tab.camera-detail');
});
}, function(err) {
console.log(err);
});
};
$scope.readImage = function(input) {
if (input.files && input.files[0]) {
var fileReader = new FileReader();
fileReader.onloadend = function() {
$scope.normalisePicture(fileReader.result, function(dataURL) {
Local.setTemp(dataURL);
$state.go('tab.camera-detail');
});
};
fileReader.readAsDataURL(input.files[0]);
}
};
TL;DR Recently I encountered similar issue as described in question, found this thread, it may has been a low memory issue with iPhone, and not much work around you can do but resize the big size image with canvas element, I using 1200 as the longest width/height for the image to resize then everything works again.
for any feature reference, more specific hardware and software the problem occurred with my test is iPhone 6 Plus and iOS 8.1.2, and the process I tried to do with images is:
using FileReader.onLoad = func with FileReader.readAsDataURL()to read input[type="file"]'s file as base64 string.
assign base64 as new image()'s src
inside image.onload = func draw a new canvas's 2d context with the same with and height as image above.
check some orientation EXIF info then rotate the canvas.
finally do other staffs with base64 string of new image which generated form canvas.toDataURL().
The empty data: occurs in both between step 1 to step 2 and step 5 randomly depends on the size of image got from `input[type="file"].
In my case, iOS Safari here seems being okay to assign image data to canvas with same width and height, but not okay to toDataURL for the canvas if it has a very big size. But Safari won't hang anyway, I can re-tap input[type="file"] to get next file since the empty data: outputted from previous one.
I have an image encoded in base64 in a javascript variable : data:image/png;base64, base64 data
[EDIT]
I need to save that file to disk without asking to the visitor to do a right click
[/EDIT]
Is it possible ? How ?
Thanks in advance
Best regards
I know this question is 2 years old, but hopefully people will see this update.
You can prompt the user to save an image in a base64 string (and also set the filename), without asking the user to do a right click
var download = document.createElement('a');
download.href = dataURI;
download.download = filename;
download.click();
Example:
var download = document.createElement('a');
download.href = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
download.download = 'reddot.png';
download.click();
In order to trigger a click event using Firefox, you need to do what it is explained in this SO answer. Basically:
function fireEvent(obj,evt){
var fireOnThis = obj;
if(document.createEvent ) {
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( evt, true, false );
fireOnThis.dispatchEvent( evObj );
} else if( document.createEventObject ) {
var evObj = document.createEventObject();
fireOnThis.fireEvent( 'on' + evt, evObj );
}
}
fireEvent(download, 'click')
As of 20/03/2013, the only browser that fully supports the download attribute is Chrome. Check the compatibility table here
... without asking to the visitor anyhing ... Is it possible?
No, that would have been a security hole. If it was possible, one would be able to write malware to the enduser's disk unaskingly. Your best bet may be a (signed) Java Applet. True, it costs a bit of $$$ to get it signed (so that it doesn't pop security warnings), but it is able to write data to enduser's disk without its permission.
I am surprised nobody here mentioned using HTML5 blobs together with a couple of nice libraries.
You first need https://github.com/eligrey/FileSaver.js/ and https://github.com/blueimp/JavaScript-Canvas-to-Blob.
Then you can load the image into a canvas
base_image = new Image();
base_image.src ='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
the canvas into a blob
var canvas = document.getElementById('YourCanvas');
context = canvas.getContext('2d');
// Draw image within
context.drawImage(base_image, 0,0);
and finally save it
x_canvas.toBlob(function(blob) {
saveAs(blob, "screenshot.png");
}, "image/png");
FF is not fully supported but at least you get a separate page with the image.
Check this out: http://jsfiddle.net/khhmm/9/
EDIT: this is not compatible with Safari / Mac.
As other answers already stated, you cannot do it only with javascript. If you want, you can send the data (using normal HTTP POST) to a PHP script, call header('Content-type: image/png') and output the decoded image data to the page using echo base64_decode($base64data).
This will work just as if user clicked on an image and open it or prompt him to save the file to disk (the normal browser's save file dialog).
It's not possible.
If it was, browsers would be massively insecure, being able to write random data to your hard disk without user interaction.
with javascript, you can't. the only real possibility i can think of will be a java-applet, but maybe (i don't know how long that image should be saved) you could simply add an img-tag with you png and force caching (but if the user deletes his cache, the image will be gone).
I think it's possible with JavaScript if you use ActiveX.
Another possibility is to make the server spit out that file with a different mime type so the browser asks the user to save it.
I think you can do it something(maybe not only with javascript...xul programming needed). There are Firefox addons that save images to a folder(check Firefox addons site)
You can make this file as blob on the server and use setTimeout function in order to fire the download.
The accepted solution seems to have a limitation for large data. If you're running into this (instead of the downloaded file's name, I see "download" and "Failed - Network error" in Chrome), here's what I did in order to download a 2mb file:
const blob = await (await fetch(document.getElementById('canvasID').toDataURL())).blob();
const file = new File([blob], {type:"image/png", lastModified: new Date()});
var a = document.createElement('a');
a.href = window.URL.createObjectURL(file);
a.download = 'image.png';
a.click();
I have upload file functionality on one of the page. I check for the extension of the file using JavaScript. Now i want to restrict the user from uploading file greater than 1 MB. Is there any way i can check the file upload size using JavaScript.
My code currently look like this:
<script language="JavaScript">
function validate() {
var filename = document.getElementById("txtChooseFile").value;
var ext = getExt(filename);
if(ext == "txt" || ext == "csv")
return true;
alert("Please upload Text files only.");
return false;
}
function getExt(filename) {
var dot_pos = filename.lastIndexOf(".");
if(dot_pos == -1)
return "";
return filename.substr(dot_pos+1).toLowerCase();
}
</script>
See http://www.w3.org/TR/FileAPI/. It is supported by Firefox 3.6; I don't know about any other browsers.
Within the onchange event of a <input id="fileInput" type="file" /> simply:
var fi = document.getElementById('fileInput');
alert(fi.files[0].size); // maybe fileSize, I forget
You can also return the contents of the file as a string, and so forth. But again, this may only work with Firefox 3.6.
Now it is possible to get file size using pure JavaScript. Nearly all browser support FileReader, which you can use to read file size as well as you can show image without uploading file to server. link
Code:
var oFile = document.getElementById("file-input").files[0]; // input box with type file;
var img = document.getElementById("imgtag");
var reader = new FileReader();
reader.onload = function (e) {
console.log(e.total); // file size
img.src = e.target.result; // putting file in dom without server upload.
};
reader.readAsDataURL(oFile );
You can get file size directly from file object using following code.
var fileSize = oFile.size;
Other that aquiring the filename there is no way for you to find out any other details about the file in javascript including its size.
Instead you should configure server-side script to block an oversized upload.
Most of these answers are way out-of-date. It is currently possible to determine file size client-side in any browser that supports the File API. This includes, pretty much, all browsers other than IE9 and older.
It might be possible using a lot of browser-specific code. Take a look at the source of TiddlyWiki, which manages to save itself on the user's hard drive by hooking into Windows Scripting Host (IE), XPCOM (Mozilla), etc.
I don't think there is any way of doing that with plain JS from a web page.
With a browser extension maybe, but from a page javascript cannot access the filesystem for security reasons.
Flash and Java should have similar restrictions, but maybe they are a bit less strict.
not possible. would be a major security concern to allow client side scripts to run that can read file info from and end users hard drive.
See here:
http://www.kavoir.com/2009/01/check-for-file-size-with-javascript-before-uploading.html
As to all the people saying this has to be done server side, they are absolutely spot on it does.
In my case though the maximum size I will except is 128Mb, if a user tries to upload something that is 130Mb they should not have to wait the 5 minute upload time to find out it is too big so I need to do an additional check before they submit the page for usability sake.
I had the same issue, Here's a simple JavaScript snippet worked for me. Adding for future googlers.
HTML
<input type="file" name="photo" id="photo" accept="image/*">
JS
const file = document.getElementById('photo');
// Show KB (add one more /1024 for MB)
const filesize = file.files[0].size / 1024;
if (filesize > 500) { // Alert greater than 500kb
console.log(filesize);
alert('Please upload image less than 500 KB');
return;
}