This question already has answers here:
Convert blob to base64
(15 answers)
Fetch image from API
(3 answers)
Closed 3 days ago.
This post was edited and submitted for review 3 days ago.
I'm newbie on this but I have this problem, I'm using an API which gives me as result a PNG image binary string:
I want to convert this to base64 and put it as an attribute in an img tag
<img id="ml">
So tried, doing this:
$("#ml").attr("src",'data:image/png;base64,'+ btoa(unescape(encodeURIComponent(response))) );
But this shows me a broken image:
I tried with this getting the same error:
var blob = new Blob([response], {type: 'image/png'});
var reader = new FileReader();
reader.onload = function (e) {
$('#ml').attr('src', e.target.result);
};
reader.readAsDataURL(blob);
Finally I used a library: https://github.com/dankogai/js-base64
var emk = Base64.encode(response);
$("#ml").attr("src",'data:image/png;base64,'+ emk );
But the result is the same.
I don't know if I'm missing something, I'd like to receive your help.
=====
UPDATE:
As you mentioned in the comments I mention the previous step:
I obtain this binary result from VanceAI API. I upload an image, then process applying an edition provided by API service and finally the result is for download, this is the code:
var form = new FormData();
form.append("api_token", "XXXXXXX1234AAAAAA");
form.append("trans_id", "XXXXBBBBVVVVVVVV"); //processed image ID
var settings = {
"url": "https://api-service.vanceai.com/web_api/v1/download?api_token=XXXXXXX1234AAAAAA",
"method": "POST",
"timeout": 0,
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"data": form
};
$.ajax(settings).done(function (response) {
console.log(response); // binary result
});
I also tried this:
$("#ml").attr("src",'data:image/png;base64,'+ btoa(response) );
But I get this error:
I also have to mention this result is not a Blob.
I hope you can help me.
Thanks.
Related
Im trying to create a blob url to use string as file for JwPlayer subtitles.
subtitles are loaded like this:
const playlistItem = {
...
tracks: [
{
file: 'https://myfakesite.org/subtitles.vtt',
label: 'en'
}
]
}
So because jwplayer dont accept my source (subtitles.ass) i converted .ass to .vtt resulting as string.
Like this:
var vttRaw = `WEBVTT
00:00:25.520 --> 00:00:29.250
Naquele dia,
a humanidade foi lembrada...
00:00:35.110 --> 00:00:38.180
do terror de estar à mercê deles`;
As jwplayer needs a url, i converted this string to blob url:
//Generate blob
var blob = new Blob([vttRaw], {
type: "text/vtt; charset=utf-8"
});
//Generate url
var vtt_url = URL.createObjectURL(blob) + "#.vtt";
In web browser that works, but in react-native-android results in a error.
Possible Unhandled Promise Rejection (id: 0):
Error: Cannot create URL for blob!
blob error
I think the problem is to generate a blob url, anyone know what can i do?
I had this issue in React Native for Android. The following worked in iOS but not Android
URL.createObjectURL(blob)
Try passing base64 data rather than the url, like in this post.
Maybe something like this:
//Generate blob
var blob = new Blob([vttRaw], {
type: "text/vtt; charset=utf-8"
});
const fileReaderInstance = new FileReader();
fileReaderInstance.readAsDataURL(blob);
fileReaderInstance.onload = () => {
base64 = fileReaderInstance.result;
vtt_data = base64;
}
actually there are many answers for this question. But my problem is,
i want to generate pdf dynamically with 5 external(URL) images. Im using PDFmake node module.
it supports only two ways local and base64 format. But i don't want to store images locally.
so my requirement is one function which takes url as parameter and returns base64.
so that i can store in global variable and create pdfs
thanks in advance
function urlToBase(URL){
return base64;
}
var img = urlToBase('https://unsplash.com/photos/MVx3Y17umaE');
var dd = {
content: [
{
text: 'fjfajhal'
},
{
image: img,
}
]
};
var writeStream = fs.createWriteStream('myPdf.pdf');
var pdfDoc = printer.createPdfKitDocument(dd);
pdfDoc.pipe(writeStream);
pdfDoc.end();
im using PDFmake module from npm
The contents of the remote image can first be fetched with an HTTP request, for example using the ubiquitous request npm module. The image string contents can then be transformed to a buffer and finally converted to a base64 string. To complete the transformation, add the proper data-url prefix, for example, data:image/png,base64, to the beginning of the base64 string.
Here is a rough example for a PNG image:
const request = require('request-promise-native');
let jpgDataUrlPrefix = 'data:image/png;base64,';
let imageUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
request({
url: imageUrl,
method: 'GET',
encoding: null // This is actually important, or the image string will be encoded to the default encoding
})
.then(result => {
let imageBuffer = Buffer.from(result);
let imageBase64 = imageBuffer.toString('base64');
let imageDataUrl = jpgDataUrlPrefix+imageBase64;
console.log(imageDataUrl);
});
I've tried all of the methods I could find in stackoverflow. This two are some of the most complete posts:
Display image from blob using javascript and websockets
How can you encode a string to Base64 in JavaScript?
I'm using cloudinary and id3js. First I upload the mp3 file to
cloudinary, then I request the file with Ajax through id3js. This
gives me all of the ID3 tags.
openUploadModal() {
cloudinary.openUploadWidget(window.cloudinaryOptions,
(errors, track) => {
if(!values(errors).length) {
id3(track[0].secure_url, (errs, tags) => {
this.setState({
title: tags.title,
audio_url: track[0].secure_url,
artist: tags.artist,
uploaded: true,
cover_photo: this.getImage(tags.v2.image)
});
});
}
});
}
And the image converter:
getImage(image) {
var arrayBuffer = image.data;
var bytes = new Uint8Array(arrayBuffer);
return "data:image/png;base64,"+btoa(unescape(encodeURIComponent(bytes)));
}
This is what the tags object looks like:
I then use the return value of getImage in the background-image attribute of a div. There are no errors in the console (not a bad request) but when opening the data:image/jpg;base64,... link there's only a little white square on the page.
How can I get a working url from the image object in the ID3 tags?
If image.data is an ArrayBuffer, you can use FileReader. FileReader load event is asynchronous, you cannot return the result from the function without using Promise, though you can use FileReaderSync() at Worker.
See also createImageBitmap alternative on Safari.
var reader = new FileReader();
reader.onload = function() {
// do stuff with `data URI` of `image.data`
console.log(reader.result);
}
reader.readAsDataURL(new Blob([image.data], {type:image.mime}));
EDIT: changed title from "JS File API - write and read UTF-8 data is inconsistent" to reflect the actual question.
I have some binary content i need to calculate the MD5 of. The content is a WARC file, that means that it holds text as well as encoded images. To avoid errors in the file saving, I convert and store all the data in arrayBuffers. All the data is put in UInt8Arrays to convert it to UTF-8.
My first attempt, for testing, is to use the saveAs library to save files from Chrome extensions. This means I was using a blob object to be passed on to the method and create the file.
var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
saveAs(b,'name.warc');
I haven't found a tool to compute the MD5 from a Blob object so what I was doing was using a FileReader to read the blob file as binary data and then use an MD5 tool (I used cryptoJS as well as a tool from faultylabs) to compute the result.
f = new FileReader();
f.readAsBinaryString(b);
f.onloadend = function(a){
console.log( 'Original file checksum: ', faultylabs.MD5(this.result) );
}
The resources (images) are downloaded directly in arraybuffer format so I have no need to convert them.
The result was wrong, meaning that checking the MD5 from the code and checking it from the file I saved on my local machine gave 2 different results. Reading as text, obviously shoots out an error.
The workaround I found, consists in writing the blob object on the disk using the filesystem API and then read it back as binary data, compute the MD5 and then save that retrieved file as WARC file (not directly the blob object but this "refreshed" version of the file).
In this case the computed MD5 is fine ( I calculate it on the "refreshed" version of the warc file) but when I launch the WARC replay instance with the "refreshed" warc archive, it throws me errors - while with the original file I don't have any problem (but the MD5 is not correct).
var fd = new FormData();
// To compute the md5 hash and to have it correct on the server side, we need to write the file to the system, read it back and then calculate the md5 value.
// We need to send this version of the warc file to the server as well.
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function computeWARC_MD5(callback,formData) {
window.requestFileSystem(window.TEMPORARY, b.size, onInitFs);
function onInitFs(fs) {
fs.root.getFile('warc.warc', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
readAndMD5();
};
fileWriter.onerror = function(e) {
console.error('Write failed: ' + e.toString());
};
fileWriter.write(b);
});
});
function readAndMD5() {
fs.root.getFile('warc.warc', {}, function(fileEntry) {
fileEntry.file( function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var warcMD5 = faultylabs.MD5( this.result );
console.log(warcMD5);
var g = new Blob([this.result],{type: "text/plain;charset=utf-8"});
saveAs(g, o_request.file);
formData.append('warc_file', g)
formData.append('warc_checksum_md5', warcMD5.toLowerCase());
callback(formData);
};
reader.readAsBinaryString(file);
});
});
}
}
}
function uploadData(formData) {
// upload
$.ajax({
type: 'POST',
url: server_URL_upload,
data: fd,
processData: false,
contentType: false,
// [SPECS] fire a progress event named progress at the XMLHttpRequestUpload object about every 50ms or for every byte transmitted, whichever is least frequent
xhrFields: {
onprogress: function (e) {
if (e.lengthComputable) {
console.log(e.loaded / e.total * 100 + '%');
}
}
}
}).done(function(data) {
console.log('done uploading!');
//displayMessage(port_to_page, 'Upload finished!', 'normal')
//port_to_page.postMessage( { method:"doneUpload" } );
});
}
computeWARC_MD5(uploadData, fd);
saveAs(b, 'warc.warc');
Could anybody explain me why there is this discrepancy? What am I missing in treating all the objects I am dealing with as binary data (store, read)?
Basically I tried another route and converted the blob file back to arraybuffer and computed the MD5 on that. At that point, the file's MD5 and the arraybuffer's are the same.
var b = new Blob(arrayBuffers, {type: "text/plain;charset=utf-8"});
var blobHtml = new Blob( [str2ab(o_request.main_page_html)], {type: "text/plain;charset=utf-8"} );
f = new FileReader();
f.readAsArrayBuffer(b);
f.onloadend = function(a){
var warcMD5 = faultylabs.MD5(this.result);
var fd = new FormData();
fd.append('warc_file', b)
fd.append('warc_checksum_md5', warcMD5.toLowerCase());
uploadData(fd);
}
I guess the result from a binary string and from a buffer array is different, that's why also the MD5 is inconsistent.
Is possible to change the Blob charset really? I'm trying it for hours but it doesn't workds. See this.
jQuery("#download").click(function() {
var csv_content = jQuery("#csv").val(),
download = document.createElement("a"),
blob = new Blob([csv_content], { type: "text/csv;charset=ISO-8859-1" });
download.href = window.URL.createObjectURL(blob);
download.download = "test.csv";
var event = document.createEvent("MouseEvents");
event.initMouseEvent(
"click", true, false, window, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
);
download.dispatchEvent(event);
});
I need export a CSV to open on Excel, but it always is save with UTF-8 and Excel can't handle it.
I found the solution before to post.
The change of charset has not been resolved, in fact. However, I sent the UTF-8 header for the download process and Excel was able to understand the file format correctly. Thanks to this response of Erik Töyrä.
blob = new Blob(["\ufeff", csv_content]);
In my case I was using Angular JS to receive an encoded CSV file from the server in response to an HTTP POST. The problem was that CSVs returned from XMLHttpRequests are represented as Unicode (I want to say UTF-8, but according to this it is UTF-16) strings, not pre-encoded binary data. It looks like this is true in your example too, it is reading the CSV from a DOM element? In this case it ends up being represented as Unicode in memory, so it doesn't matter what value you set the encoding metadata to, the data is still Unicode.
My Angular code was doing something like this:
$http.post('/url', postData, {}).then(handleResponse);
Inside handleResponse, the data was already represented in Unicode. According to Angular's $http service, not providing the responseType property on the config object causes it to default to string. Which according to Mozilla ends up represented as a DOMString in UTF-16, whereas we actually want it to be a Blob. Setting the responseType to blob on the config object successfully prevented the content from getting decoded. Without this, the response data was being inadvertently decoded before being placed into the Blob.
$http.post('/url', postData, {responseType: 'blob'}).then(handleResponse);
I then used saveAs() to get the browser to provide the file contents to the user.
function handleResponse(response) {
let headers = response.headers();
let blob = new Blob([response.data], {type: headers['content-type']});
saveAs(blob, headers['x-filename']);
}
I got the idea to set responseType from https://stackoverflow.com/a/16791296/1225617
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
} else {
const link = document.createElement('a');
if (link.download !== undefined) {
// Browsers that support HTML5 download attribute
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
this worked for csv export with excel format in vuejs.
If you have some symbols in the csv and the accepted solution is not solving the problem:
blob = new Blob(["\ufeff", csv_content]);
// for csv_content you can try like below.
function b64DecodeUnicode(str: any) {
return decodeURIComponent(atob(str).split('').map((c: any) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}