How to create an AudioBuffer from a Blob? - blob

I have an audio file/blob that has been created using the MediaRecorder api:
let recorder = new MediaRecorder(this.stream)
let data = [];
recorder.ondataavailable = event => data.push(event.data);
and then later when the recording is finished:
let superBlob = new Blob(data, { type: "video/webm" });
How can I use this blob to create an AudioBuffer? I need to either :
Transform the Blob object into an ArrayBuffer which I could use with AudioContext.decodeAudioData (returns an AudioBuffer) or
Transform the Blob object into an Float32Array, where I could copy it into the AudioBuffer with AudioBuffer.copyToChannel()
Any tips on how to achieve that are appreciated. Cheers!

To convert a Blob object to an ArrayBuffer, use FileReader.readAsArrayBuffer.
let fileReader = new FileReader();
let arrayBuffer;
fileReader.onloadend = () => {
arrayBuffer = fileReader.result;
}
fileReader.readAsArrayBuffer(superBlob);

The accepted answer is great but only gives an array buffer which is not an audio buffer. You need to use the audio context to convert the array buffer into an audio buffer.
const audioContext = AudioContext()
const fileReader = new FileReader()
// Set up file reader on loaded end event
fileReader.onloadend = () => {
const arrayBuffer = fileReader.result as ArrayBuffer
// Convert array buffer into audio buffer
audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => {
// Do something with audioBuffer
console.log(audioBuffer)
})
}
//Load blob
fileReader.readAsArrayBuffer(blob)
I wish the answer had included an example using decodeAudioData. I had to find it somewhere else and I thought since this is the top search for "Blob to Audio Buffer" I would add some helpful information for the next person that comes down this rabbit hole.

All the answers are true. However, in the modern web browsers like Chrome 76 and Firefox 69, there is a much simpler way: using Blob.arrayBuffer()
Since Blob.arrayBuffer() returns a Promise, you can do either
superBlob.arrayBuffer().then(arrayBuffer => {
// Do something with arrayBuffer
});
or
async function doSomethingWithAudioBuffer(blob) {
var arrayBuffer = await blob.arrayBuffer();
// Do something with arrayBuffer;
}

A simplified version using an async function:
async function blobToAudioBuffer(audioContext, blob) {
const arrayBuffer = await blob.arrayBuffer();
return await audioContext.decodeAudioData(arrayBuffer);
}
I put audioContext as a param, because I recommend reusing instances.

Both Answers are true, there are some minor changes. This is the function I finally used:
function convertBlobToAudioBuffer(myBlob) {
const audioContext = new AudioContext();
const fileReader = new FileReader();
fileReader.onloadend = () => {
let myArrayBuffer = fileReader.result;
audioContext.decodeAudioData(myArrayBuffer, (audioBuffer) => {
// Do something with audioBuffer
});
};
//Load blob
fileReader.readAsArrayBuffer(myBlob);
}

Related

Convert Uint8Array to a file and save to db

I may be asking the basics just now, sorry.
I want to convert Uint8Array back to a file and save it in db.
Is there anyone who can help me?
document.getElementById('upload_0').onchange = function(event) {
var ext = $('[name=upload_0]').val().split('.').pop().toLowerCase();
var file = event.target.files[0];
var fileReader = new FileReader();
fileReader.onload = async function() {
var typedarray = new Uint8Array(this.result);
const pdfSrcDoc = await PDFLib.PDFDocument.load(typedarray);
const pdfNewDoc = await PDFLib.PDFDocument.create();
const pages = await pdfNewDoc.copyPages(pdfSrcDoc, [0,1,2]);
pages.forEach((page) => pdfNewDoc.addPage(page));
const newpdf = await pdfNewDoc.save();
download(newpdf, "sample.pdf", "application/pdf");
}
-> download(newpdf, "sample.pdf", "application/pdf");
I want to convert this part into a file, not download it, and save it in db.
Also, I want to save the file name as the original name.
Can you tell me what I want to know?
Thank you.

Is there a way to modify the buffer of a png in a pdf document?

For a few days now i have been trying to extract images from a pdf, modify them, and then replace them in my pdf document. It works perfectly when working with jpeg images, but when it comes to png... I'm able to modify the image and then save it correctly, but when changing the buffer in the pdf, it turns all black. So there's my code :
try {
(async () => {
let imageData = imgTab.type === 'jpg' ? imgTab.data : await savePng(imgTab);
console.log(imgTab.type);
let typeJimp = "image/png";
if(imgTab.type === 'jpg'){
typeJimp = "image/jpeg";
}
const img = await Jimp.read(imageData).then(async function (image) {
image.color([
{ apply: 'hue', params: [90] }]);
*//HERE, the image saved is okay! It is modified as I want it to be*
image.write("testimage"+objIdx+"."+imgTab.type);
let data = fs.readFileSync("testimage"+objIdx+"."+imgTab.type);
let bufferData = Buffer.from(data);
*//The problem is when i do this to replace the buffer of my original image*
pdfObject.contents = bufferData;
fs.writeFileSync('client/public/test_modified.pdf', await pdfDoc.save());
}).catch(function (err) {
//return Promise.reject(err);
console.log(err);
});
})();
}
The main code to extract the images can be found here : pdf-lib extract images
I don't know if there's something special to do to make the buffer work, but if you do, feel free :)
Thanks in advance !
////
Okay, so for now, i just use it that way :
const img = await Jimp.read(imageData).then(async function (image) {
image.color([
{ apply: 'hue', params: [90] }]);
let data = await image.getBufferAsync('image/jpeg')
var res = await pdfDoc.embedJpg(data);
res.ref = pdfRef;
var test = await res.embed();
fs.writeFileSync('client/public/test_modified.pdf', await pdfDoc.save());
})
My pdfRef is the ref of the initial object i was trying to modify.

How to upload static json file into indexedDB ONLY when an upgrade is needed (i.e. onupgradeneeded)

I'm tyring to upload a static json file into an indexedDB ONLY when an upgrade is needed (i.e. onupgradeneeded). I've search for answers to this repeatedly but have yet to see code examples of how to approach this.
My current code below gets the json file every time the page opens, which is of course inefficient since I only need to get the json file if the indexedDB has not yet been created or needs upgraded.
I tried putting the xhr.onload section into the end of the .onupgradeneeded function, but as many have noted, the .onsuccess gets called before the xhr.onload has completed.
var jsonUrl = '/path/to/hcLookup.json');
var req, db, hcObjectStore, objectStore, data, dataArr, trans, addreq, key;
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonUrl, true);
xhr.type='json';
xhr.send();
xhr.onload = function(msg) {
data = msg.target.response;
req = window.indexedDB.open("hcLookup", 1);
req.onerror=function(event){console.log("onerror: " + event.target.errorCode)};
req.onsuccess = function(event){
console.log("ready.");
};
req.onupgradeneeded = function(event){
db = event.target.result;
objectStore = db.createObjectStore("hcLookup", {autoIncrement: true});
objectStore.createIndex("S", "S", {unique: false});
// make sure the objectStore creation is finished before adding data into it
objectStore.transaction.oncomplete = function (event) {
// Store values in the newly created objectStore.
trans = db.transaction(["hcLookup"], "readwrite");
hcObjectStore = trans.objectStore("hcLookup");
// Do something when all the data is added to the database.
trans.oncomplete = function (event) {
console.log("upgrading done!");
};
trans.onerror = function (event) {
console.log("bulk add onerror: " + event.target.errorCode)
};
//convert JSON to an strArray in order to add the dataArr into to the objectStore
dataArr = JSON.parse(data);
for (var i in dataArr) {
addreq = hcObjectStore.add(dataArr[i]);
}
};
};
};

System.Text.Encoding in WinJS

Is there an equivalent of
System.Text.Encoding.UTF8.GetString(fileContent)
in WinJS (Windows 8 Store App written in javascript/HTML)?
EDIT. fileContent is a byte array.
There is no strict equivalent of System.Text.Encoding.UTF8.GetString in WinJS, but you can try implement file reading to string as follows:
file.openReadAsync().done(function (stream) {
var blob = MSApp.createBlobFromRandomAccessStream(file.contentType, stream);
var reader = new FileReader();
reader.onload = function(event) {
var fileAsText = event.target.result;
};
reader.readAsText(blob, 'UTF-8');
});
In most cases (file upload via XHR, displaying file) you don't need to have file contents as text, so just use Blob then.
CryptographicBuffer.convertBinaryToString can be used for this.
var crypt = Windows.Security.Cryptography;
var bytes; // = new Uint8Array(100);
// TODO - set bytes variable with uint8array
var buffer = crypt.CryptographicBuffer.createFromByteArray(bytes);
var text = crypt.CryptographicBuffer.convertBinaryToString(
crypt.BinaryStringEncoding.utf8, buffer);

HTML5 Drag n Drop File Upload

I'm running a website, where I'd like to upload files with Drag 'n Drop, using the HTML5 File API and FileReader. I have successfully managed to create a new FileReader, but I don't know how to upload the file. My code (JavaScript) is the following:
holder = document.getElementById('uploader');
holder.ondragover = function () {
$("#uploader").addClass('dragover');
return false;
};
holder.ondragend = function () {
$("#uploader").removeClass('dragover');
return false;
};
holder.ondrop = function (e) {
$("#uploader").removeClass('dragover');
e.preventDefault();
var file = e.dataTransfer.files[0],
reader = new FileReader();
reader.onload = function (event) {
//I shoud upload the file now...
};
reader.readAsDataURL(file);
return false;
};
I also have a form (id : upload-form) and an input file field (id : upload-input).
Do you have any ideas?
P.S. I use jQuery, that's why there is $("#uploader") and others.
Rather than code this from scratch, why not use something like html5uploader, which works via drag n drop (uses FileReader etc.): http://code.google.com/p/html5uploader/
EDIT: apparently we respondents are supposed to tend to our answers forever more, for fear for down-votes. The Google Code link is now dead (four years later), so here's a jQuery plugin that is very similar: http://www.igloolab.com/jquery-html5-uploader/
You'll want to extract the base64 encoded file contents and ajax them over tot the server.
JavaScript
var extractBase64Data;
extractBase64Data = function(dataUrl) {
return dataUrl.substring(dataUrl.indexOf(',') + 1);
};
// Inside the ondrop event
Array.prototype.forEach.call(event.dataTransfer.files, function(file) {
var reader;
if (!file.type.match(options.matchType)) {
return;
}
reader = new FileReader();
reader.onload = function(event) {
var contentsBase64;
if (event.target.readyState === FileReader.DONE) {
contentsBase64 = extractBase64Data(event.target.result);
return $.post(someURL, {
contentsBase64: contentsBase64
});
}
};
reader.readAsDataURL(file);
});
CoffeeScript
extractBase64Data = (dataUrl) ->
dataUrl.substring(dataUrl.indexOf(',') + 1)
# Inside the ondrop event
Array::forEach.call event.dataTransfer.files, (file) ->
return unless file.type.match(options.matchType)
reader = new FileReader()
reader.onload = (event) ->
if event.target.readyState == FileReader.DONE
contentsBase64 = extractBase64Data(event.target.result)
$.post someURL,
contentsBase64: contentsBase64
reader.readAsDataURL(file)