base64 encoded image is corrupted when saved to disk - javascript

I am posting the base64 clipboard image to server (node) and I am saving the base64 to disk. For some reason the image is corrupted.
Client side logic of posting:
function sendData($http, clipboardImage) {
// $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
// var imgData = JSON.stringify(clipboardImage);
//var data = {"imgdata" : clipboardImage};
var url = "http://localhost:3000/pad/img/";
$http({
method: 'POST',
url: url,
data: "data=" + clipboardImage
});
}
$("[ng-model='html']").delegate("p", "paste", function(event) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
console.log(JSON.stringify(items)); // will give you the mime types
// find pasted image among pasted items
var blob = null;
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === 0) {
blob = items[i].getAsFile();
}
}
// load image if there is a pasted image
if (blob !== null) {
var reader = new FileReader();
reader.onload = function(e) {
sendData($http, e.target.result);
};
reader.readAsDataURL(blob);
}
});
Server logic:
app.post("/pad/img/", function(req, res) {
var imgB64Data = req.body.data;
var decodedImg = decodeBase64Image(imgB64Data);
var imageBuffer = decodedImg.data;
var type = decodedImg.type;
var extension = mime.extension(type);
var fileName = "image." + extension;
try {
fs.writeFile(fileName, imageBuffer, function(err) {
console.log(err);
});
} catch (err) {
console.error(err);
}
});
function decodeBase64Image(dataString) {
var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/),
response = {};
if (matches.length !== 3) {
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
return response;
}
The image is being saved successfully but it seems to be corrupted. Can you please point out what may be missing?

Have you tried explicitly setting the file encoding when calling fs.writeFile?
try {
fs.writeFile(fileName, imageBuffer, {encoding:'utf8'}, function(err) {
console.log(err);
});
} catch (err) {
console.error(err);
}
NodeJS Docs: fs.writeFile(filename, data\[, options\], callback)

Related

How to download multiple audio filles in JsZip

I want to download all audio files from folder but this code only download last file in folder.
var element = document.getElementById("songs");
var audionum = element.getElementsByTagName('audio').length;
var zipcounter = 0;
var zip = new JSZip();
var zipName = 'Test.zip';
for(var i = 0; i < audionum; i++){
var audiosrc = document.getElementsByTagName('source')[i].getAttribute("src");
var audiosrcsplit = audiosrc.split('/')[1];
// loading a file and add it in a zip file
JSZipUtils.getBinaryContent(audiosrc, function (err, data) {
if(err) {
throw err; // or handle the error
}
zip.file(audiosrcsplit, data, {binary:true});
zipcounter++;
if (zipcounter == audionum) {
zip.generateAsync({type:'blob'}).then(function(content) {
saveAs(content, zipName);
});
}
});
}
For ES6 , you can try replacing var with let (block scope).
If you are making use of ES5 then, try something like below.
var element = document.getElementById("songs");
var audionum = element.getElementsByTagName('audio').length;
var zipcounter = 0;
var zip = new JSZip();
var zipName = 'Test.zip';
function addToZip(audiosrc, audiosrcsplit) {
JSZipUtils.getBinaryContent(audiosrc, function (err, data) {
if (err) {
throw err; // or handle the error
}
zip.file(audiosrcsplit, data, {
binary: true
});
zipcounter++;
if (zipcounter == audionum) {
zip.generateAsync({
type: 'blob'
}).then(function (content) {
saveAs(content, zipName);
});
}
});
}
for (var i = 0; i < audionum; i++) {
var audiosrc = document.getElementsByTagName('source')[i].getAttribute("src");
var audiosrcsplit = audiosrc.split('/')[1]; // loading a file and add it in a zip file
addToZip(audiosrc, audiosrcsplit);
}

Generate Zip file contain list of Files without JSZip library

Hello Developers,
I'm trying to download the list of files getting form XMLHttpRequest() request method and store it in the array of files. I wanted to zip all the files in an array using javascript without using any 3rd party library.
I have tried to achieve this by URL.createObjectURL(url) and URL.revokeObjectURL(url) method but the file I'm getting is corrupted.
I'm Sharing my code snippet please help me out
const URLS = [
'https://vr.josh.earth/assets/2dimages/saturnv.jpg',
'https://vr.josh.earth/assets/360images/hotel_small.jpg',
'https://vr.josh.earth/assets/360images/redwoods.jpg'
];
$(document).ready(function () {
debugger
$("#downloadAll").click(function () {
var blob = new Array();
var files = new Array();
URLS.forEach(function (url, i) {
getRawData(url, function (err, data) {
debugger
var mydata = data;
// mydata = btoa(encodeURIComponent(data));
// var blobData = b64toBlob(mydata , 'image/jpg');
var blobData = new Blob([mydata], { type: 'image/jpg' });
blob.push(blobData);
var filename = "testFiles" + i + ".jpg";
var file = blobToFile(blobData, filename);
files.push(file);
debugger
if (files.length == URLS.length) {
// saveData(blob, "fileName.zip");
var AllBlobData = new Blob([blob], { type: 'application/zip' });
saveData(AllBlobData, "Test.zip");
// saveFile("DownloadFiles.zip", "application/zip", files)
}
});
});
});
});
//Retriving record using XMLHttpRequest() method.
function getRawData(urlPath, callback, progress) {
var request = new XMLHttpRequest();
request.open("GET", urlPath, true);
request.setRequestHeader('Accept', '');
if ('responseType' in request)
request.responseType = "arraybuffer"
if (request.overrideMimeType)
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send();
var file, err;
request.onreadystatechange = function () {
if (this.readyState === 4) {
request.onreadystatechange = null;
if (this.status === 200) {
try {
debugger
var file = request.response || request.responseText;
} catch (error) {
throw error;
}
callback(err, file);
} else {
debugger
callback(new Error("Ajax Error!!"))
}
} else {
debugger
}
}
}
//For Saving the file into zip
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
// var AllBlobs = new Blob([data], { type: "" });//application/zip //octet/stream
// var url = window.URL.createObjectURL(AllBlobs);
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
//Downloaded Zip File
enter image description here

How to add an attachement to an email (not stored in file disk)

I want to open outlook with an attachement (zip) using Javascript.
It's working fine if the file in in some directory in the computer client.
this.sendEmail = function (zip) {
try {
var theApp = new ActiveXObject("Outlook.Application");
var objNS = theApp.GetNameSpace('MAPI');
var theMailItem = theApp.CreateItem(0); // value 0 = MailItem
theMailItem.to = ('test#gmail.com');
theMailItem.Subject = ('test');
theMailItem.Body = ('test');
theMailItem.Attachments.Add(zip);
theMailItem.display();
}
catch (err) {
alert(err.message);
}
};
But What I want to do is to add the file that I have alredy in memory
this.SenddZip = function (docDescription, fileName) {
var zip = new JSZip();
for (var i = 0; i < docDescription.length; i++) {
var doc = docDescription[i];
zip.file(doc.core_documenttitle + doc.core_fileextension, doc.fileBase64, { base64: true });
}
Utils.sendEmail(zip);
// Generate the zip file asynchronously
zip.generateAsync({ type: "blob" })
.then(function (content) {
// Force down of the Zip file
var name = "documents";
if (fileName) {
name = fileName;
}
// location.href = "data:application/zip;base64," + content;
saveAs(content, name + ".zip");
Utils.sendEmail(xxxxxxxx);
});
};
If their is no solution for this :
Is their a way to download the document without the confirmation dialog ?
saveAs ask always for confirmation before to store the file.
Thank you

Length of uploaded couchDB attachment always 0 Bytes

So...I'm new to all this stuff and I'm developing an app for android with AngularJS and Ionic Framework and try to upload an audiofile I have recorded with the cordova capture Plugin like this:
// gets called from scope
$scope.captureAudio = function() {
var options = { limit: 1, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
uploadFile(documentID, audioData);
}, function(err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (document, file) {
var baseUrl = 'urltomydatabase';
var name = encodeURIComponent'test.3gpp'),
type = file[0].type,
fileReader = new FileReader(),
putRequest = new XMLHttpRequest();
$http.get(baseUrl + encodeURIComponent(document))
.success(function (data) {
putRequest.open('PUT', baseUrl + encodeURIComponent(document) + '/' + name + '?rev=' + data._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file[0]);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent);
};
putRequest.onreadystatechange = function (response) {
if (putRequest.readyState == 4) {
//success - be happy
}
};
})
.error(function () {
// failure
});
};
How the file looks in the console.log:
Playing the recorded file on the device works nice.
But everytime I upload the recording and the upload has finished, the uploaded attachment inside the document has the length '0' in the couchDB.
How the created file looks in the database after the upload:
What am I doing wrong?
EDIT: I just found out, when I upload an image, passed from this function as blob, it works well:
function upload(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function (blob) {
uploadFile(documentID, blob);
});
};
image.onload = onload;
image.src = imageURL;
}
So maybe the solution is creating a blob from the audiofile? But everytime I try it, my blob has the size of 0 bytes even before uploading it and I don't find somewhere a great explanation of how to convert a MediaFile object to blob...
It looks like your code does not send the content of your file as multipart attachment. To see what is really send to couchdb, capture the traffic with wireshark (https://www.wireshark.org/) or such.
This thread brought me to the solution, PouchDB purifies it. Now my upload function looks like this and can handle every file format
// e.g capture Audio
$scope.captureAudio = function () {
var options = {limit: 1, duration: 10};
$cordovaCapture.captureAudio(options).then(function (audioData) {
uploadFile(documentID, audioData, 'audio');
}, function (err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (id, file, mediatype) {
var fileName = makeID();
if (mediatype == 'image') var name = encodeURIComponent(fileName + '.jpg');
if (mediatype == 'audio') var name = encodeURIComponent(fileName + '.3gpp');
if (mediatype == 'video') var name = encodeURIComponent(fileName + '.3gp');
db.get(id).then(function (doc) {
var path = file.fullPath;
window.resolveLocalFileSystemURL(path, function (fileEntry) {
return fileEntry.file(function (data) {
var reader = new FileReader();
reader.onloadend = function (e) {
var blob = b64toBlobAlt(e.target.result, file.type);
if (blob) {
db.putAttachment(id, name, doc._rev, blob, file.type).then(function () {
if (mediatype == 'video' || mediatype == 'image') getMedia();
if (mediatype == 'audio') $scope.audios.push(source);
});
}
};
return reader.readAsDataURL(data);
});
});
});
};
// creating the blob from the base64 string
function b64toBlobAlt(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
}

Cordova - Capture video and retrieve base64 data

I am using phonegap to record a video and I am wanting to save the base64 data-encoded string. So far I have tried this..
function captureSuccess(mediaFiles) {
var i, path, len;
path = mediaFiles[0];
win(path);
}
function win(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
console.log("read success");
console.log(evt.target.result);
};
reader.readAsDataURL(file);
};
function captureError(error) {
navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
}
function captureVideo() {
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 1});
}
I have used readAsDataURL as specified in the documentation. The output of evt.target.result is "data:video/mp4;base64," but there isn't any encoded data after the filetype.
Is there anything else I need to add in order to get the full base64 data of the video?
I am really struggling to find anything that can help me. Any help would be greatly appreciated.
var b64toBlobAlt = function(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
};
var path = mediaFiles[0].fullPath;
window.resolveLocalFileSystemURL(path, function(fileEntry) {
return fileEntry.file(function(data) {
var reader = new FileReader();
reader.onloadend = function(e) {
var blob = b64toBlobAlt(e.target.result, 'video/mp4');
if (blob) {
// do whatever you want with blob
});
}
};
return reader.readAsDataURL(data);
});
});

Categories