I tried to write a bit of code to retrieve an image file (from Wikimedia Commons), store it locally and then display it. Here my code:
<!DOCTYPE html>
<html>
<head>
<script>
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function onError(e) {
console.log('Error', e);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://upload.wikimedia.org/wikipedia/fr/2/26/10_francs_Mathieu_1987_F365-28_revers.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {alert(fs.root.name);}, onError);
window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
fs.root.getFile('image.jpg', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwrite = function(e) {};
writer.onerror = function(e) {};
var blob = new Blob([xhr.response], {type: 'image/jpeg'});
writer.write(blob);
}, onError);
}, onError);
}, onError);
window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
fs.root.getFile('image.jpg', {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(event) {
var img = document.createElement("img");
img.src = event.target.result;
document.body.parentNode.insertBefore(img, document.body.nextSibling);
};
reader.readAsDataURL(file);
}, onError);
}, onError);
}, onError);
};
xhr.send();
</script>
</head>
<body>
</body>
</html>
Nothing is displayed. Chrome's console doesn't display any error message, so I have no idea why it's not working. Any clue?
Edit :
I have just seen I actually get a FileError, code 10, which means QUOTA_EXCEEDED_ERR, even if I start my Google Chrome with these parameters:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files --unlimited-quota-for-files
Actually, I get the same error with or without the --unlimited-quota-for-files parameter, which is weird. But I get a File Error 2 without --allow-file-access-from-files
In answer to your questions about why launching with "--unlimited-quota-for-files" won't work, I think you're confusing two different things. That parameter simply removed the quota limit, it does not automatically pre-approve scripts to usurp space in the sandbox without permission. If you were using "temporary" file system request, then it would allocate it without prompt (see link at the end of my answer).
But as you experienced by needing to call the requestQuota() method, Chrome will not allow the allocation of persistent file system storage without explicit user permission. There are a few reasons for this, but security as the best: namely that if Chrome were to allocate persistent file system storage on demand (without user knowledge) to any script that asked for it, then a malicious script could quick easily fill a user's hard drive, crash Chrome memory due to many thousands of objects, and cause general mayhem. Such a vulnerability could also trigger buffer overflows by hammering the memory like that.
Bottom line: Chrome only allows persistent file system storage with user approval. More from Google: Managing HTML5 Offline Storage:Persistent storage
If anyone stumbles across this the --unlimited-quota-for-files is no longer a valid flag. However, there is a list of current chromium flags maintained here.
--unlimited-storage would be the new flag to run, I believe.
Overrides per-origin quota settings to unlimited storage for any apps/origins. This should be used only for testing purpose.
I think you had to update to the quota request because the flag didn't override anything (but I don't actually know when the flag itself was deprecated). Because it didn't work as it previously did (assuming your code either worked before, or you got it from a tutorial) I think the browser fell-back on the quota system when the overide didn't happen and saw the quota was exceeded with what you were doing, thus throwing the exception.
You got the File Error without the --allow-file-access-from-files because it'd be a security issue if the browser was allowed to access those files under normal operation, hence the File Error should've been of type SECURITY_ERR.
The information in the following link is old, but the tactic is similar to the code in question(the flag being --unlimited-storage now instead).See this article for more details.
All said, In an actual application the Quota request is a must and the OP's solution at the time of this writing contained the correct code. Currently the javascript for the quota and fs request would look as follows:
navigator.webkitPersistentStorage.requestQuota(1024*1024, function(mB){
window.requestFileSystem(PERSISTENT, mB, function(fs){
//fs write/read, ect. code goes here. Or set a global variable to the value fs
globalFS = fs; //to be accessed later in code, so you don't have to keep requesting.
}, onError);
}, onError);
I added a call to window.webkitStorageInfo.requestQuota, and now it works. I can't get why it is necessary, as I started Chrome with the --unlimited-quota-for-files option.
Here the working code:
<!DOCTYPE html>
<html>
<head>
<script>
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function onError(e) {
console.log('Error', e);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://upload.wikimedia.org/wikipedia/fr/2/26/10_francs_Mathieu_1987_F365-28_revers.jpg', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
fs.root.getFile('image.jpg', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwrite = function(e) {};
writer.onerror = function(e) {};
var blob = new Blob([xhr.response], {type: 'image/jpeg'});
writer.write(blob);
}, function(e) {
console.log('Error', e);
});
}, function(e) {
console.log('Error', e);
});
}, function(e) {
console.log('Error', e);
});
}, function(e) {
console.log('Error', e);
});
window.requestFileSystem(PERSISTENT, 1024 * 1024, function(fs) {
fs.root.getFile('image.jpg', {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(event) {
var img = document.createElement("img");
img.src = event.target.result;
document.body.parentNode.insertBefore(img, document.body.nextSibling);
};
reader.readAsDataURL(file);
}, function(e) {
console.log('Error', e);
});
}, function(e) {
console.log('Error', e);
});
}, function(e) {
console.log('Error', e);
});
};
xhr.send();
</script>
</head>
<body>
</body>
</html>
Related
Currently i am working on opening pdf document in angularjs w.r.t. desktop/ mobile also.
i have followed this ref.:
Open a PDF in a new window of the browser with angularjs
there similar implementation i have done :
code is as follows
**$http.get('generatePdfUrl')
.then(function (data) { // data is your url
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
});**
even i have applied responsetype : 'arraybuffer' as well,
in the angularjs web application this url points to
blob://http://localhost:8080/126gyesdfsdfadjf,
its is opening pdf document properly with window.open(fileURL),
but the same is not working for the angularjs mobile application using cordova build,
there application url points out to blob:file///126gyesdfsdfadjf,
but unable to open pdf document,
can anybody have suggestions on this.
regars,
vasu.
For this, you need to install a plugin for opening the pdf document.
function writePDFToFile(fileName, 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){
console.log('Error status: ' + e.status + ' - Error message: ' + e.message);
},
success: function () {
console.log('file opened successfully');
}
});
};
fileWriter.onerror = function(e){
alert(e);
};
var blob = new Blob([data], { type: 'application/pdf' });
fileWriter.write(blob);
}, function onerror(e){
alert(e);
});
}, function onerror(e){
alert(e);
});
},function onerror(e){
alert(e);
});
}catch(e){
alert(e);
}
}
above implementation worked for me.
Check this link for plugin.
I am having a problem with this code. i wanna process the cordova android image url ( ie. stored in localStorage ) to upload in my web server.
function processImages(list, i){
var images = list[i].images;
images && images.forEach(function(image, j){
window.resolveLocalFileSystemURI(image, function(entry) {
var reader = new FileReader();
reader.onloadend = function(evt) {
list[i].images[j] = evt.target.result;
}
reader.onerror = function(evt) {
alert("error");
}
entry.file(function(f) {
//alert("Image is added");
reader.readAsDataURL(f);
}, function(e) {
alert('Image process error : '+e);
});
});
});
}
This code runs good if i am enabling #alert("Image is added"); this alert.
without this alert the app is shutting down by giving error unfortunately appname has stopped.
Its also not working for n number of images of size more than 2mb.
Note : consider async call and image size is more than 2mb each minimum 10 image per record.
Please help me !!!
Thanks
How can I convert a file (png/jpg/word/excel etc) to base64 format if I have url of the file (in the browser's sandboxed LocalFileSystem) which is already there in client system using javascript.
I had tried using creating canvas(image).
I also tried file control.
I don't want to use any control as we have url of the file in the sqllite db.
I tried
function UploadAttachmentfile() {
try {
if(objAttachment.length >0)
{
var ctn = objAttachment.length;
for (var j = 0; j < ctn; j++) {
var row = objAttachment[j].IMGS; \\image
var fname = row.split('\\').pop().split('/').pop();
alert(fname);
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fs) {
alert('request file system');
fs.root.getDirectory("Foldername", null, function (entry) {
alert('ENTRY : '+entry);
entry.getFile(fname, null, function (fileEntry) {
fileEntry.file(gotFile, fail);
}, fail);
}, fail);
}, fail);
function gotFile(file) {
readDataUrl(file);
}
function readDataUrl(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
alert("Read as data URL");
alert("target result :"+evt.target.result);
};
reader.readAsDataURL(file);
}
function fail(evt) {
alert('fail');
alert(evt.target.error.code);
}
}
}
}
catch (err) {
}
}
But it always alert fail only.
If you want to get the file on the user's computer WITHOUT the user selecting it (EVERY SESSION AGAIN), then, you can not do it (thank <enter deity here>). I highly reccomend to read this answer linked here for a complete and up-to-date explenation.
If however your user selects the file during his session via an file-input enabled element, then it is simple:
Assuming you've got the url using createObjectURL() after the user selected the file(s), then you simply use the file-reader's readAsDataURL( fileObject || local URL ) method:
fileReader.readAsDataURL( fileObject );
That will encode it to base64.
EDIT:
turns out you are developing for mobile phone using Cordova (I've added that tag to your Question). However that's still based on the file-api and has the same .readAsDataURL() method: see documentation here. It contains simple examples and notes on different mobile platforms!
Also, it seems you are trying to get a file from the LocalFileSystem interface of the File System API (that gives you access to the browser's sandboxed file system). So the other answer I linked to doesn't apply (much).
The following example (modified from the documentation linked above) should get you started:
<!DOCTYPE html>
<html>
<head>
<title>FileReader Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-2.5.0.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for Cordova to load
//
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
}
// Cordova is ready
//
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}
function gotFS(fileSystem) {
fileSystem.root.getFile("readme.txt", null, gotFileEntry, fail);
}
function gotFileEntry(fileEntry) {
fileEntry.file(gotFile, fail);
}
function gotFile(file){
readDataUrl(file);
}
function readDataUrl(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("Read as data URL");
console.log(evt.target.result);
};
reader.readAsDataURL(file);
}
function fail(evt) {
console.log(evt.target.error.code);
}
</script>
</head>
<body>
<h1>Example</h1>
<p>Read File</p>
</body>
</html>
From here on, you change the console.log(evt.target.result); part: instead of writing the base64 output to the console, you send that string back to the server (again using AJAX, etc.)
Done :)
Is there a possibility to check the connection to the network in a Firefox extension?
I just want to know if the user is Online or Offline.
I've already tried navigator.online, but it doesn't work.
https://developer.mozilla.org/en-US/docs/Online_and_offline_events is what you're looking for.
And now I'll just ramble to get beyond 30 chars, thanks stackoverflow.
As I'm learned, the Firefox doesn't know if I cut the network connection. So I've created a little XMLHttpRequest (XHR) to set a Boolean:
var netOnline;
function createXMLHttpRequest() {
return Components.classes["#mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
}
function issueRequest() {
var req = createXMLHttpRequest();
req.open("GET", "http://google.com", true);
req.timeout = 1000; // ms
// online
req.addEventListener("load", function(event) {
netOnline = true;
});
// timeout -> offline
req.addEventListener("timeout", function(event) {
netOnline = false;
});
// error -> offline
req.addEventListener("error", function(event) {
netOnline = false;
});
req.send();
};
It works fine. Anyhow thanks for your help!
Is it possible with javascript to convert text from text-input and upload it as a file to server? I need to add to page something like text editor to open text file, then change it and upload to server as file but not as value of parameter in post request.
So is it possible to do?
Thanks.
If the browser supports XMLHttpRequest 2 (see http://caniuse.com/xhr2), you have an option.
The Uploading a file or blob: xhr.send(Blob) section of the HTML5 Rocks Tutorial (New Tricks in XMLHttpRequest2) has some sample code to get you started:
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));