Create data URIs on the fly? - javascript

Is there a script (javascript / client side). That create data URIs on the fly. Now i create data URIs with a online base64 creator. And then put that output in the css file. But when i changing the images. Its a lot of work to do it. Is there a script, that can do it for me.?

The modern browsers now have good support for base64 encoding and decoding. There are two functions respectively for decoding and encoding base64 strings:
atob() decodes a string of base-64 data
btoa() creates a base-64 encoded ASCII string from a "string" of binary data
This let's you create data uri's easily i.e
var longText = "Lorem ipsum....";
var dataUri = "data:text/plain;base64," + btoa(longText);
//a sample api expecting an uri
d3.csv(dataUri, function(parsed){
});

As a complete solution to your scenario, you can use fetch to get a blob representation of your image, and then use FileReader to convert the blob in its base64 representation
// get an image blob from url using fetch
let getImageBlob = function(url){
return new Promise( async resolve=>{
let resposne = await fetch( url );
let blob = resposne.blob();
resolve( blob );
});
};
// convert a blob to base64
let blobToBase64 = function(blob) {
return new Promise( resolve=>{
let reader = new FileReader();
reader.onload = function() {
let dataUrl = reader.result;
resolve(dataUrl);
};
reader.readAsDataURL(blob);
});
}
// combine the previous two functions to return a base64 encode image from url
let getBase64Image = async function( url ){
let blob = await getImageBlob( url );
let base64 = await blobToBase64( blob );
return base64;
}
// test time!
getBase64Image( 'http://placekitten.com/g/200/300' ).then( base64Image=> console.log( base64Image) );

One way is to make a Blob of an object, and then use URL.createObjectURL()
let a = URL.createObjectURL(new Blob([JSON.stringify({whatever: "String..."}, null, 2)]))
console.log(a)

Related

Base64 to Image File Convertion in JS

I am working on a project where I have to upload an image as form data along with other text fields. I have my file in Base64 string at first, then I convert it into a file before uploading it to the server.
const data = await fetch(base64String);
const blob = await data.blob();
const file = await new File([blob], 'avatar', { type: 'image/png' });
I logged the base64String in the client side before uploading it to the server. Then I upload file to the server as a File. Before saving it to MongoDB when I log it as a base64 string again in the server side, I see my string is not the same as before. I feel like while converting the base64 to file in the client side I am doing something wrong. Help me out please.
I have figured out my problem. When I take image file input from my computer I get a base64 string like below -
dataimage/jpegbase64/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA...
But, when I convert it back into a file it expects a string like below -
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA....
So, basically, I had to trim the string accordingly to match the expected format and wrote a base64 to file conversion function following this answer.
Here is my function to convert a base64 string to an image file
export function getFileFromBase64(string64:string, fileName:string) {
const trimmedString = string64.replace('dataimage/jpegbase64', '');
const imageContent = atob(trimmedString);
const buffer = new ArrayBuffer(imageContent.length);
const view = new Uint8Array(buffer);
for (let n = 0; n < imageContent.length; n++) {
view[n] = imageContent.charCodeAt(n);
}
const type = 'image/jpeg';
const blob = new Blob([buffer], { type });
return new File([blob], fileName, { lastModified: new Date().getTime(), type });
}

Decode XMLHTTPResponseText into dataUrl without base encoding on server side

How can the plain text response of an XMLHTTPRequest be converted to a dataUrl on client side?
Image data is being send from the server to an Iframe and the only option to retrieve the data is the default encoded data from a GET request.*
I do not have any control over the server. I can not specify overrideMimeType nor the responseType of the request.
I tried to utf8 encode the returned data:
const utf8 = new TextEncoder();
const bytes = utf8.encode(imageDataAsText);
//Convert to data url
const fr = new FileReader();
const blob = new Blob([bytes], { type: attachment.metadata.mediaType });
fr.onload = (e) => {
setImageData(fr.result as string);
};
fr.readAsDataURL(blob);
Converting via the char code didn't work either:
https://stackoverflow.com/a/6226756/3244464
let bytesv2 = []; // char codes
for (var i = 0; i < imageDataAsString.length; ++i) {
var code = imageDataAsString.charCodeAt(i);
bytesv2 = bytesv2.concat([code & 0xff, code / 256 >>> 0]);
}
Raw data as it is displayed by console out. What is the actual default encoding of the data I am working with here?
Context:
* The data in question is recieved inside an iframe inside the atlassian (jira/confuence) ecosystem. They do not support piping binary data from the parent frame to the iframe, nor can I make my own request due to the authorization flow which requires cookies stored on the parent page. All other options mention to override some encoding, or changing it on the server side do not apply in this specific case.
When you are using XMLHttpRequest to get binary data then don't return it as a string. Use xhr.responseType = 'blob' (or arrayBuffer if you intend to read/modify it)
var xhr = new XMLHttpRequest()
xhr.responseType = 'blob'
xhr.onload = () => {
// Convert xhr blob to data url
const fr = new FileReader()
fr.onload = () => {
setImageData(fr.result)
}
fr.readAsDataURL(xhr.response)
}
Better yet use the fetch api instead of the old XMLHttpRequest to get the binary
It's more popular among web workers and servers. It's also simpler and based on promises
fetch(url)
.then(res => res.blob())
.then(blob => { ... })
And why do you need it to be a base64 url? if it's just to show a preview of an <img> then it's a waste of time, cpu and memory.
It would be better just to do:
img.src = URL.createObjectURL(blob)

how to convert byte array to base64 encoded format?

I have a page to download a file from the Postgres database. Now I can hit the following URL to view the file content present in the database(stored as bytes)-HTTP://sandbox4.wootz.io:8080/api/blob/1/UploadFile/hope%20real.txt
Since the data is stored in a column of type bytes(byte array) when I click the download button it downloads the file and when I see its contents it is displayed as a byte array.
file.txt(contents)
[\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335]
download functionality
axios({
url: 'api/store/blob/UploadFile/' + data.chosenfile,
method: 'GET',
headers: {'session_id': data.sessionid},
responseType: 'arraybuffer'
}).then(response => {
console.log(response.data); //displays nothing (empty)
var fileURL = window.URL.createObjectURL(new Blob([response.data]));
console.log('fileURL is'+fileURL)
var fileLink = document.createElement('a');
console.log('fileLink is'+fileLink)
fileLink.href = fileURL;
fileLink.setAttribute('download', data.chosenfile);
document.body.appendChild(fileLink);
fileLink.click();
)
console.log of the response object
{"data":{},"status":200,"statusText":"OK","headers":{"access-control-allow-origin":"*","connection":"keep-alive","content-length":"86","content-type":"text/html; charset=utf-8","date":"Mon, 06 Jul 2020 18:22:23 GMT","etag":"W/\"56-Vaz0hG1/FIgtEurgvK+wOU+4F4M\"","x-powered-by":"Express"},"config":{"url":"api/store/blob/UploadFile/hope real.txt","method":"get","headers":{"Accept":"application/json, text/plain, */*","Access-Control-Allow-Origin":"http://localhost","session_id":"c5b3b878-771e-4472-84eb-6de15686effa"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"responseType":"arraybuffer","xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1},"request":{}}
Uploadfile part of my code(this is how the files was uploaded to database)
function readFileAsync(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
var base64Url = reader.result;
console.log(base64Url) //ENITRE BASE64 URL
resolve(base64Url.substr(base64Url.indexOf(',') + 1)); //will return only the base64string part from the base64 url
};
reader.onerror = reject;
reader.readAsDataURL(file);
})
}
async function uploadFile(path, data) {
try {
let base64string = await readFileAsync(data.chosenfile);
console.log('base64 content is'+ base64string)
let response = await axios({
method: 'post',
url: 'api/store/blob' + path,
headers: {'session_id': data.sessionid},
data: {"id":data.chosenfile.name, "file": base64string }
});
if (response.status == 200) {
console.log(response.status);
}
return response.data;
} catch (err) {
console.error(err);
}
}
what am i doing wrong? why am i getting the file contents as [\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335] ? What should I do to get the actual file's content in the downloaded file?
NOTE:With respect to the upload part, I am using the same strategy for all kind of files(excel documents,txt files etc) which is encoding it to base64 encoded string before passing it in the axios post payload.Now this payload is passed to another project called data-manager (interacts with postgres database).so when this data-manager project recieves the payload that i sent, it converts it to bytes [] before inserting to the table column of type bytea.So ultimately when i download any file from this table i will get the file contents also in bytea format.
Your file is a correct ASCII text file with content [\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335] literally.
That you get this content when you download it is perfectly fine, since it's what this file's content is.
What you want is to parse that content from the Hex representation they used to an actual ArrayBuffer to finally read that again as UTF-8 text (or any encoding respecting ASCII).
This has to be done after you do download the file and read it as text.
You first extract the actual bytes sequence as Hex from that [\x - ] wrapper, then you split the resulting string at every two chars to get hex values of every bytes, and finally you parse it into an Uint8Array to get back the original data:
// for StackSnippet we need to hardcode the response
// OP would have to make its request return that string
const response = { data: String.raw`[\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335]` };
// .then( (response) => {
const encoded_text = response.data;
// remove leading "[\x" and final "]"
const encoded_data = encoded_text.slice( 3, -1 );
// split at every two chars, so we can get 0xNN, 0xNN
const hex_bytes = encoded_data.match( /.{2}/g );
// as numbers (0 - 255)
const num_bytes = hex_bytes.map( (hex) => parseInt( hex, 16 ) );
// wrap in an Uint8Array
const view = new Uint8Array( num_bytes );
// from there you can generate the Blob to save on disk
download( new Blob( [ view ] ), "file.txt" );
// but if you want to read it as UTF-8 text, you can:
const as_text = new TextDecoder().decode( view );
console.log( as_text );
// } );
function download( blob, filename ) {
const anchor = document.createElement( "a" );
anchor.href = URL.createObjectURL( blob );
anchor.download = filename;
anchor.textContent = "click to download";
document.body.append( anchor );
}

set csv encoding when downloading a file

I am using react, Paparse and encoding-japanese
With Paparse I can upload a CSV and decode it from Shift-JS. but the opposite operation is not supported by the library.
I added the encoding-japanese, in order to convert a string to SHIFT-js and download it.
Here is my code :
const csv = csvParser.unparse({
"fields": ["行形式","取引番号","取引日","支払期限","顧客番号","顧客企業名","顧客電話番号","送付先郵便番号","請求書発行日","郵送","メール送付","取引金額","明細","単価","数量","金額","消費税率","税込対象額_10%","税込対象額_8%","税込対象額_経8%","税込対象額_旧8%","税込対象額_非","税込対象額_対象外"],
"data": [
["取引","transaction-20200218-094750_1","2020/02/18","2020/03/31","DP79","Sample1Corp","03-0000-0000","123-4567","2020/02/19","0","1","110","","","","","","110","","","",""]
]
});
const a = document.createElement("a");
const sjisArray = Encoding.convert(csv, 'SJIS', 'UTF8');
console.log(sjisArray)
a.href = window.URL.createObjectURL(new Blob(['\ufeff'+sjisArray], {type: "text/csv;charset=shift-js"}));
a.download = "取引サンプル.csv";
a.click();
It throw no error, but my csv file when I open it in notepad, it is still in UTF8 with BOM.
I wish to have it in shift-js.
How can I achieve that ?
Your Encoding library is currently returning a DOMString, because you passed such a DOMString as input.
This means that your Blob constructor will convert this DOMString to UTF-8 and that's what you'll have in your file: an UTF-8 version of the UTF-16 representation of the Shift-JIS encoded text.
Least to say, that's not what you want.
Quick looking at that library's docs, it seems that the best would be to pass an ArrayBuffer version of your text to encode, so that it returns to you an Array of the bytes values (like an Uint8Array, except they use a normal Array for whatever reasons...).
Then from that Array of bytes, you'll be able to generate a new ArrayBuffer that you will be able to pass to your Blob without it converting it back to UTF-8.
const csv = Papa.unparse({
"fields": ["行形式","取引番号","取引日","支払期限","顧客番号","顧客企業名","顧客電話番号","送付先郵便番号","請求書発行日","郵送","メール送付","取引金額","明細","単価","数量","金額","消費税率","税込対象額_10%","税込対象額_8%","税込対象額_経8%","税込対象額_旧8%","税込対象額_非","税込対象額_対象外"],
"data": [
["取引","transaction-20200218-094750_1","2020/02/18","2020/03/31","DP79","Sample1Corp","03-0000-0000","123-4567","2020/02/19","0","1","110","","","","","","110","","","",""]
]
});
// First convert our DOMString to an ArrayBuffer
const utf8Array = new TextEncoder().encode( csv );
// pass it to Encoding so we get back an Array of bytes
const sjisArray = Encoding.convert(utf8Array, 'SJIS', 'UTF8');
// now we can make our Blob without auto encoding
const blob = new Blob( [ new Uint8Array( sjisArray ) ] );
const a = document.createElement('a');
a.download = 'Shift-JIS.csv';
a.href = URL.createObjectURL( blob );
a.textContent = 'download';
document.body.append( a );
// just to check we encoded it correctly
readAsText( blob, 'Shift-JIS' )
.then( txt => console.log( 'read back as Shift-JIS:', txt ) );
readAsText( blob, 'utf-8' )
.then( txt => console.log( 'read back as UTF-8:', txt ) );
function readAsText( blob, encoding ) {
return new Promise( (res, rej) => {
const reader = new FileReader();
reader.onerror = rej;
reader.onload = (evt) => res( reader.result );
reader.readAsText( blob, encoding );
} );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/encoding-japanese/1.0.30/encoding.min.js"></script>

How can I use UTF-8 in blob type?

I have to export table by csv file.
csv file data is from server by Blob type.
Blob {size: 2067, type: "text/csv"}
async exportDocumentsByCsv() {
this.commonStore.setLoading(true)
try {
const result = await DocumentSearchActions.exportDocumentsByCsv({
searchOption: this.documentSearchStore.searchOption
})
// first
// const blob = new Blob([result.body], { type: 'text/csv;charset=utf-8;' })
// second
// const blob = new Blob([`\ufeff${result.body}`], { type: 'text/csv;charset=utf-8;' })
const blob = result.body
console.log('result.body', result.body)
const fileName = `document - search - result.csv`
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// for IE
window.navigator.msSaveOrOpenBlob(blob, fileName)
} else {
FileSaver.saveAs(blob, fileName)
}
this.commonStore.setLoading(false)
} catch (err) {
alert(err.errorMessage)
this.commonStore.setLoading(false)
}
}
I have to set utf-8 or else because of my language.
I tried to fix this issue, but I don't know how to fix it.
I searched fix this issue by using \ufeff but When I try to use this like
second way, It doesn't work for me.
| [object | Blob] |
Blob doesn't take care of the encoding for you, all it sees is binary data. The only conversion it does is if you pass in an UTF-16 DOMString in the constructor's BlobsList
The best in your situation is to set up everything in your application from server to front as UTF-8 and to ensure that everything is sent using UTF-8. This way, you will be able to directly save the server's response, and it will be in UTF-8.
Now, if you want to convert a text file from a known encoding to UTF-8, you can use a TextDecoder, which can decode a ArrayBuffer view of the binary data from a given encoding to DOMString, which can then be used to generate an UTF-8 Blob:
/* const data = await fetch(url)
.then(resp=>resp.arrayBuffer())
.then(buf => new Uint8Array(buf));
*/
const data = new Uint8Array([147, 111, 152, 94 ]);
// the original data, with Shift_JIS encoding
const shift_JISBlob = new Blob([data]);
saveAs(shift_JISBlob, "shift_JIS.txt");
// now reencode as UTF-8
const encoding = 'shift_JIS';
const domString = new TextDecoder(encoding).decode(data);
console.log(domString); // here it's in UTF-16
// UTF-16 DOMStrings are converted to UTF-8 in Blob constructor
const utf8Blob = new Blob([domString]);
saveAs(utf8Blob, 'utf8.txt');
function saveAs(blob, name) {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = name;
a.textContent = 'download ' + name;
document.body.append(a);
}
a{display: block;}

Categories

Resources