Unable to select files on Mobile both IOS and Android - javascript

I'm trying to be able to upload an image to change a background of a table automatically, but it is only working on Desktop computers, it won’t work on neither IOS nor Android, anyone has any pointers? Thanks in advance.
const frame = document.getElementById('table');
const file = document.getElementById('file');
const reader = new FileReader();
reader.addEventListener("load", function () {
frame.style.backgroundImage = `url(${ reader.result })`;
}, false);
file.addEventListener('change',function() {
const image = this.files[0];
if(image) reader.readAsDataURL(image);
}, false)

Try using object urls
document.body.id = 'table'
const [{style}, file] = document.querySelectorAll('#table, #file')
file.addEventListener('change', img => {
[img] = file.files
style.backgroundImage = img ? `url(${URL.createObjectURL(img)})` : ''
})
<input type=file id=file accept="image/*">

Related

How to convert reader.readAsDataURL(file) to readAsArrayBuffer

I have a component which allows me to drag multiple images onto the page and display the preview of those images. The following code achieves that:
displayPreviews(files: FileList) {
for (let i = 0; i < files.length; i++) {
const file = files.item(i);
const reader = new FileReader();
reader.onload = () => {
const image = reader.result as string;
this.uploadFileArray.push({
id: 'id',
image: image,
});
};
reader.readAsDataURL(file);
}
}
----------
<li *ngFor="let image of uploadFileArray">
<div *ngIf="image && image !== ''" [ngStyle]="{'background-image': 'url(' + image.image + ')'}"></div>
</li>
However, when selecting a large amount of images, it slows down the interaction with the rest of the page (form filling etc). I read that reader.readAsArrayBuffer can help alleviate that issue. However, I don't know how to integrate it. The below shows a grey box as it's no longer reading the image in the preview.
detectPhotos(files: FileList) {
for (let i = 0; i < files.length; i++) {
// Reference to a file
const file = files.item(i);
const reader = new FileReader();
reader.onload = () => {
const image = reader.result;
this.uploadFileArray.push({
id: 'id',
image: image,
});
};
reader.readAsArrayBuffer(file);
};
}
One issue of using readAsDataURL, the browser is going to have to convert blob to dataURI and then to display it, it's having to decode the dataURI. If you don't need to process the images first etc, you can use URL.createObjectURL to create a URL that references the BLOB instead.
Be aware, that URL.createObjectURL will keep the blob in memory until you call URL.revokeObjectURL(), it won't get GC'ed until you do. If using something like React, you could attach this to a useEffect dismount, if using pure JS you will want to keep a reference of these to clear when your done.
document.querySelector('input').addEventListener('change', function (e) {
for (const file of e.target.files) {
const url = URL.createObjectURL(file);
const img = document.createElement('img');
img.style.width = "100px";
img.setAttribute('src', url);
img.onload = () => {
URL.revokeObjectURL(url);
};
document.querySelector('#images').appendChild(img);
}
});
<input type="file" name="files" multiple accept="image/*"/>
<div id="images"></div>

cant get length of m4a audio file on webpage

I am trying to make a nodejs website that will return the length in seconds of any audio file a user chooses. So far I have it working with mp3, wav, and flac files. But it doesn't work for all .m4a or .aif files
The code for my HTML page with javascript is below:
choose audio file to get length:
<input style="cursor: pointer;" type="file" id="file" multiple="multiple" />
<script>
//when files are selected:
$("#file").change(async function (e) {
console.log('file(s) selected')
//get files
var files = e.currentTarget.files;
//get number of files
var numberOfFiles = files.length;
//for each file
for (i = 0; i < numberOfFiles; i++) {
console.log(`songs[${i}].type=`, files[i].type)
//get file length
let songLength = await getSongLength(files[i]);
console.log('songLength=', songLength)
}
});
//recieve audio file, return length
function getSongLength(song) {
return new Promise(function (resolve, reject) {
console.log('getSongLength() begin setup')
//create objectURL and audio object for ssong
objectURL = URL.createObjectURL(song);
mySound = new Audio([objectURL])
console.log('getSongLength() end setup')
//when song metadata is loaded:
mySound.addEventListener("canplaythrough", function (e) {
console.log('getSongLength() canplaythrough')
var seconds = e.currentTarget.duration;
resolve(seconds)
});
});
}
</script>
I gathered 6 different files for testing, and after running them on my above code have found out the following results:
aif: not working
flac: working
m4a_file: not working
m4a_file_from_comments_below:not working
mp3: working
wav: working
my test files for download: https://easyupload.io/m/la9xro
It seems like when I input my m4a file sample_M4A_file that it hangs inside the getSongLength() function and never enters the .addEventListener("canplaythrough" function, is there any alternative I can use to consistently get the duration in seconds for every audio file?
It's because your browser doesn't support Apple Lossless codecs. If you try in Safari, it will work.
If you attach an error event to your media element, you'll see it fires.
There is no real universal solution, apart from using an heavy machinery like mediainfo.js (2.4MB+) which should support most formats.
const input = document.querySelector( "input" );
input.onchange = async (evt) => {
const mediainfo = await new Promise( (res) => MediaInfo(null, res) );
const file = input.files[ 0 ];
const getSize = () => file.size;
const readChunk = async (chunkSize, offset) =>
new Uint8Array( await file.slice(offset, offset + chunkSize).arrayBuffer() );
const info = await mediainfo.analyzeData(getSize, readChunk);
// assumes we are only interested in audio duration
const audio_track = info.media.track.find( (track) => track[ "#type" ] === "Audio" );
console.log( audio_track.Duration );
};
<script src="https://unpkg.com/mediainfo.js#0.1.4/dist/mediainfo.min.js"></script>
<input type="file">
Ps: when using the media element solution, there is no need to wait for canplaythrough, just wait for loadedmetadata, and if you get Infinity, try this hack.

Preview last uploaded image

I'm using an old project where I could upload many images but for this one, I only need just one. When uploaded, I should see what's uploaded (preview). When first uploaded, I see the image. If uploaded a different image, I still see the first image. I dont want that, I need to preview the last uploaded image.
JavaScript:
$('.receipt.upload').on('change', function(e) {
let id = e.target.id;
let files = e.target.files;
let image = files[0];
let reader = new FileReader();
reader.onload = function(file) {
let img = new Image();
console.log(file);
img.src = file.target.result;
$('.'+id).replaceWith(img);
}
reader.readAsDataURL(image);
//console.log(files);
});
Rails html.erb:
<div>
<%= image_tag('/assets/receipt/missing-receipt.jpg', class: "receipt#{contract.id}") %>
</div>
// Inside a form
<div>
<%= f.file_field :receipt, id: "receipt#{contract.id}" , class: "receipt upload"%>
</div>
Change these makes no difference:
let files = e.target.files[0];
let image = files;
Created <img> img does not have .className set to <input type="file"> .id. At second change event no element exists in document with id at jQuery() call $('.'+id).
Set the .className of replacement element img to id.
$('.receipt.upload').on('change', function(e) {
let id = e.target.id;
let files = e.target.files;
let image = files[0];
let reader = new FileReader();
reader.onload = function(file) {
let img = new Image();
img.className = id; // set `img` `.className` to `id`
console.log(file);
img.src = file.target.result;
$('.'+id).replaceWith(img);
}
reader.readAsDataURL(image);
});
You don't need the FileReader...
$('.receipt.upload').on('change', function(e) {
let {id, files} = this
let img = new Image
img.src = URL.createObjectURL(files[0])
img.className = id
$('.'+id).replaceWith(img)
})

Javascript image upload and display

My basic task is select image and display it,without saving it in database.
For this
1.I have made a select tag in html,through which I can upload the image.
2.I have made a blank image tag in which at there is no image source,alternate is upload image.
3.select tag has onchange javascript event handler which calls javascript function changeimage.
<script>
function changeimage()
{
document.form_name.imagetag.src=document.form_name.filetag.value;
}
</script>
In above Code
form_name : Is the name of my form
<form name = "form_name">
imagetag : Is the name of my Img tag
<Img src=" " name = "imagetag">
filetag : Is the name of my
<input type="file" name = "filetag" onchange="changeimage()">
I have save file using php extension.And when I try to print the value of filetag it shows "C:\fakepath\image.png",display this address for all image.
I have save my php file in www location.
I am using window 7,wamp server and chrome latest version.
You may want to checkout this solution (where my code derives from). It involves a little bit of jQuery but if you truly must write it out in pure JS, here you go.
Note: I modified your tags to conform to the JS below. Also try to stay away from writing any inline scripts. Always good to keep your HTML and JS loosely coupled.
var fileTag = document.getElementById("filetag"),
preview = document.getElementById("preview");
fileTag.addEventListener("change", function() {
changeImage(this);
});
function changeImage(input) {
var reader;
if (input.files && input.files[0]) {
reader = new FileReader();
reader.onload = function(e) {
preview.setAttribute('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
<input type="file" id="filetag">
<img src="" id="preview">
You can also use the Image() constructor. It creates a new HTML Image Element.
Example -
document.getElementById("filetag").addEventListener("change", function(e) {
let newImg = new Image(width, height);
// Equivalent to above -> let newImg = document.createElement("img");
newImg.src = e.target.files[0];
newImg.src = URL.createObjectURL(e.target.files[0]);
output.appendChild(newImg);
});
Reference - https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image
You need one input tag to upload file and a image tag to render on the site.
The HTML and Javascript should look like
const renderFile = () => {
const render = document.querySelector('img')
const file = document.querySelector('input[type=file]').files[0]
const reader = new FileReader();
reader.addEventListener('load' , ()=> {
render.src = reader.result;
}, false)
if(file){
reader.readAsDataURL(file);
}
}
<input type = 'file' onchange = 'renderFile()' >
<br>
<br>
<img src = "" alt='rendered image' id='rendered-image' >
Simply on every upload the web page will show the image uploaded
You can Style the height and width of the image according to the need

Display Image Using Upload JS

I want to display the image using the upload form and submit button.
But the problem though, I can't make the image appear.
Here's what I did.
function myFunction() {
var x = document.getElementById("myFile").value;
document.getElementById('myImg').src = document.getElementById("myFile").name;
<form>Select a file to upload:
<input type="file" id="myFile" name=filename>
</form>
<button type="button" onclick="myFunction()">Upload This</button>
<img id="myImg" src="">
I just don't know what seems to be the problem with this.
Thank you for helping me out.
The browser does NOT allow javascript full access to the .value property of an input tag with type="file". This is for security reasons so no local path information is made available to javascript.
Thus, you can't set a .src value on an image tag based on a file input value that the end-user specified.
If you don't want to upload the image to server side, you have a possibility to do it only in the client side.
add a div to your html (dom):
<div id='bottom'>
<div id='drag-image' class='holder-file-uploader bottom-asset'> Drag here an image</div>
</div>
add this javascript:
<script>
var holder = document.getElementById('drag-image');
holder.ondragover = function () { return false; };
holder.ondragend = function () { return false; };
holder.ondrop = function (event) {
event.preventDefault && event.preventDefault();
//do something with:
var files = event.dataTransfer.files;
console.log(files);
bottomFileAdd(files, 0);
return false;
};
//Recursive function to add files in the bottom div
//this code was adapted from another code, i didn't test it
var bottomFileAdd = function (files, i) {
if(!i) i=0;
if (!files || files.length>=i) return;
var file = files.item(i);
var img = document.createElement('img');
var bottom = document.getElementById('bottom'); //this string should not be static
bottom.appendChild(img);
var reader = new FileReader();
reader.onload = function (event) {
console.log(event.target);
img.src = event.target.result;
bottomFileAdd(files, i+1);
};
reader.readAsDataURL(file);
}
</script>
note: It may not work in older browsers.
I hope it helps.
You tried to set the src attribute of the <img> tag to a local file path. However, the web browser doesn't expose the local file URL (file://...) in the value property of the <input> tag. The browser implementation may vary; Chrome, for example, gives you a fake path.
You can load the image by the FileReader API into a data URI and show it by setting the src attribute of the <img> tag:
function myFunction() {
var myFile = document.getElementById("myFile");
if (myFile.files && myFile.files.length) {
if (typeof FileReader !== "undefined") {
var fileReader = new FileReader();
fileReader.onload = function(event) {
document.getElementById("myImg").src = event.target.result;
};
fileReader.readAsDataURL(myFile.files[0]);
} else {
alert("Your browser doesn't support the FileReader API.")
}
} else {
alert("No file was selected.")
}
}
You need a fairly modern web browser for this to work:
Browser Firefox Chrome IE Opera Safari
Version 3.6 7 10 12.02 6.0.2
You can have a look at a working sample page. The final implementation of such image preview should set the <img> element to a fixed size, but your markup with my function is enough as a simple demonstration.

Categories

Resources