Reputation: 827
In the browser, I was building an array of image data and as you can see here, converted it to quite a few different forms in order to download it in the browser, which worked:
let clamped = Uint8ClampedArray.from(frameBuffer);
let imageData = new ImageData(clamped, width, height);
this.resultContext.putImageData(imageData, 0, 0);
this.uri = this.resultCanvas.toDataURL("image/png");
this.blob = dataURItoBlob(this.uri);
But now I'm trying to save this blob with the Node.js fs module, and this doesnt work:
fs.writeFile(this.path + "/" + angle + ".png", this.blob, err => {
if (err) {
alert("An error ocurred creating the file " + err.message);
}
console.log("The file has been successfully saved");
});
Edit: dataURItoBlob:
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(",")[0].indexOf("base64") >= 0)
byteString = atob(dataURI.split(",")[1]);
else byteString = unescape(dataURI.split(",")[1]);
// separate out the mime component
var mimeString = dataURI
.split(",")[0]
.split(":")[1]
.split(";")[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString });
}
It's not throwing an error but the resulting file is invalid. How can I fix this?
Upvotes: 2
Views: 3341
Reputation:
Looks like this works
canvas.toBlob(saveBlob);
function saveBlob(blob) {
const reader = new FileReader();
reader.onloadend = () => {
fs.writeFile('filename.png', new Uint8Array(reader.result), err => {
if (err) {
alert("An error ocurred creating the file " + err.message);
} else {
console.log("The file has been successfully saved");
}
});
}
reader.readAsArrayBuffer(blob);
}
note in 2019 I might switch to promises and async stuff. There's little bit of setup but then usage is easier for some definition of easier
const fs = require('fs'); // would prefer import
const util = require('util');
const writeFile = util.promisify(fs.writeFile);
function readBlobAsUint8Array(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
return new Uint8Array(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(blob);
});
}
function getCanvasAsBlob(canvas) {
return new Promise((resolve) => {
canvas.toBlob(resolve);
});
}
async function saveCanvasAsPNG(filename, canvas) {
const blob = await getCanvasAsBlob(canvas);
const data = await readBlobAsUint8Array(blob);
await writeFile(filename, data);
}
which can be called from another async function like
async function someFunc() {
try {
await saveCanvasAsPNG('foo.png', canvas);
console.log('success');
} catch (e) {
alert(e);
}
}
or from a non-async function as
saveCanvasAsPng('foo.png', canvas)
.then(() => {
console.log('success');
})
.catch(alert);
note this also works
const dataUrl = canvas.toDataURL();
const uu = dataUrl.substring('data:image/png;base64,'.length);
fs.writeFileSync(filename, uu, 'base64');
Upvotes: 2