Convert image extracted from URL to base64 - javascript

I am fetching the user's Facebook profile picture whenever they login via Facebook. I want to convert the image to base 64 from the URL. What would be the best way of doing this, while ensuring that the user can still see their profile picture in the view (home.view)? At the moment, I am directly referring to the URL.
This is my code so far:
facebook.service.js
function FacebookService($http, config) {
this.getUserPicture = function(userId, token) {
return $http({
method: 'GET',
url: 'https://graph.facebook.com/' + userId + '/picture?type=large&redirect=false'
})
}
}
home.controller.js
function HomeController($scope, $cordovaNativeStorage, FacebookService, $ionicLoading) {
if (window.cordova) {
// Get Facebook access token
$cordovaNativeStorage.getItem("facebookAccessToken").then(function(value) {
$scope.facebookAccessToken = value
// Get Facebook user picture (currently stored as a URL, would want to store it as a base 64 string which can be displayed as an image
FacebookService.getUserPicture($scope.facebookUserData.id).then(function(dataResponse) {
$scope.facebookUserPicture = dataResponse.data;
// Save Facebook user picture
$cordovaNativeStorage.setItem("facebookUserPicture", $scope.facebookUserPicture).then(function() {}, function(error) {
console.error("Unable to cache user data: " + result);
$ionicLoading.show({
template: 'Unable to cache user data',
duration: 1500
})
});
}, function(error) {
console.log(error.data.error.message)
})
}, function(error) {
console.log(error.data.error.message)
})
}
};
home.view.js
<img class="icon icon-home img-circle" ng-src="{{ facebookUserPicture.data.url }}">

There's a method to do it via canvas (source):
var convertImgToDataURLviaCanvas = function(url, callback) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL();
callback(dataURL);
canvas = null;
};
img.src = url;
}
convertImgToDataURLviaCanvas( 'http://some.com/images/1.jpg', function( base64_data ) {
console.log( base64_data );
} );

You can use this helper function to fetch a url and convert into dataURI.
function getDataUri(url, callback) {
var image = new Image();
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(this, 0, 0);
// Get raw image data
callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, ''));
// ... or get as Data URI
callback(canvas.toDataURL('image/png'));
};
image.src = url;
}
Usage :
getDataUri($scope.facebookUserPicture.url, function(dataUri) {
// here you can set it up as the img src for the profile picture
$scope.profilePictureUri = dataUri;
});
You can also define this as a promise instead of a call back.
And finally, <img class="icon icon-home img-circle" ng-src="{{profilePictureUri}}">
Read more on this wonderful article by David Walash

This will fetch any resource as a blob and use filereader to convert it to a base64 data url. If you where to use canvas#toDataURL you would not get the same base64...
var blob = new Blob(['Simulate a url'])
var url = URL.createObjectURL(blob)
console.log("original blob size", blob.size)
fetch(url)
.then(res => res.blob())
.then(blob => {
var fr = new FileReader()
fr.onload = () => {
var b64 = fr.result
console.log(b64)
console.log("base64 size: ", b64.length)
$iframe.src = b64
}
fr.readAsDataURL(blob)
})
<iframe id="$iframe"></iframe>
There is better way to solve this problem and that is to store the raw binary you got in some way as a blob. Base64 is going to take up ~3x more data and since javascript string are utf16 it's going to take up 2x more memory...
Some good alternetives are indexedDB and Sandboxed Filesystem API

Related

Save the blob url image from using viewer.screenshot() to server/database

I used forge viewer api. Viewer.screenshot() to get the image of a component. It returns a blob url as the image. E.g “blob:localhost:3000/afdijhejsbjdjd”. But I need to save this image to my local server, how can I achieve this? Using Nodejs.
How can I change this blob url to a transferable image url?
We can convert the image Blob URL to a based64 encoded string like the below, and then
function getScreenShotImageBase64(viewer, width, height) {
return new Promise((resolve) => {
viewer.getScreenShot(width, height, blobURL => {
let img = new Image();
let tmpCanvas = document.createElement('canvas');
let ctx = tmpCanvas.getContext('2d');
tmpCanvas.width = width;
tmpCanvas.height = height;
img.onload = function() {
// draw viewer image on canvas
ctx.drawImage(img, 0, 0, width, height);
resolve(tmpCanvas.toDataURL('image/png'));
};
img.src = blobURL;
});
});
}
let imageBase64 = await getScreenShotImageBase64(viewer, viewer.container.offsetWidth, viewer.container.offsetHeight);
Here is the preview of the result:
Afterward, send the base64 string to your backend server, and then you can either save the image base64 string to your database,
Or resave the base64 string to file. For example in nodejs.
fs.writeFileSync(path.join(uploadPath, fileName), new Buffer(base64, 'base64'))
ref: How to upload image using Base64 string in NodeJs

Convert Link from Image URL from s3 into File Object using JavaScript

I want to convert my s3 image link into a file object using JavaScript.
I've found out how to do this with an image URI but wasn't able to figure out how to convert the image URL into a URI. Once I do this I could convert it into a file object
Heres the image link:
http://s3.us-east-2.amazonaws.com/rentpop/298%2F2014-mclaren-650s-Spyder-Tarocco-Orange-2.jpg
Source for this code
function getDataUri(url, callback) {
var image = new Image();
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(this, 0, 0);
// Get raw image data
callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, ''));
// ... or get as Data URI
callback(canvas.toDataURL('image/png'));
};
image.src = url;
}
// Usage
getDataUri('local_location_to_image.extension', function(dataUri) {
// Do whatever you'd like with the Data URI!
});

Javascript: How to save file location to local storage?

In Javascript (w/ Angular 2+) I have an app where I am trying to save a dataURl to localstorage once it has been picked by a user. Currently I have tried the following code but on retrieval I get an empty obj {} as the body.
HTML
<input style="display:none;" type="file" (change)="fileEvent($event)" #file>
Angular File Storage and Retrieval Function
fileEvent(ev: any): void {
console.log('Event select file', ev);
let obj: any = ev.target.files[0];
let file: File = {
Key: obj.name,
ContentType: obj.type,
Size: obj.size,
Body: obj
};
localStorage.setItem("myapp", JSON.stringify(file);
}
getFileFromLocalStorage {
console.log(JSON.parse(localStorage.getItem("myapp"));
}
File Retrieval Response below
You can not store image directly to localstorage like this. First you need to convert the image to Base64. Then save the Base64 string in localStorage value.
Below is function to convert Image into Base64:
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
Now you can save this to your local storage.
Here is the reference answer on SO.

Save base64 encoded image to Firebase Storage

Using firebase 3.0.x, is it possible to save a base64 encoded image to the new Firebase Storage service?
I am using canvas to resize images in the browser prior to uploading them, and output them as a base64 jpeg. I know that the Storage api can accept Blobs, but IE9 support is needed for my current project.
You only need to use the putString function without converting the BASE64 to blob.
firebase.storage().ref('/your/path/here').child('file_name')
.putString(your_base64_image, ‘base64’, {contentType:’image/jpg’});
Make sure to pass the metadata {contentType:’image/jpg’} as the third parameter (optional) to the function putString in order for you to retrieve the data in an image format.
or simply put:
uploadTask = firebase.storage().ref('/your/path/here').child('file_name').putString(image, 'base64', {contentType:'image/jpg'});
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
function(snapshot) {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log('Upload is paused');
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log('Upload is running');
break;
}
}, function(error) {
console.log(error);
}, function() {
// Upload completed successfully, now we can get the download URL
var downloadURL = uploadTask.snapshot.downloadURL;
});
You can then use the downloadURL to save to firebase.database() and/or to put as an src to an <img> tag.
The latest version of the Firebase SDK supports base64 image uploads. Simply use the putString method from Firebase Storage.
https://firebase.google.com/docs/reference/js/firebase.storage
One small caveat is that sometimes you'll have a base64 String with unnecessary whitespace. For example, I've found that the cordova Camera plugin returns base64 with unnecessary whitespace. The Storage SDK will fail to upload this because JavaScript can't perform it's native atob function - something the Firebase JS does under the hood. You'll have to strip the whitespace - see DOM Exception 5 INVALID CHARACTER error on valid base64 image string in javascript
Yes, it's possible now. You should use Firebase Storage new method called putString. You may read spec here.
So, Firebase spec says that you have now two methods to store Base64 string and Base64url string:
// Base64 formatted string
var message = '5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
ref.putString(message, 'base64').then(function(snapshot) {
console.log('Uploaded a base64 string!');
});
// Base64url formatted string
var message = '5b6p5Y-344GX44G-44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
ref.putString(message, 'base64url').then(function(snapshot) {
console.log('Uploaded a base64url string!');
})
From my experience, using putString(message, 'base64url') constantly returns Error about bad formated Base64 string code: "storage/invalid-format", message: "Firebase Storage: String does not match format 'base64': Invalid character found". The solution is to cut off beginning of string data:image/jpeg;base64, and use first method instead putString(message, 'base64'). Then it works.
If you use canvas.toBlob() you'll get the byte[] that you need to pass into Firebase Storage.
Quick example:
function save() {
var canvas = document.getElementById("canvas");
canvas.toBlob(blob => {
var storage = firebase.app().storage().ref();
var name = id + "/" + (new Date()).getTime() + ".png";
var f = storage.child("drawings/" + name);
var task = f.put(blob);
task.on('state_changed', function(snapshot) {
}, function(error) {
console.error("Unable to save image.");
console.error(error);
}, function() {
var url = task.snapshot.downloadURL;
console.log("Saved to " + url);
var db = firebase.database();
var chats = db.ref().child("chats");
chats.child(id).child("drawingURL").set(url);
});
});
};
Otherwise you'll have to convert the base64 yourself, for example with atob().
Here are two values I use to help with support on .toBlob() it is less performant however, it gets the job done.
This method takes in the base64 string, the content type (IE: image/png) and a callback for when the blob has been constructed using atob()
var b64_to_blob = function(b64_data, content_type, callback) {
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});
callback(blob);
};
I use this method to get the base64 value of a direct link when necessary, In my case it's to download a users Facebook photo when they register on my application.
var image_link_to_b64 = function(url, content_type, callback) {
var image = new Image();
image.crossOrigin = 'Anonymous';
image.onload = function() {
var canvas = document.createElement('CANVAS');
var context = canvas.getContext('2d');
var data_url;
canvas.height = this.height;
canvas.width = this.width;
context.drawImage(this, 0, 0);
data_url = canvas.toDataURL(content_type);
data_url = data_url.substr(22);
callback(data_url);
canvas = null;
};
image.src = url;
};
Below is how it looks when adding the information to firebase storage
$fileService.image_link_to_b64(facebook_info.photoURL + '?width=512&height=512', 'image/png', function(b64) {
$fileService.b64_to_blob(b64, 'image/png', function(blob) {
$fileService.upload_user_photo(blob, 'image/png', function(url) {
// Firebase storage download url here
}
}
}
Incase you're wondering upload_user_photo simply uploads to firebase storage:
var upload_user_photo = function(data, blob, callback) {
var upload_task = user_photo_reference.child('user_photo').put(data);
upload_task.on('state_changed', function(snapshot) {
}, function(error) {
alert('error: ', error);
}, function() {
callback(upload_task.snapshot.downloadURL);
});
};]
For IE9 see this polyfill: https://github.com/eligrey/Blob.js/blob/master/Blob.js
This solution works for me using the Google Cloud Storage API.
But it should work also with the Firebase one by replacing the file.save with the ref put method.
const file = storage.file(file_path_in_gs)
const contents = new Uint8Array(Buffer.from(base64ImgStr, 'base64'))
file.save(contents,
{
contentType: img_type,
metadata: {
metadata: {
contentType: img_type,
firebaseStorageDownloadTokens: uuid()
}
}
}
, () => { })
With Firebase SDK 9 for web (as of May 2022)
import { getStorage, ref, uploadString } from "firebase/storage";
const storage = getStorage();
const storageRef = ref(storage, 'some-child');
// Data URL string
const message4 = 'data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
uploadString(storageRef, message4, 'data_url').then((snapshot) => {
console.log('Uploaded a data_url string!');
});

Adding raw SVG code to HTML Canvas

Earlier this day, I have succeed in converting SVG file to JPEG using javascript. The main steps are:
Get SVG image from a url
Add image to HTML5 Canvas
Convert the Canvas to JPEG encoded in base64
I replicate the getImageFromUrl function on jsPDF-master to achieve this.
var getImageFromUrl = function (url, callback) {
var img = new Image,
data, ret = {
data: null,
pending: true
};
img.onError = function () {
throw new Error('Cannot load image: "' + url + '"');
}
img.onload = function () {
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// Grab the image as a jpeg encoded in base64, but only the data
data = canvas.toDataURL('image/jpeg').slice('data:image/jpeg;base64,'.length);
// Convert the data to binary form
data = atob(data)
document.body.removeChild(canvas);
ret['data'] = data;
ret['pending'] = false;
if (typeof callback === 'function') {
callback(data);
}
}
img.src = url;
return ret;
}
From that function, the image to be converted is actually a file. In my case, I don't have a file but only the raw code (text when you open a SVG file with text editor).
My question is:
How do you add raw code of a SVG file into the HTML canvas? Is this process also have .onload event attribute like image object?
Thank you
You can convert a "raw" (inline) SVG to image by converting it to a Blob and then use that as an image source:
function drawInlineSVG(ctx, rawSVG, callback) {
var
/// create Blob of inlined SVG
svg = new Blob([rawSVG], {type:"image/svg+xml;charset=utf-8"}),
/// create URL (handle prefixed version)
domURL = self.URL || self.webkitURL || self,
url = domURL.createObjectURL(svg),
/// create Image
img = new Image;
/// handle image loading
img.onload = function () {
/// draw SVG to canvas
ctx.drawImage(this, 0, 0);
domURL.revokeObjectURL(url);
callback(this);
};
img.src = url;
}
Then call it like this:
var rawSVG = '<svg ... >';
drawInlineSVG(ctx, rawSVG, function(img) {
console.log('done!');
});
An error handler should of course be included for production code (not shown here).
Important to note: You cannot draw inline SVG's if they contain external references (CSS styles, images and so on). This is due to browser's security policies. You would have to convert all external references to inline data (ie. images to data-uris and so on).

Categories