I have a local site which uses Javascript to browse files on my machine. This is not a NodeJS question. I have been reading binary files on my local filesystem and converting them to base64. The problem I'm having is when there are non-printable characters. The output I get from javascript is different to the base64 command line tool in Linux.
An example file, which we can use for this question, was generated with head -c 8 /dev/random > random -- it's just some binary nonsense written to a file. On this example it yielded the following:
$ base64 random
Tg8j3hAv/u4=
If you want to play along at home you can run this to generate the same file:
echo -n 'Tg8j3hAv/u4=' | base64 -d > random
However, when I try and read that file in Javascript and convert it to base64 I get a different result:
Tg8j77+9EC/vv73vv70=
It looks kind of similar, but with some other characters in there.
Here's how I got it:
function readTextFile(file)
{
let fileContents;
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
fileContents = rawFile.responseText;
}
}
}
rawFile.send(null);
return fileContents;
}
var fileContents = readTextFile("file:///Users/henrytk/tmp/stuff/random");
console.log(btoa(unescape(encodeURIComponent(fileContents))));
// I also tried
console.log(Base64.encode(fileContents));
// from http://www.webtoolkit.info/javascript_base64.html#.YVW4WaDTW_w
// but I got the same result
How is this happening? Is it something to do with how I'm reading the file? I want to be able to read that file synchronously in a way which can be run locally - no NodeJS, no fancy third-party libraries, if possible.
I believe this is the problem:
fileContents = rawFile.responseText
This will read your file as a JavaScript string, and not all binary is valid JavaScript character code points.
I will recommend using fetch to get a blob, since that is the method I know best:
async function readTextFileAsBlob(file) {
const response = await fetch( file );
const blob = await response.blob();
return blob;
}
Then, convert the blob to base64 using the browser's FileReader.
(Maybe that matches the Linux tool?)
const blobToBase64DataURL = blob => new Promise(
resolvePromise => {
const reader = new FileReader();
reader.onload = () => resolvePromise( reader.result );
reader.readAsDataURL( blob );
}
);
In your example, you would use these functions like this:
readTextFileAsBlob( "file:///Users/henrytk/tmp/stuff/random" ).then(
async blob => {
const base64URL = await blobToBase64DataURL( blob );
console.log( base64URL );
}
);
This will give you a URL like data://.... You'll need to split off the URL part, but if all goes well, the last bit should be the right base64 data. (Hopefully).
Related
I have some code(vanilla Javascript) that allows me to generate a Base64 string from an image and it works. I have to bring this string to node js and then store it in a MongoDB database. The problem is that once the fetch is done the string is undefined. What can I do?
Base64 encoder
var logoUri;
const file = logo.files[0];
if(file.size<=2e+6){
const reader = new FileReader
reader.addEventListener('load', ()=>{
// console.log(reader.result)
logoUri=reader.result
console.log(logoUri) // the console log works
//then i fetch (post) this logoUri
})
reader.readAsDataURL(file)
I am writing frontend Angular application, where user should be able to upload MS Word template files (.dotx) and later download them on demand. Due to file size limitations I have to upload files as byte array and files will be stored and downloaded in this format. Approach, described below works fine with .txt files, however with MS Word files it does not work. Downloaded MS Word file has issues with encoding and is not readable.
Part 1: Uploading file
I use to get file from user:
<input type="file" class="file-input" (change)="onFileSelected($event)">
Reading file to byte array ("uploading file"):
onFileSelected($event) {
const file = $event.target.files[0] as File;
const reader = new FileReader();
const fileByteArray = [];
reader.readAsArrayBuffer(file);
reader.onloadend = (evt) => {
if (evt.target.readyState === FileReader.DONE) {
const arrayBuffer = evt.target.result as ArrayBuffer;
const array = new Uint8Array(arrayBuffer);
for (const a of array) {
fileByteArray.push(a);
}
this.byteArray = fileByteArray;
}
};
}
Downloading file:
downloadFile() {
const bytesView = new Uint8Array(this.byteArray);
const str = new TextDecoder('windows-1252').decode(bytesView); //windows-1252 encoding used here for cirilic
const file = new Blob([str], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'});
saveAs(file, 'test.dotx');
}
Did not find similar issues in Internet, I guess it is not standard way of dealing with files. Is it ever possible to process MS Word files as byte array with JS?
Another important question - is it safe to upload a file as an array of bytes, saved in database?
Appreciate any help.
I successfully passed an image as binary string out of puppeteers page.evaluate() function back to node.js using:
async function getBinaryString(url) {
return new Promise(async (resolve, reject) => {
const reader = new FileReader();
const response = await window.fetch(url)
const data = await response.blob();
reader.readAsBinaryString(data);
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject('Error occurred while reading binary string');
});
}
I am able to save it with:
fs.writeFileSync(“image.png”, new Buffer.from(binaryString, "binary"), function (err) { });
But now I wish to convert this PNG image to base64 without saving it to file first because I will upload it to a different server. If I save it to file, I can do the following:
function base64Encode(file) {
const bitmap = fs.readFileSync(file);
return new Buffer.from(bitmap).toString('base64');
}
How do I skip the file saving part and get proper base64 data for my PNG?
I tried to pass binary string to new Buffer.from(binaryString).toString('base64') but I was unable to save it as a working PNG.
This doesn’t really warrant answering my own question but #Jacob reminded me that I forgot to try:
new Buffer.from(binaryString, 'binary').toString('base64');
with a "binary" parameter, which solved the issue and PNG was correctly formatted again when going from base64 to file or to image in a browser.
Maybe the code in question can be reused by some other puppeteer user, it took me a while to come up with and find pieces across the web.
I want to..
.. convert an ICO file (e.g. http://www.google.com/favicon.ico ) to a PNG file after I downloaded it.
.. preserve transparency.
.. apply the solution in a node.js application.
I don't want to and already tried to ..
.. use native tools such as imagemagick (that's what I currently use in my application, but it's really bad for maintaining platform independency).
.. use tools that internally use native tools (e.g. gm.js).
.. rely on webservices such as http://www.google.com/s2/favicons?domain=www.google.de that don't allow configuring the resulting size or require payments or logins.
Therefore I'd love a Javascript-only solution. I used Jimp in another application, but it does not support ICO files.
Any help is appreciated. Thanks!
Use a FileReader() . Convert the Base64 to a data/png. Done.
const inputFile = __dirname + "/favicon.ico";
const outputFile = __dirname + "/favicon.png";
(function( inputFile, outputFile ) {
const fileApi = require("file-api");
const fs = require("fs");
const File = fileApi.File;
var fileReader = new fileApi.FileReader();
fileReader.readAsDataURL(new File(inputFile));
fileReader.addEventListener("load", function (ev) {
var rawdata = ev.target.result;
rawdata = rawdata.replace(/.*base64,/, "");
fs.writeFileSync(outputFile, rawdata, "base64");
});
})(inputFile, outputFile);
I am not familiar with Node environment but I wrote this ES6 module PNG2ICOjs using purely Javascript ArrayBuffer or Blob and can 100% run on client-side browsers (I assume Node file should act like a Blob).
import { PngIcoConverter } from "../src/png2icojs.js";
// ...
const inputs = [...files].map(file => ({
png: file
}));
// Result is a Blob
const resultBlob1 = await converter.convertToBlobAsync(inputs); // Default mime type is image/x-icon
const resultBlob2 = await converter.convertToBlobAsync(inputs, "image/your-own-mime");
// Result is an Uint8Array
const resultArr = await converter.convertAsync(inputs);
I am new to java and javascript programing.
I was able to write a piece of code in java to access a particular URL and download the wav file from that URL (this url returns a wav file).
url = new URL('url name');
input = url.openStream();
output = new FileOutputStream (wavfile);
byte[] buffer = new byte[500];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
output.close();
I do not want to do this in Java and want to be able to do it in Javascript. The main attempt is to use javascript and get the wav file and play it on a HTML5 enabled browser.
I eventually want to put it on an android platform, so do not prefer to use ajax or jquery.
Please suggest how this can be done in javascript.
Thanks,
axs
You couldn't use JavaScript to read files but HTML5 has a File API, take a look at:
http://dev.w3.org/2006/webapi/FileAPI/
READING FILES IN JAVASCRIPT USING THE FILE APIS
export async function loadWavFromUrl(audioContext, url) {
const response = await fetch(url);
const blob = await response.blob()
const arrayBuffer = await blob.arrayBuffer();
return await audioContext.decodeAudioData(arrayBuffer);
}
I recommend reusing AudioContext instances, which is why there is a param for it. You can call like this:
const ac = new AudioContext();
loadWavFromUrl(audioContext, url).then(audioBuffer => ...do stuff with it...);
The OP is maybe confused about reusing Javascript code in Java/Android. The code will be different.