How to parse into base64 string the binary image from response? - javascript

I want to parse the requested image from my REST API into base64 string.
Firstly... I thought, it would be easy, just to use window.btoa() function for this aim.
When I try to do it in such part of my application:
.done( function( response, position ) {
var texture = new Image();
texture.src = "data:image/png;base64," + window.btoa( response );
I've got the next error: Uncaught InvalidCharacterError: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
As I read here: javascript atob returning 'String contains an invalid character'
The issue occurs because of newlines in the response and that's why window.btoa() failed.
Any binary image format of course will have newlines... But as from the link above the suggestion was to remove/replace those characters - is a bad suggestion for me, because if to remove/replace some characters from binary image it just will be corrupted.
Of course, the possible alternatives relate to the API design:
- to add some function, which return base64 representation
- to add some function, which return url to the image
If I won't repair it, I shall return base64 representation from the server, but I don't like such a way.
Does exist some way to solve my problem with the handling binary image from response, as it's shown above in the part of screenshot, doesn't it?

I think part of the problem you're hitting is that jQuery.ajax does not natively support XHR2 blob/arraybuffer types which can nicely handle binary data (see Reading binary files using jQuery.ajax).
If you use a native XHR object with xhr.responseType = 'arraybuffer', then read the response array and convert it to Base64, you'll get what you want.
Here's a solution that works for me:
// http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
function fetchBlob(uri, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', uri, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
if (callback) {
callback(blob);
}
}
};
xhr.send();
};
fetchBlob('https://i.imgur.com/uUGeiSFb.jpg', function(blob) {
// Array buffer to Base64:
var str = btoa(String.fromCharCode.apply(null, new Uint8Array(blob)));
console.log(str);
// Or: '<img src="data:image/jpeg;base64,' + str + '">'
});
https://jsfiddle.net/oy1pk8r3/2/
Produces base64 encoded console output: /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAIBAQIBAQICAgICAgICAw.....

instead of looping through the blob with _arrayBufferToBase64(),
use apply() to do the conversion,
it's 30 times faster in my browser and is more concise
// http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
function fetchBlob(uri, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', uri, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
if (callback) {
callback(blob);
}
}
};
xhr.send();
};
fetchBlob('https://i.imgur.com/uUGeiSFb.jpg', function(blob) {
var str = String.fromCharCode.apply(null, new Uint8Array(blob));
console.log(str);
// the base64 data: image is then
// '<img src="data:image/jpeg;base64,' + btoa(str) + '" />'
});

Im guessing to use escape on the string before you pass it to the function, without the API call I can't test myself.
test
encodeURI("testñ$☺PNW¢=")
returns
"test%C3%B1$%E2%98%BAPNW%C2%A2="
It just escapes all the characters, it should escape all the illegal characters in the string
test
encodeURI("¶!┼Æê‼_ðÄÄ┘Ì+\+,o▬MBc§yþó÷ö")
returns
"%C2%B6!%E2%94%BC%C3%86%C3%AA%E2%80%BC_%C3%B0%C3%84%C3%84%E2%94%98%C3%8C++,o%E2%96%ACMBc%C2%A7y%C3%BE%C3%B3%C3%B7%C3%B6"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

The issue you're encountering is that the response is being considered a Unicode String. See the section on Unicode Strings here: window.btoa
Several solutions are offered in this post

Try this on its working well. please try once. #user2402179
$.ajax({
type: 'GET',
url: baseUrl",
dataType: 'binary',
xhr() {
let myXhr = jQuery.ajaxSettings.xhr();
myXhr.responseType = 'blob';
return myXhr;
},
headers: {'Authorization': 'Bearer '+token}
}).then((response) => {
// response is a Blob
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.addEventListener('load', () => {
$('#theDiv').append('<img src="' +reader.result+ '" />')
resolve(reader.result);
}, false);
reader.addEventListener('error', () => {
reject(reader.error);
}, false);
reader.readAsDataURL(response);
});
});

Base 64 Image data is worked for me like
<img src="data:image/png;base64,' + responce + '" />

Related

Convert in to FileObject from imageUrl using Javascript( on any JS frameworks mostly React)

I do have image url handy , probably an drop box url
https://www.dropbox.com/s/tcg73i4bxbu423g/gradient-test.jpg?dl=0
How to get the fileobject for the same , since my backend api accept only file object , is there any way i can get file object.
I am expecting the below object format . is there any way guys
it will be great if any fiddle is applicable
Note: is it possible to convert without any external api .
any answers will be highly helpful & thankful
You can load image as a file use below function(link, #HaNdTriX). And the url you provided is not an image url so you should extract the image path first.
function toDataUrl(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
imagepath = "https://uc5d3934b120724e8be5a303a2af.previews.dropboxusercontent.com/p/thumb/AA2-rSW7gi7La52QQXPE_mXgt-ssFnHje-5SnLKNxXuTD_qtYtjackFxZTyn3SWQDCLEw66TdZeqa4hMdd33pGxoaXMufvP5XVRPlGZr_a8WJ_OgxphXn45cTKbFHXD2e7I4PcYgSnkBOiYpfqNK_GcMJvTlZskkWvsUwiqopClEkh_4_GDNQcOE-Po8puDE9koQuMnAh6q0Ig4-eZ3xyZO_X-fC9Z9M7niTHGbLAgpVlYWyyKLGFpgVJHD8jpZ1F38c2V8H8M6c4emhMaWr1bEBo4WWxjFHThLj1f1vDrWEv7Z18ZEro-bekrZRh_AwH7oxIBmYFZYhA91c6OMXAFiCdOX0hwRwhMJVxruschBy8bHqVkm2II5wTnDj6IbGlu5uatEt6LVVbLv0U2ZGlmSq/p.jpeg?fv_content=true&size_mode=5"
toDataUrl(imagepath, function(myBase64) {
console.log(myBase64); // myBase64 is the base64 string
});

Javascript string encoding Windows-1250 to UTF8

I've an angularjs app that receive data from an external webservice.
I think I'm receiving UTF-8 string but encoded in ANSI.
For example I get
KLMÄšLENÃ
When I want to display
KLMĚLENÍ
I've tried to use decodeURIComponent to convert it but that doesn't work.
var myString = "KLMÄšLENÃ"
console.log(decodeURIComponent(myString))
I'm probably missing something but I can't find what.
Thanks and regards,
Eric
You can use TextDecoder. (Be beware! some browser does not support it.)
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (this.status == 200) {
var dataView = new DataView(this.response);
var decoder = new TextDecoder("utf-8");
var decodedString = decoder.decode(dataView);
console.log(decodedString);
} else {
console.error('Error while requesting', url, this);
}
};
xhr.send();
Java servlet code for simulating server side output:
resp.setContentType("text/plain; charset=ISO-8859-1");
OutputStream os = resp.getOutputStream();
os.write("KLMĚLENÍ".getBytes("UTF-8"));
os.close();

How do I Convert URL to Blob with javascript or jquery [duplicate]

I'd like to build a simple HTML page that includes JavaScript to perform a form POST with image data that is embedded in the HTML vs a file off disk.
I've looked at this post which would work with regular form data but I'm stumped on the image data.
JavaScript post request like a form submit
** UPDATE ** Feb. 2014 **
New and improved version available as a jQuery plugin:
https://github.com/CoeJoder/jquery.image.blob
Usage:
$('img').imageBlob().ajax('/upload', {
complete: function(jqXHR, textStatus) { console.log(textStatus); }
});
Requirements
the canvas element (HTML 5)
FormData
XMLHttpRequest.send(:FormData)
Blob constructor
Uint8Array
atob(), escape()
Thus the browser requirements are:
Chrome: 20+
Firefox: 13+
Internet Explorer: 10+
Opera: 12.5+
Safari: 6+
Note: The images must be of the same-origin as your JavaScript, or else the browser security policy will prevent calls to canvas.toDataURL() (for more details, see this SO question: Why does canvas.toDataURL() throw a security exception?). A proxy server can be used to circumvent this limitation via response header injection, as described in the answers to that post.
Here is a jsfiddle of the below code. It should throw an error message, because it's not submitting to a real URL ('/some/url'). Use firebug or a similar tool to inspect the request data and verify that the image is serialized as form data (click "Run" after the page loads):
Example Markup
<img id="someImage" src="../img/logo.png"/>
The JavaScript
(function() {
// access the raw image data
var img = document.getElementById('someImage');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
var dataUrl = canvas.toDataURL('image/png');
var blob = dataUriToBlob(dataUrl);
// submit as a multipart form, along with any other data
var form = new FormData();
var xhr = new XMLHttpRequest();
xhr.open('POST', '/some/url', true); // plug-in desired URL
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert('Success: ' + xhr.responseText);
} else {
alert('Error submitting image: ' + xhr.status);
}
}
};
form.append('param1', 'value1');
form.append('param2', 'value2');
form.append('theFile', blob);
xhr.send(form);
function dataUriToBlob(dataURI) {
// serialize the base64/URLEncoded data
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(dataURI.split(',')[1]);
}
else {
byteString = unescape(dataURI.split(',')[1]);
}
// parse the mime type
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// construct a Blob of the image data
var array = [];
for(var i = 0; i < byteString.length; i++) {
array.push(byteString.charCodeAt(i));
}
return new Blob(
[new Uint8Array(array)],
{type: mimeString}
);
}
})();
References
SO: 'Convert DataURI to File and append to FormData
Assuming that you are talking about embedded image data like http://en.wikipedia.org/wiki/Data_URI_scheme#HTML
****If my assumption is incorrect, please ignore this answer.**
You can send it as JSON using XMLHttpRequest.
Here is sample code: (you may want to remove the header part ('data:image/png;base64,') before sending)
Image
<img id="myimg" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
Button
<input id="subbtn" type="button" value="sub" onclick="sendImg()"></input>
Script
function sendImg() {
var dt = document.getElementById("myimg").src;
var xhr = new XMLHttpRequest();
xhr.open("POST", '/Home/Index', true); //put your URL instead of '/Home/Index'
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { //4 means request finished and response is ready
alert(xhr.responseText);
}
};
var contentType = "application/json";
xhr.setRequestHeader("Content-Type", contentType);
for (var header in this.headers) {
xhr.setRequestHeader(header, headers[header]);
}
// here's our data variable that we talked about earlier
var data = JSON.stringify({ src: dt });
// finally send the request as binary data
xhr.send(data);
}
EDIT
As #JoeCoder suggests, instead of json, you can also use a FormData object and send in Binary format. Check his answer for more details.

Can't get EXIF info using loadImage.parseMetaData

I am using JavaScript LoadImage.parseMetaData (https://github.com/blueimp/JavaScript-Load-Image) to try and get Orientation of an image on the web, so I can rotate it.
If I hardcode the orientation (see "orientation: 3" in my second loadImage call), I can rotate it... but I am trying to use loadImage.parseMetaData to get the Orientation.
I have used web based EXIF parsers and the orientation info is there in the image.
When I call loadImage.parseMetaData "data.exif" seems to be null. See this fiddle: http://jsfiddle.net/aginsburg/GgrTM/13/
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.filepicker.io/api/file/U0D9Nb9gThy0fFbkrLJP', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
console.log ("got image");
var blob = new Blob([this.response], {type: 'image/png'});
console.log("about to parse blob:" + _.pairs(this.response));
loadImage.parseMetaData(blob, function (data) {
console.log("EXIF:" + _.pairs(data))
var ori ="initial";
if (data.exif) {
ori = data.exif.get('Orientation');
}
console.log("ori is:" + ori);
});
var loadingImage = loadImage(
blob,
function (img) {
console.log("in loadingImage");
document.body.appendChild(img);
},
{maxWidth: 600,
orientation: 3,
canvas: true,
crossOrigin:'anonymous'
}
);
if (!loadingImage) {
// Alternative code ...
}
}
};
xhr.send();
Any ideas or alternative approaches to correctly orientating images welcome.
Your call to loadImage needs to be inside the callback from the call to parseMetaData.
The reason: as is, your code contains a race condition. The call the loadImage is very likely to be made BEFORE the call the parseMetaData completes and stuffs the orientation due to the fact they are both asynchronous calls.
Why are you making a new blob whereas you asked for a Blob? The metadata are then lost, this is why you are losing it and exif is null.
Just replace :
var blob = new Blob([this.response], {type: 'image/png'});
By:
var blob = this.response;
Should do the trick.
Had the same problem, I changed the reponse type for 'arrayBuffer' and then create the blob from the response
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var arrayBufferView = new Uint8Array(this.response);
var blob = new Blob([arrayBufferView], { type: "image/jpeg" });
...

using xmlhttprequest to fetch a cross-domain PNG file

Sadly, I see a zillion similar questions but no answers that seem specific to my situation. I am not using jquery. I don't care about anything but the newest browsers (Chrome in particular). I am looking for a way to load a javascript Image from a cross-domain fetch of a PNG or JPG file.
i.e. I just want to do this:
var img1 = new Image();
img1.addEventListener('load', function() { imageLoaded( canvas, context, this); }, false)
img1.src = textureUrl;
which works great for same domain. However, apparently that will not include the Origin tag in the request header, so it is unable to work in a cross-domain environment, even though we have successfully set up the CORS headers on the servers. If there is something simple I can do to this request to include that header, that would be great.
But I gather what I have to do is use XHR to do an async fetch of the asset, to get the binary data, and then somehow shove that data into a regular Image() object. I believe we have successfully obtained the data in various forms (tried arraybuffer and blobs), but are not successful in jamming it into the Image() object.
For example:
var img3 = new Image();
var req = new window.XMLHttpRequest();
req.overrideMimeType('text/plain; charset=x-user-defined'); // seems to make no difference
req.responseType = 'arraybuffer'; // no joy with arraybuffer or blob
req.open("GET", textureUrl, true, "", ""); // async request allows CORS preflight exchange
req.onreadystatechange = function (oEvent) {
if (req.readyState === 4) {
if (req.status === 200) {
alert( "XHR worked" );
if( req.response ) {
alert( "resp text: " + req.response ); // identifies response as arraybuffer or blob
}
// I believe this section is where I need the most help.
// var base64Img = window.btoa(unescape(encodeURIComponent( req.responseText)) );
var base64Img = window.btoa( unescape( encodeURIComponent( req.response ) ) );
alert( "b64: " + base64Img ); // vaguely uu64ish, but truncated
var src = "";
if( isPng == 1 ) { // just to indicate the src url is built differently for jpg.
alert("png");
src = 'data:image/png;base64,' + base64Img;
}
....
img3.src = src; // img3 loads fine if I just jam a same domain url here
<closing braces>
From what I have read, it isn't clear I need to override the mime type, if I specify arraybuffer, but it isn't clear to me.
I get data back (no cross-domain errors, yay), and it seems to be about the right size, but I am not convinced I am successfully uu64 encoding it, nor that I am jamming a suitable data url into the image.
Again, I only need this to work with the newest Chrome browser, and I would like to be as 'pure HTML5' as possible, so I don't feel the need to work with IE7, etc.
I don't know if req.response includes the first line of the HTTP response or not (i.e. is it my responsibility to trim something before uuencoding it...)
Hope you can pull the wool from my eyes!
Thanks in advance.
I got stuck on the same problem for some time. This is what you need to do to make it work:
For zip/png etc. formats, you should use:
req.responseType = 'arraybuffer';
The tricky thing is in case of arraybuffer, req.responseText doesn't work but instead use req.response
var base64Img = window.btoa(
unescape(
encodeURIComponent(req.response)
)
);
If you are happy with using the latest HTML features, the following could help.
Loading binaries using Fetch API:
const response = await fetch('https://cross-origin.org/path-to-binary.png' , {
cache: 'no-cache',
mode: 'cors',
credentials: 'omit'
});
if (!response.ok) {
console.error(response);
throw new Error(response.statusText);
}
console.log('response from fetch', response);
const blob = await response.blob();
To convert Blob to base64 you can use the FileReader API
// Lang: Typescript
private async convertBlobToBase64(blob: Blob): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result as string);
};
reader.readAsDataURL(blob);
});
}

Categories