I am having problem in sending my base64 image from phonegap (ios) to firebase storage. The main problem is firebase storage only accepted BLOB or File as attachment.
Heres my code for the camera function. Cordova-plugin-camera
function GetCamera(){
navigator.camera.getPicture( cameraSuccess, cameraError, {quality :50,
destinationType: Camera.DestinationType.DATA_URL,
encodingType: Camera.EncodingType.JPEG,
saveToPhotoAlbum: true});}
function to convert base 64 to blob
function b64toblob(b64_data, content_type) {
content_type = content_type || '';
var slice_size = 512;
var byte_characters = atob(b64_data);
var byte_arrays = [];
for(var offset = 0; offset < byte_characters.length; offset += slice_size) {
var slice = byte_characters.slice(offset, offset + slice_size);
var byte_numbers = new Array(slice.length);
for(var i = 0; i < slice.length; i++) {
byte_numbers[i] = slice.charCodeAt(i);
}
var byte_array = new Uint8Array(byte_numbers);
byte_arrays.push(byte_array);
}
var blob = new Blob(byte_arrays, {type: content_type});
return blob;};
Camera success function. take note that imageblob is a global variable
function cameraSuccess(imageData){
document.getElementById('Attachment1').innerHTML = "Attachment: True";
var image = imageData;
imageblob = b64toblob(image,"image/jpeg");}
putting the blob to firebase storage
try{
var storageRef = storage.ref().child('fire');
var uploadTask = storageRef.put(imageblob);
uploadTask.on('state_changed',null, null, function(){
var downloadURL = uploadTask.snapshot.downloadURL;
console.log("downloadURL :"+downloadURL);
});
i have tried every single thing, but its not working. Really need your guys help.. i am out of ideas
Cordova camera plugin doesn't return file object. That is problem with plugin.
But it returns all details about image. By using that you can create a blob or file object.
Reference for creating blob from file url.
var getFileBlob = function (url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function (blob) {
cb(blobToFile(blob, 'test.jpg')); // Second argument is name of the image
});
};
Calling function for get file blob
getFileObject('img/test.jpg', function (fileObject) { // First argument is path of the file
console.log(fileObject);
});
In your camera success function try this.
function cameraSuccess(imageData){
document.getElementById('Attachment1').innerHTML = "Attachment: True";
getFileObject(imageData.nativeURL, function(fileObject) {
console.log(fileObject);
var imgName = fileObject.name;
var metadata = { contentType: fileObject.type };
var uploadFile = storageRef.child("images/" + imgName).put(fileObject, metadata);
uploadFile.on(firebase.storage.TaskEvent.STATE_CHANGED, function(snapshot) {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
}, function(error) {
console.log(error);
}, function() {
var imgFirebaseURL = uploadFile.snapshot.downloadURL;
console.log(imgFirebaseURL);
});
});
}
Related
I am new to coding in javascript, I have been tasked as an excersise using some pre-existing functions to create an image item using a given url. I need to read the image, store it in local storage and then display it on the screen. The only functionI need to add too is process file. I am stuck and cannot get it to display the image. I get an error saying that the path does not exist. Below is my code, any guidance to what I am doing wrong? I feel like I am very close but doing something funamendatly wrong.
function addImageEntry(key, url) {
var imgElement = new Image();
imgElement.alt = "Photo entry";
imgElement.src = url;
addSection(key, imgElement);
}
function makeItem(type, data) {
var itemObject = { type: type, data: data };
return JSON.stringify(itemObject);
}
function processFile(event) {
function addImage(url) {
var key = "diary" + Date.now();
addImageEntry(key, url);
var imgElement = new Image();
imgElement.src = url;
var item = makeItem("image", imgElement.src);
localStorage.setItem(key, item);
}
var inputElement = event.target;
var fileObject = inputElement.files[0];
var reader = new FileReader();
reader.addEventListener("load",addImage);
url = reader.readAsDataURL(fileObject);
event.target.value = "";
}
The url = reader.readAsDataURL(fileObject) won't store the image data.
It stores in reader.result.
Use imgElement.src = reader.result.
document.querySelector('input[type="file"]').addEventListener('change', processFile)
function processFile(event) {
var fileObject = event.target.files[0]
var reader = new FileReader()
reader.addEventListener('load', addImage)
reader.readAsDataURL(fileObject)
function addImage() {
var imgElement = new Image()
imgElement.src = reader.result
document.body.append(imgElement)
}
}
Amend:
function addImage(event) {
// use reader.result is ok too
localStorage.setItem('myimage', event.target.result)
}
function addImageEntry() {
var imgElement = new Image()
imgElement.src = localStorage.getItem('myimage')
imgElement.style.display = 'block'
document.body.append(imgElement)
}
I am using web workers for uploading file and I am sending the file in the form of formData object as got to know that the web worker doesn't have access to DOM I used formdata-polyfill in place of default FormData , it is throwing this error and I don't know how to use this polyill properly.
here is my code,
//trying to send the formdata-polyfill object to worker
require('formdata-polyfill');
let data = new FormData();
data.append('server-method', 'upload');
data.append('file', event.target.files[0]);
// let data = new FormData(event.target.files[0]);
if (this.state.headerActiveTabUid === '1')
this.props.dispatch(handleFileUpload({upload: 'assets', data}));
//worker.js
var file = [], p = true, url,token;
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);//add url to upload
xhr.setRequestHeader('Authorization', token);
xhr.onload = function(e) {
};
xhr.send(blobOrFile);
}
function process() {
for (var j = 0; j <file.length; j++) {
var blob = file[j];
const BYTES_PER_CHUNK = 1024 * 1024;
// 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while (start < SIZE) {
if ('mozSlice' in blob) {
var chunk = blob.mozSlice(start, end);
} else {
var chunk = blob.slice(start, end);
}
upload(chunk);
start = end;
end = start + BYTES_PER_CHUNK;
}
p = ( j === file.length - 1);
self.postMessage(blob.name + " Uploaded Succesfully");
}
}
self.addEventListener('message', function(e) {
url = e.data.url;
token = e.data.id;
file.push(e.data.files);
if (p) {
process();
}
});
I've got an array of URLs [URL1, URL2, URL3,...] : each element is a link to one of the chunks of the same file. Each chunk is separately encrypted, with the same key as all the other chunks.
I download each chunk (in a forEach function) with a XMLHttpRequest. onload :
each chunk is first decrypted
then each chunk is converted to an ArrayBuffer (source)
each ArrayBuffer is pushed to an array (source)
when the three first steps are done for each chunk (callback by a var incremented on step#1 === the array.length), a blob is constructed with the array
the blob is saved as file with FileReader API & filesaver.js
If it's a one chunk's file, everything works fine.
But with multiple chunks, steps #1 & #2 are ok, but only the last ArrayBuffer seems to be pushed to the array. What am I missing?
Below my code
// var for incrementation in forEach funtion
var chunkdownloaded = 0;
// 'clearfileurl' is the array of url's chunks :[URL1, URL2, URL3,...]
clearfileurl.forEach(function(entry) {
var xhr = new XMLHttpRequest();
var started_at = new Date();
xhr.open('GET', entry, true);
xhr.responseType = 'text';
// request progress
xhr.onprogress = function(pe) {
if (pe.lengthComputable) {
downloaderval.set((pe.loaded / pe.total) * 100);
}
};
// on request's success
xhr.onload = function(e) {
if (this.status == 200) {
chunkdownloaded+=1;
var todecrypt = this.response;
// decrypt request's response: get a dataURI
try {
var bytesfile = CryptoJS.AES.decrypt(todecrypt.toString(), userKey);
var decryptedfile = bytesfile.toString(CryptoJS.enc.Utf8);
} catch(err) {
console.log (err);
return false;
}
//convert a dataURI to a Blob
var MyBlobBuilder = function() {
this.parts = [];
}
MyBlobBuilder.prototype.append = function(dataURI) {
//function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
// var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
this.parts.push(ab);
console.log('parts', this.parts)
this.blob = undefined; // Invalidate the blob
}
MyBlobBuilder.prototype.getBlob = function() {
if (!this.blob) {
console.log (this.parts);
this.blob = new Blob(this.parts);
}
return this.blob;
};
var myBlobBuilder = new MyBlobBuilder();
myBlobBuilder.append(decryptedfile);
// if all chunks are downloaded
if (chunkdownloaded === clearfileurl.length) {
// get the blob
var FinalFile = myBlobBuilder.getBlob();
// launch consturction of a file with'FinalFile' inside FileReader API
var reader = new FileReader();
reader.onload = function(e){
// build & save on client the final file with 'file-saver' library
var FileSaver = require('file-saver');
var file = new File([FinalFile], clearfilename, {type: clearfiletype});
FileSaver.saveAs(file);
};
reader.readAsText(FinalFile);
} else {
console.log('not yet');
}
}
};
// sending XMLHttpRequest
xhr.send();
});
You need to take out the declaration of MyBlobBuilder, try this:
// var for incrementation in forEach funtion
var chunkdownloaded = 0;
//convert a dataURI to a Blob
var MyBlobBuilder = function() {
this.parts = [];
}
MyBlobBuilder.prototype.append = function(dataURI, index) {
//function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
// var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
this.parts[index] = ab;
console.log('parts', this.parts)
this.blob = undefined; // Invalidate the blob
}
MyBlobBuilder.prototype.getBlob = function() {
if (!this.blob) {
console.log (this.parts);
this.blob = new Blob(this.parts);
}
return this.blob;
};
var myBlobBuilder = new MyBlobBuilder();
// 'clearfileurl' is the array of url's chunks :[URL1, URL2, URL3,...]
clearfileurl.forEach(function(entry, index) {
var xhr = new XMLHttpRequest();
var started_at = new Date();
xhr.open('GET', entry, true);
xhr.responseType = 'text';
// request progress
xhr.onprogress = function(pe) {
if (pe.lengthComputable) {
downloaderval.set((pe.loaded / pe.total) * 100);
}
};
// on request's success
xhr.onload = function(e) {
if (this.status == 200) {
chunkdownloaded+=1;
var todecrypt = this.response;
// decrypt request's response: get a dataURI
try {
var bytesfile = CryptoJS.AES.decrypt(todecrypt.toString(), userKey);
var decryptedfile = bytesfile.toString(CryptoJS.enc.Utf8);
} catch(err) {
console.log (err);
return false;
}
myBlobBuilder.append(decryptedfile, index);
// if all chunks are downloaded
if (chunkdownloaded === clearfileurl.length) {
// get the blob
var FinalFile = myBlobBuilder.getBlob();
// launch consturction of a file with'FinalFile' inside FileReader API
var reader = new FileReader();
reader.onload = function(e){
// build & save on client the final file with 'file-saver' library
var FileSaver = require('file-saver');
var file = new File([FinalFile], clearfilename, {type: clearfiletype});
FileSaver.saveAs(file);
};
reader.readAsText(FinalFile);
} else {
console.log('not yet');
}
}
};
// sending XMLHttpRequest
xhr.send();
});
*edit I also updated the append function to ensure that the files are in the correct order
I am developing a web application in which application downloads the encrypted chunks of data. And after then I have to decrypt and play the video. But I cannot let the user to wait for all decryption. Hence I am using Media Stream API. It is working. But I am getting this error after decryption of last chunk.
"Uncaught DOMException: Failed to execute 'addSourceBuffer' on 'MediaSource': This MediaSource has reached the limit of SourceBuffer objects it can handle. No additional SourceBuffer objects may be added.(…)"
<script type="text/javascript">
//////////
var no_of_files = 0;
var no_of_dlfiles = 0;
var FilesURL = [];
var files_str = 'video/vid_1.webm, video/vid_2.webm, video/vid_3.webm, video/vid_4.webm, video/vid_5.webm';
var file_counter = 0;
var mimeCodec = 'video/webm; codecs="vorbis,vp8"';
var passkey = "014bcbc0e15c4fc68b098f9b16f62bb7shahbaz.hansinfotech#gmail.com";
FilesURL = files_str.split(',');
no_of_files = FilesURL.length;
var player = document.getElementById('videoplayer');
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
player.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
//////////
function sourceOpen (_) {
console.log("start");
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
sourceBuffer.mode = "sequence";
function WriteDatatoTemp()
{
//console.log(this.readyState); // open
if(file_counter<FilesURL.length)
{
console.log(file_counter);
no_of_dlfiles++;
$("#decryptionRatio").text(no_of_dlfiles+" of "+no_of_files);
$("#decryption_status").show();
getFileObject(FilesURL[file_counter], function (fileObject) {
//
var outputFile = fileObject;
var reader = new FileReader();
reader.onloadend = function(e){
var decrypted_data = JSON.parse(CryptoJS.AES.decrypt(e.target.result, passkey, {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));
var byteArray = Base64Binary.decodeArrayBuffer(decrypted_data);
sourceBuffer.addEventListener('updateend', function(){
file_counter++;
// console.log(file_counter);
if(player.paused)
{
player.play();
}
if(file_counter == FilesURL.length - 1)
{
mediaSource.endOfStream();
}
WriteDatatoTemp();
});
try
{
while(!sourceBuffer.updating)
{
sourceBuffer.appendBuffer(byteArray);
}
}
catch(e)
{
console.log(e);
}
};
reader.readAsText(outputFile);
//
});
}
}
WriteDatatoTemp();
}
///
var getFileBlob = function (url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function (blob) {
cb(blobToFile(blob, 'vid.webm'));
});
};
</script>
I'm wondering how to upload file onto Firebase's storage via URL instead of input (for example). I'm scrapping images from a website and retrieving their URLS. I want to pass those URLS through a foreach statement and upload them to Firebase's storage. Right now, I have the firebase upload-via-input working with this code:
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var file = evt.target.files[0];
var metadata = {
'contentType': file.type
};
// Push to child path.
var uploadTask = storageRef.child('images/' + file.name).put(file, metadata);
// Listen for errors and completion of the upload.
// [START oncomplete]
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var url = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', url);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';}
Question what do I replace
var file = evt.target.files[0];
with to make it work with external URL instead of a manual upload process?
var file = "http://i.imgur.com/eECefMJ.jpg"; doesn't work!
There's no need to use Firebase Storage if all you're doing is saving a url path. Firebase Storage is for physical files, while the Firebase Realtime Database could be used for structured data.
Example . once you get the image url from the external site this is all you will need :
var externalImageUrl = 'https://foo.com/images/image.png';
then you would store this in your json structured database:
databaseReference.child('whatever').set(externalImageUrl);
OR
If you want to actually download the physical images straight from external site to storage then this will require making an http request and receiving a blob response or probably may require a server side language ..
Javascript Solution : How to save a file from a url with javascript
PHP Solution : Saving image from PHP URL
This answer is similar to #HalesEnchanted's answer but with less code. In this case it's done with a Cloud Function but I assume the same can be done from the front end. Notice too how createWriteStream() has an options parameter similar to bucket.upload().
const fetch = require("node-fetch");
const bucket = admin.storage().bucket('my-bucket');
const file = bucket.file('path/to/image.jpg');
fetch('https://example.com/image.jpg').then((res: any) => {
const contentType = res.headers.get('content-type');
const writeStream = file.createWriteStream({
metadata: {
contentType,
metadata: {
myValue: 123
}
}
});
res.body.pipe(writeStream);
});
Javascript solution to this using fetch command.
var remoteimageurl = "https://example.com/images/photo.jpg"
var filename = "images/photo.jpg"
fetch(remoteimageurl).then(res => {
return res.blob();
}).then(blob => {
//uploading blob to firebase storage
firebase.storage().ref().child(filename).put(blob).then(function(snapshot) {
return snapshot.ref.getDownloadURL()
}).then(url => {
console.log("Firebase storage image uploaded : ", url);
})
}).catch(error => {
console.error(error);
});
Hopefully this helps somebody else :)
// Download a file form a url.
function saveFile(url) {
// Get file name from url.
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
xhr.addEventListener("abort", transferCanceled);
xhr.responseType = 'blob';
xhr.onload = function() {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
delete a;
if (this.status === 200) {
// `blob` response
console.log(this.response);
var reader = new FileReader();
reader.onload = function(e) {
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
var metadata = {
'contentType': 'image/jpeg'
};
var file = e.target.result;
var base64result = reader.result.split(',')[1];
var blob = b64toBlob(base64result);
console.log(blob);
var uploadTask = storageRef.child('images/' + filename).put(blob, metadata);
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var download = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', download);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';
// [END_EXCLUDE]
});
// `data-uri`
};
reader.readAsDataURL(this.response);
};
};
xhr.open('GET', url);
xhr.send();
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
function transferComplete(evt) {
window.onload = function() {
// Sign the user in anonymously since accessing Storage requires the user to be authorized.
auth.signInAnonymously().then(function(user) {
console.log('Anonymous Sign In Success', user);
document.getElementById('file').disabled = false;
}).catch(function(error) {
console.error('Anonymous Sign In Error', error);
});
}
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}