Pretty much what the post says. I don't want to use an async option and can't seem to find any out of the box cloudinary transformation that will do something like cloudinaryImg/transform_toBase64,w_20,h_20/123.jpg (this is an example). This also needs to be on the front end.
Also most of the javascript options seem to only do async.
You can generate the base64 of the image using its URL.
Here are some resources -
How can I convert an image into Base64 string using JavaScript?
https://base64.guru/developers/javascript/examples/convert-image
Here is a simple example influenced by the one given here -
var url = 'https://res.cloudinary.com/demo/image/upload/sample.jpg';
var xhr = new XMLHttpRequest();
xhr.onload = function () {
// Create a Uint8Array from ArrayBuffer
var codes = new Uint8Array(xhr.response);
// Get binary string from UTF-16 code units
var bin = String.fromCharCode.apply(null, codes);
// Convert binary to Base64
var b64 = btoa(bin);
console.log(b64);
};
// Send HTTP request and fetch file as ArrayBuffer
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.send();
Related
When using web.whatsapp.de one can see that the link to a recieved image may look like this:
blob:https://web.whatsapp.com/3565e574-b363-4aca-85cd-2d84aa715c39
If the link is copied in to an address window it will open up the image, however - if "blob" is left out - it will simply open a new web whatsapp window.
I am trying to download the image displayed by this link.
But using common techniques such as using request, or urllib.request or even BeautifulSoup always struggle at one point: The "blob" at the beginning of the url will throw an error.
These answers Download file from Blob URL with Python will trhow either the Error
URLError: <urlopen error unknown url type: blob>
or the Error
InvalidSchema: No connection adapters were found for 'blob:https://web.whatsapp.com/f50eac63-6a7f-48a4-a2b8-8558a9ffe015'
(using BeatufilSoup)
Using a native approach like:
import requests
url = 'https://web.whatsapp.com/f50eac63-6a7f-48a4-a2b8-8558a9ffe015'
fileName = 'test.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
file.write(chunk)
file.close()
Will simply result in the same error as using BeautifulSoup.
I am controlling Chrome using Selenium in Python, however I was unable to download the image correctly using the provided link.
A blob is a filelike object of raw data stored by the browser.
You can see them at chrome://blob-internals/
It's possible to get the content of a blob with Selenium with a script injection. However, you'll have to comply to the cross origin policy by running the script on the page/domain that created the blob:
def get_file_content_chrome(driver, uri):
result = driver.execute_async_script("""
var uri = arguments[0];
var callback = arguments[1];
var toBase64 = function(buffer){for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)i[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder("ascii").decode(a)};
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function(){ callback(toBase64(xhr.response)) };
xhr.onerror = function(){ callback(xhr.status) };
xhr.open('GET', uri);
xhr.send();
""", uri)
if type(result) == int :
raise Exception("Request failed with status %s" % result)
return base64.b64decode(result)
bytes = get_file_content_chrome(driver, "blob:https://developer.mozilla.org/7f9557f4-d8c8-4353-9752-5a49e85058f5")
Blobs are not actual files to be remotely retrieved by a URI. Instead, they are programatically generated psuedo-URLs which are mapped to binary data in order to give the browser something to reference. I.e. there is no attribute of <img> to provide raw data so you instead create a blob address to map that data to the standard src attribute.
From the MDN page linked above:
The only way to read content from a Blob is to use a FileReader. The following code reads the content of a Blob as a typed array.
var reader = new FileReader();
reader.addEventListener("loadend", function() {
// reader.result contains the contents of blob as a typed array
});
reader.readAsArrayBuffer(blob);
For people who are trying to do the same in node and selenium, please refer below.
var script = function (blobUrl) {
console.log(arguments);
var uri = arguments[0];
var callback = arguments[arguments.length - 1];
var toBase64 = function(buffer) {
for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)
i[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder("ascii").decode(a)
};
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function(){ callback(toBase64(xhr.response)) };
xhr.onerror = function(){ callback(xhr.status) };
xhr.open('GET', uri);
xhr.send();
}
driver.executeAsyncScript(script, imgEleSrc).then((result) => {
console.log(result);
})
For detailed explanation, please refer below link
https://medium.com/#anoop.goudar/how-to-get-data-from-blob-url-to-node-js-server-using-selenium-88b1ad57e36d
This question already has answers here:
Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
(9 answers)
Closed 6 years ago.
I am querying salesforce for some attachment data and it returns the data in binary format.
I have tried to convert the same to base64, but I have been quite unsuccessful so far. I have tried the btoa() method but it returns the The string to be encoded contains characters outside of the Latin1 range. error.
I tried to use the fileReader method i.e., readAsDataURL(), it returns the base64 string but unfortunately that doesn't represent the image.
COuld you please help me out as to how to convert the binary form of the data to base64encoded string?
Edit
Ultimately, I want to show the image on the webpage with the data I am getting which I am unable to do
If you are retrieving that image from server, you have the choice of convert to base64 from the server (and serve it ready to the client), or you need to pass the URL of the image from server, and then read it and convert to base64 from client javascript. But if you retrieve that binary from server to client, client will be unable to parse it since the data is corrupted due the wrong sending method.
Example converting a URL to base64 (with Canvas or FileReader):
function convertImgToDataURLviaCanvas(url){
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("image/png");
canvas = null;
};
img.src = url;
}
function convertFileToDataURLviaFileReader(url){
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function () {
console.log(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.send();
}
Conversion Fiddle:
http://jsfiddle.net/handtrix/yvq5y/
My custom server embeds meta data about an image in the PNG meta data fields. The image is loaded via a regular img tag. I'd like to access the meta data from JavaScript - any way to achieve this?
If not, what are the alternatives for serving additional information for an image? The images are generated on the fly and are relatively expensive to produce, so I'd like to serve the meta data and the image data in a single round trip to the server.
i had a similar task. I had to write physical dimensions and additional metadata to PNG files. I have found some solutions and combined it into one small library.
png-metadata
it could read PNG metadata from NodeJS Buffers, and create a new Buffers with new metadata.
Here how you can read PNG metadata in the Browser:
function loadFileAsBlob(url){
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status === 200) {
resolve(this.response);
// myBlob is now the blob that the object URL pointed to.
}else{
reject(this.response);
}
};
xhr.send();
})
};
const blob = await loadFileAsBlob('1000ppcm.png');
metadata = readMetadataB(blob);
A couple of solutions I can think of:
Pass the metadata as headers, use XMLHttpRequest to load the image and display it by converting the raw bytes to a data uri, as talked about here. Looks roughly like this:
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var metadata = xhr.getResponseHeader("my-custom-header");
image.src = window.URL.createObjectURL(xhr.response);
}
xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();
Alternatively, write a little png parser in js (or compile libpng to javascript using something like emscripten), and do basically the same thing as above.
It probably wouldn't be too hard to write actually; since you don't care about the image data, you'd just have to write the chunk-traversing code. Read up on how chunks are laid out here, and figure out what chunk type you're storing the metadata in. Still, don't really recommend this if you can just use headers...
I'm trying to use a combination of Ajax and data URIs to load a JPEG image and extract its EXIF data with a single HTTP request. I am modifying a library (https://github.com/kennydude/photosphere) to do this; currently this library uses two HTTP requests to set the source of the image and to get the EXIF data.
Getting the EXIF works, no problem. However I am having difficulty using the raw data from the ajax request as source for the image.
Source code for a small test of the technique:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
// own ajax library - using it to request a test jpg image
new Ajax().sendRequest
(
"/images/photos/badger.jpg",
{ method : "GET",
callback: function(xmlHTTP)
{
var encoded = btoa (unescape(encodeURIComponent(xmlHTTP.responseText)));
var dataURL="data:image/jpeg;base64,"+encoded;
document.getElementById("image").src = dataURL;
}
}
);
}
</script>
<script type="text/javascript" src="http://www.free-map.org.uk/0.6/js/lib/Ajax.js"></script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
I get what looks like sensible jpeg data sent back, and the length (in bytes) of the raw data and the base64-encoded-then-unencoded-again raw data is the same. However the attempt to set the image src fails on both Firefox (25) and Chrome (31) (current versions) - chrome displays "broken image" icon suggesting the src is an invalid format.
I used this mozilla page for info on base64 encoding/decoding:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
Any idea what might be wrong? Looking around I can create the base64 encoded image server side but can it be done client side like this? For one thing, base64 encoding server side obviously increases the data size and the whole purpose of this exercise is to cut down the amount of data being transferred from the server, as well as the number of requests.
Thanks,
Nick
Thanks for that. I've done a bit more digging on this and it turns out there is a solution at least on current versions of Firefox and Chrome (EDIT: IE10 works too). You can use XMLHttpRequest2 and use a typed array (Uint8Array). The following code works:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
function init()
{
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET','/images/photos/badger.jpg',true);
// Must include this line - specifies the response type we want
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e)
{
var arr = new Uint8Array(this.response);
// Convert the int array to a binary string
// We have to use apply() as we are converting an *array*
// and String.fromCharCode() takes one or more single values, not
// an array.
var raw = String.fromCharCode.apply(null,arr);
// This works!!!
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
document.getElementById("image").src = dataURL;
};
xmlHTTP.send();
}
</script>
</head>
<body onload='init()'>
<img id="image" alt="data url loaded image" />
</body>
</html>
Basically you ask for a binary response, then create an 8-bit unsigned int view of the data before converting it back into a (binary-friendly) string String.fromCharCode(). The apply is necessary as String.fromCharCode() does not accept an array argument. You then use btoa(), create your data url and it then works.
The following resources were useful for this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays?redirectlocale=en-US&redirectslug=JavaScript%2FTyped_arrays
and
http://www.html5rocks.com/en/tutorials/file/xhr2/
Nick
Nick's answer works very well. But when I did this with a fairly large file, I got a stack overflow on
var raw = String.fromCharCode.apply(null,arr);
Generating the raw string in chunks worked well for me.
var raw = '';
var i,j,subArray,chunk = 5000;
for (i=0,j=arr.length; i<j; i+=chunk) {
subArray = arr.subarray(i,i+chunk);
raw += String.fromCharCode.apply(null, subArray);
}
I had trouble with the ArrayBuffer -> String -> Base64 method described above, but ran across another method using Blob that worked great. It's not a way to convert raw data to Base 64 (as in the title), but it is a way to display raw image data (as in the actual question):
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var blb = new Blob([xhr.response], {type: 'image/png'});
var url = (window.URL || window.webkitURL).createObjectURL(blb);
image.src = url;
}
xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();
All credit goes to Jan Miksovsky, author of this fiddle. I just stumbled across it and thought it'd make a useful addition to this discussion.
Modern ES6 powered solution for image downloading: (without specifying image type)
async function downloadImageFromUrl(url) { // returns dataURL
const xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET', url, true);
xmlHTTP.responseType = 'blob';
const imageBlob = await new Promise((resolve, reject) => {
xmlHTTP.onload = e => xmlHTTP.status >= 200 && xmlHTTP.status < 300 && xmlHTTP.response.type.startsWith('image/') ? resolve(xmlHTTP.response) : reject(Error(`wrong status or type: ${xmlHTTP.status}/${xmlHTTP.response.type}`));
xmlHTTP.onerror = reject;
xmlHTTP.send();
});
return blobToDataUrl(imageBlob);
}
function blobToDataUrl(blob) { return new Promise(resolve => {
const reader = new FileReader(); // https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
reader.onload = e => resolve(e.target.result);
reader.readAsDataURL(blob);
})}
Usage:
downloadImageFromUrl('https://a.b/img.png').then(console.log, console.error)
I've been working for two days on this issue since I needed a solution to render the User's Outlook Profile Picture from the raw data received from Microsoft Graft. I have implemented all the solutions above, with no success. Then I found this git:
get base64 raw data of image from responseBody using jquery ajax
In my case, I just replaced "data:image/png;base64," with "data:image/jpg;base64,"
It works like a charm.
You will have to do base64 encoding on the server side as the responseText is treated as a String, and the response data that the server is sending is binary.
I am creating a Google-Chrome extension and I want to be able to pull some images that a website is loading and put them in the extension. In some cases, this can result in a lot of requests to the server, effectively slowing it down. These images are loaded when the user visits the page, so there is no need for the extension to request the images again. Is there any way to get the data without pulling the data from the server again?
Using binary Ajax, you can pull the images as Blob objects, which FileReader can convert to a base64 URL string.
Fetch the binary data of the image as an ArrayBuffer and store it in a Blob:
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
oReq.onload = function(oEvent) {
var blob = new Blob([oReq.response], {type: "image/png"});
// step 2 goes here...
};
oReq.send();
(According to the spec, you can also do oReq.responseType = "blob" to make oReq.response a Blob immediately, instead of an ArrayBuffer. I'm not 100% sure if this is actually supported yet.)
Read the Blob with FileReader:
var fr = new FileReader();
fr.onload = function(e) {
var dataUrl = e.target.result;
// step 3 goes here...
}
fr.readAsDataURL(blob);
Finally, you have the URL stored in dataUrl. Assign it directly to the src attribute of an image element:
document.getElementById("myimg").src = dataUrl;
To avoid performing the fetch in the future, store the data URL in localStorage or an IndexedDB store.