How can I save canvas as image to Firebase storage? - javascript

I'm trying to save canvas as an image to the firebase storage. I have read many articles and questions about saving canvas to server, and tried to implement the same with the below code.
function server(){
canvas = document.getElementById("c");
var storageRef = firebase.storage().ref();
var mountainsRef = storageRef.child('mountains.jpg');
var image = new Image();
image.src = canvas.toDataURL("image/png");
var uploadTask = storageRef.child('images/' + "apple").put(image);
uploadTask.on('state_changed', function(snapshot){
// Observe state change events such as progress, pause, and resume
// See below for more detail
}, function(error) {
// Handle unsuccessful uploads
}, function() {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
var downloadURL = uploadTask.snapshot.downloadURL;
});
}
But when I run the web app, the console shows error:
FirebaseError: Firebase Storage: Invalid argument in put at index 0: Expected Blob or File.
How can I successfully save a canvas to Firebase storage?

Yes this is possible. The problem you are having is that you are trying to upload a dataUrl but firebase's put function only excepts blobs or files. To convert a canvas to a blob use the toBlob function.
canvas.toBlob(function(blob){
var image = new Image();
image.src = blob;
var uploadTask = storageRef.child('images/' + "apple").put(blob);
});
Edit: changed var uploadTask = storageRef.child('images/' + "apple").put(image); to var uploadTask = storageRef.child('images/' + "apple").put(blob);
Also not sure if this will work in your case when i tried it I got a tainted canvas error.
What worked for me was the answer to this question How to convert dataURL to file object in javascript?

Related

Load Image/Video from IndexedDB

I am working on a PWA project where I have created an IndexedDB and stored the images and videos in it. On the next reload of page, if image/video is available in IndexedDB, it should load it from there.
function fetchMedia(id) {
var transaction = db.transaction(["media"]);
var objectStore = transaction.objectStore("media");
var request = objectStore.get(id);
request.onerror = function(event) {
console.log("Unable to retrieve daa from database!");
return "";
};
request.onsuccess = function(event) {
var imgFile = request.result;
console.log(imgFile)
var imgURL = window.URL.createObjectURL(imgFile);
return imgURL;
};
}
It always returns undefined.
When I console.log the imgFile, it shows that it's there in the IndexedDB:
File in IndexedDB:
I have also tried this but no success yet:
var imgURL = window.URL.createObjectURL(new Blob(imgFile, {'type': 'application/octet-stream'}));
What's the correct approach to load the files from IndexedDB?
If your screenshot is accurate, then request.result is not an image, it's an object {id: '13388-7247-6247-62584', file: Blob, ...}. You didn't just store the image file, you wrapped it in an object. So what you're getting back out is an object.
Try imgFile = request.result.file; instead.
You cannot return inside the callback, you should wrap it in a promise.

How to Convert image URL from server (API / ImageURL) to Base64 in Vue.Js

A lot of reference I see about this problem is about upload file and convert to base64 but in my case I want to convert an Image URL from server and convert it to base64 but I still failed to do it, right now I tried it like this, but it still failed since it doesn't show anything
this is my html:
<div v-if="questionData">
<img class="img-preview-download" :src="questionData.image_url? getBase64Image(questionData.image_url) : 'https://via.placeholder.com/640x360'" alt="img-preview">
</div>
this is my method:
getBase64Image(img) {
console.log("cek base64 : ", btoa(img));
return `data:image/jpeg;base64,${btoa(img)}`;
},
I read some using file reader but isn't it only for file when you upload a data using input? can someone help me to solve this? I'm using Vue.Js for the framework
when I used this method I got result like this:
So this is my answer for my future self, who might be forget and stumble again in this problem!
You can solve it by making a new image and inside that image file, you can add your src so the image can be process when still loading or onload.
Remember!
Since it is you, You might be remove the last image.src = url to get a clean code, but this is important, if you remove that line, image.onload will not be trigger because it will search for the image source. and if you try to use image.srcObject to put it with mediaStream it will give you Resolution Overloaded since you still not find the answer for this problem, it is okay, you can use the image first since your step is to achieve how to get file from Image URL. so this is the method you use to solve this problem:
downloadPreview() {
const el = this.$refs.printMe;
const options = {
type: 'dataURL'
};
this.$html2canvas(el, options).then(data => {
this.output = data;
const a = document.createElement('a');
a.style.display = 'none';
a.href = data;
// this is just optional function to download your file
a.download = `name.jpeg`;
document.body.appendChild(a);
a.click();
});
},
convertImgUrlToBase64(url) {
let self = this;
var image = new Image();
image.setAttribute('crossOrigin', 'anonymous'); // use it if you try in a different origin of your web
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext('2d').drawImage(this, 0, 0);
canvas.toBlob(
function(source) {
var newImg = document.createElement("img"),
url = URL.createObjectURL(source);
newImg.onload = function() {
// no longer need to read the blob so it's revoked
URL.revokeObjectURL(url);
};
newImg.src = url;
},
"image/jpeg",
1
);
// If you ever stumble at 18 DOM Exception, just use this code to fix it
// let dataUrl = canvas.toDataURL("image/jpeg").replace("image/jpeg", "image/octet-stream");
let dataUrl = canvas.toDataURL("image/jpeg");
console.log("cek inside url : ", url);
if(url === backgroundImg) {
self.assignImageBase64Background(dataUrl);
} else {
self.assignImageBase64(dataUrl);
}
};
image.src = url;
},
assignImageBase64(img) {
this.imgBase64 = img;
},
just for information, I use this library to change the div into image file:
vue-html2canvas
Notes:
If you ever wondering why I give self.assignImageBase64(dataUrl); this function in the end, this is because I still wondering how onload works, and how to return Base64 url to the parent thats why I just assign it again in another function since it easier to do.

Node.js createWriteStream 'finish' called late

I have a Google Cloud Function hosted on Firebase which takes an image URL from Twilio and, using pipe(), uploads the image to a bucket on GCS. This works, however I want to call another function once the image has been successfully uploaded. I have a .on('finish') to trigger another function, however in looking at logs, it appears the finish is being called almost a minute after the file has actually finished uploading. I can physically see the image in my GCS console well before the finish function is called.
What might be the cause of this delay?
const mediaUrl = request.body.MediaUrl0;
const contentType = request.body.MediaContentType0;
const extension = mime.extension(contentType);
global.filename = Date.now() + "." + extension;
console.log("Filename: " + filename);
//Save image to gcs bucket
const gc = new Storage({
projectID: 'testProject-rgjdxr'
});
const bucketName = 'msg-images';
const bucket = gc.bucket(bucketName);
const file = bucket.file(filename);
const w = file.createWriteStream({
metadata:{
contentType: contentType
}
});
pollRequest(mediaUrl).auth(accountSid, authToken).pipe(w).on('finish', () => {
global.gcsUrl = `https://storage.cloud.google.com/${bucketName}/${filename}`;
console.log(gcsUrl);
//I can see this log, however the timestamp is about 60sec
//after the file was uploaded successfully to GCS bucket.
analyzeImage(gcsUrl); //passing image url to another function
});

Upload file to AWS S3 using REST API Javascript

I am trying to retrieve a file from the user's file system and upload it to AWS S3. However, I have had no success thus far doing so. To be more specific, I have been working with trying to upload images. So far the images won't render properly whenever I upload them. I am really only familiar with uploading images as Blobs, but since SHA256 function can't read a Blob I'm unsure what to do. Below is my code:
var grabFile = new XMLHttpRequest();
grabFile.open("GET", 'https://s3.amazonaws.com/'+bucketName+'/asd.jpeg', true);
grabFile.responseType = "arraybuffer";
grabFile.onload = function( e ) {
var grabbedFile = this.response;
var arrayBufferView = new Uint8Array( this.response );
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
var base64data = '';
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
//var readData = reader.result;
var readData = blob;
//readData = readData.split(',').pop();
console.log(readData);
console.log(readData.toString());
var shaString = CryptoJS.SHA256(readData.toString()).toString();
var request = new XMLHttpRequest();
var signingKey = getSigningKey(dateStamp, secretKey, regionName, serviceName);
var headersList = "content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date";
var time = new Date();
time = time.toISOString();
time = time.replace(/:/g, '').replace(/-/g,'');
time = time.substring(0,time.indexOf('.'))+"Z";
var canonString = "PUT\n"+
"/asd5.jpeg\n"+
"\n"+
//"content-encoding:base64\n"+
"content-type:image/jpeg\n"+
"host:"+bucketName+".s3.amazonaws.com\n"+
'x-amz-acl:public-read\n'+
'x-amz-content-sha256:'+shaString+"\n"+
'x-amz-date:'+time+'\n'+
'\n'+
headersList+'\n'+
shaString;
var stringToSign = "AWS4-HMAC-SHA256\n"+
time+"\n"+
dateStamp+"/us-east-1/s3/aws4_request\n"+
CryptoJS.SHA256(canonString);
var authString = CryptoJS.HmacSHA256(stringToSign, signingKey).toString();
var auth = "AWS4-HMAC-SHA256 "+
"Credential="+accessKey+"/"+dateStamp+"/"+regionName+"/"+serviceName+"/aws4_request, "+
"SignedHeaders="+headersList+", "+
"Signature="+authString;
request.open("PUT", "https://"+bucketName+".s3.amazonaws.com/asd5.jpeg", true);
request.setRequestHeader("Authorization", auth);
//request.setRequestHeader("content-encoding", "base64");
request.setRequestHeader("content-type", "image/jpeg");
request.setRequestHeader('x-amz-acl', 'public-read');
request.setRequestHeader("x-amz-content-sha256", shaString);
request.setRequestHeader("x-amz-date", time);
request.send(readData.toString());
console.log(request);
How do I go about doing this? The code above just uploads something that's just a few Bytes because blob.toString() comes out as [Object Blob] and that's what gets uploaded. If I don't toString() it, I get an error from my SHA256 function.
As you can see, I tried reading it as Base64 before uploading it, but that did not resolve my problem either. This problem has been bugging me for close to a week now and I would love to get this solved. I've tried changing content-type, changed the body of what I'm uploading, etc. but nothing has worked.
EDIT: Forgot to mention (even though the title should imply it) but I cannot use the SDK for this. I was using it at one point, and with it I was able to upload images as Blobs. So I know this is possible, it's just that I don't know what crafty thing the SDK is doing to upload it.
EDIT2: I found the solution just in case someone stumbles across this in the future. Try setting replace every place I have shaString with 'UNSIGNED PAYLOAD' and send the blob and it will work! Here's where I found it: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html

Upload a photo to Firebase Storage with Image URI

I am currently attempting to upload a photo to my Firebase app's storage in my Apache Cordova app. I currently get the photo's URI with the following code:
function getPhotoFromAlbum() {
navigator.camera.getPicture(onPhotoURISuccess, onFail, {
quality: 50,
sourceType: navigator.camera.PictureSourceType.SAVEDPHOTOALBUM,
destinationType: navigator.camera.DestinationType.FILE_URI
});
}
function onPhotoURISuccess(imageURI) {
var image = document.getElementById('image');
image.style.display = 'block';
image.src = imageURI;
getFileEntry(imageURI);
}
And then am attempting to convert the image into a file and push it to my Firebase storage with the following function:
function getFileEntry(imgUri) {
window.resolveLocalFileSystemURL(imgUri, function success(fileEntry) {
console.log("got file: " + fileEntry.fullPath);
var filename = "test.jpg";
var storageRef = firebase.storage().ref('/images/' + filename);
var uploadTask = storageRef.put(fileEntry);
}, function () {
// If don't get the FileEntry (which may happen when testing
// on some emulators), copy to a new FileEntry.
createNewFileEntry(imgUri);
});
}
I have both the file and the camera cordova plugins installed, the only errors I get when I attempt to do this is
Error in Success callbackId: File1733312835 : [object Object]
Which is just an error message from cordova.js
I also know I have my Firebase storage set up correctly because I have tested it through an emulator by adding a file input and successfully uploading whatever file the user added, to the Firebase storage.
Is it possible to upload a file to Firebase storage using this method of converting an image to a file through its URI, and then uploading it? If so, what is the correct way to do so / what is wrong with the way i'm doing it?
I was able to accomplish uploading an image by using a data url. Below is my code:
var filename = "test.jpg";
var storageRef = firebase.storage().ref('/images/' + filename);
var message = 'data:image/jpg;base64,' + imageUri;
storageRef.putString(message, 'data_url').then(function (snapshot) {
console.log('Uploaded a data_url string!');
});
Is it possible to upload a file to Firebase storage using this method of converting an image to a file through its URI, and then uploading it? If so, what is the correct way to do so / what is wrong with the way i'm doing it?
Yes it is possible to upload a file on firebase through its URI. However you have to follow the correct way.
1. You have to store the data in firebase after file reading operation is completed.you can use FileReader.onloadend for this.
2. By using a data_url you can store to firebase.
Here is the snippet for more clarity:
function getFileEntry(imgUri) {
window.resolveLocalFileSystemURL(imgUri, function onSuccess(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function() {
filename = "test.jpg";
var storageRef = firebase.storage().ref('/images/' + filename);
var data = 'data:image/jpg;base64,' + imgUri;
storageRef.putString(data, 'data_url').then(function (snapshot) {
console.log('Image is uploaded by base64 format...');
});
};
reader.readAsArrayBuffer(file);
});
},
function onError(err) {
console.log(err);
createNewFileEntry(imgUri);
});
}

Categories

Resources