Create a download link from a Blob URL - javascript

In a Google chrome extension I am working on, a file is downloaded from a server with an XMLHttpRequest. This file contains some binary data which are stored in an ArrayBuffer object. In order to provide the possibility to download this file I am using the createObjectURL API.
function publish(data) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
var url = window.webkitURL.createObjectURL(blob);
$("#output").append($("<a/>").attr({href: url}).append("Download"));
}
It is working fine; except that the filename is an opaque UUID like 9a8f6a0f-dd0c-4715-85dc-7379db9ce142. Is there any way to force this filename to something more user-friendly?

you can force an arbitrary filename by setting the "download" attribute of your anchor
see: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download

I have never tried it before, but it should be possible to create a new File object (which allows you to specify a file name) and write your blob to it. Something along the lines of:
function publish(data, filename) {
if (!window.BlobBuilder && window.WebKitBlobBuilder) {
window.BlobBuilder = window.WebKitBlobBuilder;
}
fs.root.getFile(filename, {
create: true
}, function (fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function (e) {
console.log('Write completed.');
};
fileWriter.onerror = function (e) {
console.log('Write failed: ' + e.toString());
};
var builder = new BlobBuilder();
builder.append(data);
var blob = builder.getBlob();
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
I think this could work for you.

Related

How to Convert Uploaded Audio to Blob using Javascript?

I am trying to capture the audio that's uploaded by the user, convert it to Blob then using wavesurfer.js to display the waveform.
I am following this instruction here https://bl.ocks.org/nolanlawson/62e747cea7af01542479
And here is the code
// Convert audio to Blob
$('#audioFileInput').on('change', function () {
var file = $('#audioFileInput')[0].files[0];
var fileName = file.name;
var fileType = file.type;
var fileReader = new FileReader();
fileReader.onloadend = function (e) {
var arrayBuffer = e.target.result;
blobUtil.arrayBufferToBlob(arrayBuffer, fileType).then(function (blob) {
console.log('here is a blob', blob);
console.log('its size is', blob.size);
console.log('its type is', blob.type);
surfTheBlob(blob);
}).catch(console.log.bind(console));
};
fileReader.readAsArrayBuffer(file);
});
But it says
blobUtil.arrayBufferToBlob(...).then is not a function
Another issue is that since the user might upload the audio themselves, the audio type might vary, expected to come from native device audio recorder. Anyone can help please? thanks.
A File object, like the ones you get in the input.files FileList, is already a Blob:
inp.onchange = e =>
console.log(inp.files[0] instanceof Blob) // true
<input type="file" id="inp">
So all you really need is to pass directly this File to your library:
$('#audioFileInput').on('change', function () {
var file = this.files[0];
surfTheBlob(file);
});
Found the answer already.
// Convert audio to Blob
$('#audioFileInput').on('change', function () {
var file = $('#audioFileInput')[0].files[0];
var fileName = file.name;
var fileType = file.type;
var url = URL.createObjectURL(file);
fetch(url).then(function(response) {
if(response.ok) {
return response.blob();
}
throw new Error('Network response was not ok.');
}).then(function(blob) {
surfTheBlob(blob);
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ', error.message);
});
});
Cheers!

Download binary data into the app sandbox using XHR2 request instead of cordova-file-transfer

Cordova is "sunsetting" (going to deprecate) cordovan-plugin-file, see their blogpost.
No more work will be done on the file-transfer plugin by the Cordova development community.
You can continue to use the file-transfer plugin if you wish - it should work fine as-is for the foreseeable future.
We highly suggest Cordova users transition to using the standards-compliant way of sending and receiving binary data.
They are encouraging a transition to use XHR2 requests (XHR Requests where the responseType is set to Blob or ArrayBuffer.
The blog post wants to provide an example how binary data can be fetched using XHR2:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
console.log('file system open: ' + fs.name);
fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
console.log('fileEntry is file? ' + fileEntry.isFile.toString());
var oReq = new XMLHttpRequest();
// Make sure you add the domain name to the Content-Security-Policy <meta> element.
oReq.open("GET", "http://cordova.apache.org/static/img/cordova_bot.png", true);
// Define how you want the XHR data to come back
oReq.responseType = "blob";
oReq.onload = function (oEvent) {
var blob = oReq.response; // Note: not oReq.responseText
if (blob) {
// Create a URL based on the blob, and set an <img> tag's src to it.
var url = window.URL.createObjectURL(blob);
document.getElementById('bot-img').src = url;
// Or read the data with a FileReader
var reader = new FileReader();
reader.addEventListener("loadend", function() {
// reader.result contains the contents of blob as text
});
reader.readAsText(blob);
} else console.error('we didnt get an XHR response!');
};
oReq.send(null);
}, function (err) { console.error('error getting file! ' + err); });}, function (err) { console.error('error getting persistent fs! ' + err); });
I have some issues understanding the code above and the intention of cordova to drop the file-tranfer plugin in favour of
directly fetching the Blobs via Ajax.
Am I seeing this right:
fs.root.getFile creates a file. The download success handler (oReq.onload) does not attempt
to write the fetched blob to the created file. There is no clear reason why the fileEntry is created.
If I would want to save the fetched blob to the created FileEntry, within oReq.onload
I could go on using a FileWriter, but only for small (I read up to 5 MB) files (since the Blob is handled in-memory).
The blog post is more about how a blob can be fetched in general and not about it can
be downloaded into the filesystem. If I would want to download bigger files (like a couple of 100 MB),
moving away from cordova-plugin-filetransfer is not an option at the moment.
With this code you can download big images as they are written by blocks of 1MB instead of doing the whole write at once.
Without the 1MB writting I wasn't able to write files bigger than 4MB, but with this I've tested with files up to 40MB without problems
window.resolveLocalFileSystemURL(cordova.file.externalDataDirectory,
function (dirEntry) {
console.log('file system open: ' + dirEntry.name);
createFile(dirEntry, "downloadedImage.jpg");
}, onFSError);
function onFSError(error) {
alert(JSON.stringify(error));
}
function createFile(dirEntry, fileName) {
// Creates a new file or returns the file if it already exists.
dirEntry.getFile(fileName, {create: true, exclusive: false}, function(fileEntry) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://static.vix.com/es/sites/default/files/styles/large/public/imj/3/30-cosas-de-los-gatos-que-no-sabias-3.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function() {
if (this.status == 200) {
var blob = new Blob([this.response], { type: 'image/jpeg' });
writeFile(fileEntry, blob);
}
};
xhr.send();
}, onFSError);
}
function writeFile(fileEntry, data) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function (fileWriter) {
fileWriter.onerror = function(e) {
console.log("Failed file write: " + e.toString());
};
function writeFinish() {
function success(file) {
alert("Wrote file with size: " + file.size);
}
function fail(error) {
alert("Unable to retrieve file properties: " + error.code);
}
fileEntry.file(success, fail);
}
var written = 0;
var BLOCK_SIZE = 1*1024*1024; // write 1M every time of write
function writeNext(cbFinish) {
fileWriter.onwrite = function(evt) {
if (written < data.size)
writeNext(cbFinish);
else
cbFinish();
};
if (written) fileWriter.seek(fileWriter.length);
fileWriter.write(data.slice(written, written + Math.min(BLOCK_SIZE, data.size - written)));
written += Math.min(BLOCK_SIZE, data.size - written);
}
writeNext(writeFinish);
});
}

How to read and write from a file in Javascript

There are many similar questions to this, however, when I used the code provided, it didn't work. My code is as follows:
function write(fs) {
fs.root.getFile('archive.txt', {create: true}, function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var blob = new Blob([prompt("MESSAGE: ")], {type: 'text/plain'});
fileWrite.write(blob);
}, errorHandler);
}, errorHandler);
}
function onInitFs(fs) {
fs.root.getFile('archive.txt', {}, function(fileEntry) {
// Get a File object representing the file,
// then use FileReader to read its contents.
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
The file archive.txt does exist but when I call the function, it doesn't work. So instead I used window.requestFileSystem() which I found on a website. However, when I compile this code through Github, it doesn't work.
Also, if someone could tell me a way to read and write to a file without using php as this is all in html file using Github without git. I have another file in Github in the same directory as this. Would I need to include the full directory rather than archive.txt?
It's not possible without server side code.
I've asked a similar question a while ago.

How long does a Blob file created in Google Chrome Exist?

Part of a Google Chrome Extension I am working on has this existing JavaScript below for creating a Blog file from a screenshot image...
getBlob = function(canvas) {
// standard dataURI can be too big, let's blob instead
// http://code.google.com/p/chromium/issues/detail?id=69227#c27
var dataURI = canvas.toDataURL(),
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
byteString = atob(dataURI.split(',')[1]),
// separate out the mime component
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0],
// write the bytes of the string to an ArrayBuffer
ab = new ArrayBuffer(byteString.length),
ia = new Uint8Array(ab),
i;
for (i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: mimeString});
},
saveBlob = function(blob, filename, callback, errback) {
var onWriteEnd = function() {
// Return the name of the file that now contains the blob.
callback('filesystem:chrome-extension://' + chrome.runtime.id + '/temporary/' + filename);
};
window.webkitRequestFileSystem(TEMPORARY, 1024*1024, function(fs){
fs.root.getFile(filename, {create:true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = onWriteEnd;
fileWriter.write(blob);
}, errback);
}, errback);
}, errback);
},
Looking at saveBlob(blob, filename, callback, errback) above. How long would a file created this way exist? Does it disappear when the browser is closed?
The file would exist until directly deleted by user or Clear browsing data is used at settings; though there is no guarantee of persistence.
4.4.1.2 Constants
TEMPORARY of type unsigned short Used for storage with no
guarantee of persistence.
See also Temporary storage

Cordova write PDF to file

I whant to write a Cordova App for BlackBerry10 that can write a PDF file (from a SharePointWebservice) and show it.
The PDF is transmitted from a ASP.NET Webservice as byte[] using
byte[] result = spFile.OpenBinary();
I'm able to access the file with JSON. This works fine.
To transform the data fromm JSON to usable format I use the following code:
var binary = '';
var bytes = new Uint8Array(data.d);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(data.d[i]);
}
binary is now looking like that:
%PDF-1.5%ยตยตยตยต 1 0 obj ... startxref 103423 %%EOF
Here is the Code to write it to a file using cordova-plugin-file.
var blob = new Blob([binary], { type: 'application/pdf' });
fileWriter.write(blob);
It works fine for txt files, but when I try to write the PDF file I get an empty document.
I have also tryed window.btoa(binary) instead of just using binary.
Any ideas what ho to create the data blob, or which format to use?
I have solved the Problem by using the cordova fileOpener2 Plugin. I am using the var "bytes" from above filled into the new named variable data.
try {
window.resolveLocalFileSystemURL(cordova.file.externalApplicationStorageDirectory, function (directoryEntry) {
directoryEntry.getFile(fileName, { create: true }, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
fileWriter.onwriteend = function (e) {
cordova.plugins.fileOpener2.open(cordova.file.externalApplicationStorageDirectory + fileName, 'application/pdf',
{
error: function (e) {
...
},
success: function () {
... //PDF has opened
}
}
);
};
fileWriter.onerror = function (e) {
...
};
//Blob erstellen - Blackberry File Plugin verwenden
var blob = new Blob([data], { type: 'application/pdf' });
fileWriter.write(blob);
}, function onerror(e) {
...
});
}, function onerror(e) {
...
});
}, function onerror(e) {
...
});
} catch (e) {
...
}
Used Plugins:
cordova-plugin-file &
cordova-plugin-file-opener2
For other file types like PNG I use (for jpg just replace png with jpg):
var blob = new Blob([data], { type: 'image/png' });
to write the file and
window.open(cordova.file.externalApplicationStorageDirectory + fileName);
to open and show it.
Showing txt files is quite easy, you can do it like that:
if (fileName.split('.')[1].indexOf("txt") > -1) {
var blob = new Blob([bytes], { type: 'text/plain' });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
This worked for me, comment if you have any questions.

Categories

Resources