How to use a File object as css image source? - javascript

I have a reference to a javascript File object (image) which was provided by the user from a "open file dialog". How do I load this image file into a css background-image without having to read all data into a base64-string first?
The examples I have found use a FileReader to read the data and then load that into the css-tag but this seems like a bit of ineffective use of memory. Since I have the File-reference it would be nice if I could pass that into the css-tag somehow instead and let the image be streamed into memory instead. The url()-wrapper for "background-image" supports local filenames but for security reasons the full path of the File is not available to my script so I can't use that.
Any suggestions?

Let's say you have your File object in a variable called file.
var url = URL.createObjectURL(file)
yourElement.style.background = `url(${url})`
https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

Related

In Javascript, when opening a file via an "input file" button, is the entire file read into memory

In javascript, when opening a file via a button returns a Blob object (e.g. blob1).
I can then get the actual data of the blob via blob1ArrayBuffer = blob1.arrayBuffer();
When the Blob object (e.g. blob1) is created, does it load all the bytes into memory?
Or does it just returns the address so that later the actual bytes can be read via blob1.arrayBuffer() ?
No, all the file isn't read in memory (you can try to open a file of a few TB, that should still work).
However note that the OS will still need to read some of that file to produce the metadata of the file. This may take some times in some conditions (e.g when selecting folders with many files, or when selecting a file from a network disk etc.)
Even when doing blob1.arraybuffer() the full file isn't necessarily put in memory, since the specs ask that all the consumers of the Blob use a ReadableStream to get the data from it. But obviously in this case, the full data will be copied in the resulting ArrayBuffer that will most probably live in memory.

Keeping information about js file in localStorage

I want to create plugin mechanizm. It is, you can load js file on my website and run your js "plugin" (function) when this plugin is set to run (toggled as running).
All this I want to do without any server.
I mean, I want to keep in localstorage js files or path to this files.
It looks to be hard to do because js can't easy access files path.
I handle file by <input type="file"/>
And I react on onchange event. I get event where I can find selected file by event.srcElement.files[0]
With that I can create URL of that object by : URL.createObjectURL(event.srcElement.files[0])
And I tried to store that URL in localstorage but this URL is temporary.
Also I tried to store whole event or just file (event.srcElement.files[0]).
But I need to create string from that if I want to put it to the function .setItem :
localStorage.setItem("functionURL", JSON.stringify(this.functionURL));
.toString() creates [Object Event/File]
JSON.stringify() creates {} from [Object Event/File]
So, maybe is there a way to somehow remember file which we can use as a function without any server ?
So, maybe is there a way to somehow remember file which we can use as a function without any server ?
Basically, no. :-) Web storage only stores strings. You can't use a string to access a file on the user's local filesystem from your web page, for obvious security reasons.
You could, instead:
Make it possible for them to "upload" the file into your page (without a server) by having them identify the file in an input[type=file], reading its text (via the File API), and then storing that text in local storage
On page load, if local storage has code to run, run it
Offer the user a way to delete or update the code they've uploaded to the page
Since all of that happens in the browser, you don't need a server.
Web storage does have size limits, though they're pretty generous, (around 2.5-5MB) and per-origin, so you have that largely to yourself. But if you run into those limits, you could take it further by caching those files via a service worker, but the complexity goes up markedly. I'd start with web storage and only move on if you really need to support massive files.
#1 (reading the script file the user identifies via an input[type=file]) is really simple on modern browsers:
var file = input.files[0];
var fr = new FileReader();
fr.onload = function() {
// Use `fr.result` here, it's a string containing the text
};
fr.readAsText(file);

How to export/upload an html/javascript blob file to the client PC displaying the html file?

I wrote a c++/c# Windows program that creates an html report using an xsl transform. The html report includes canvas element drawings. I give the user the option of converting the html report to a Word doc (if it's installed), but, although the conversion works fine, it ignores the canvas drawings. As a workaround, I would like to convert the canvas elements to png images and "export" them to the client PC (that is using my program to create the report). I know how to convert the canvas to a dataURL and then to a blob, but I can't figure out how to upload the blob file to the client PC, which of course is not a webserver.
Also, once the file is on the client, can the blob be treated as a png image?
[Edit] : I missed that the export is made to an .doc file
In this case, it depends on how you are converting your html to .doc.
In the case of an .docx, it should be possible to include your canvas' images as attachments in the .docx internal file tree, under word > media.
In the case of an .doc, the image file seems to be merged into the .doc file itself, might be possible to use an FileReader to append it.
If you are using a library, it depends on the library you use. The first one I found on google (html-docx-js), claims that they need your images as dataURI to be able to save it.
And to convert all your canvases to dataURI, you can use something along the lines of :
document.querySelectorAll('canvas').forEach( canvas =>{
var img = new Image();
try{
img.src = canvas.toDataURL();
canvas.replaceWith(img);
}
catch(e){
handleTaintedCanvas(); // I let you decide what should happen here
}
});
So once it's done, you would just have to call this lib, and it should work.
[Previous] This answers how to export to an stand-alone .html file.
For better compatibility across devices, convert your canvases to dataURI png images.
The Blob way
If you want to go the Blob way, you'd have to save a folder, containing your html file, and all the images as separated files, with correct references to them in the HTML markup.
That's possible too, e.g you could generate an zip file with the correct structure, and all included files, but some browsers don't accept loading external files from the file:// protocol, and your user would have to keep the directory structure untouched.
So all in all,
a lot of work for you,
little advantages (37% of image files size...)
complications for your users (all don't even know what to do with an zip file...)
<canvas> to dataURL
To convert your canvases to dataURI, a simple function would be
[Moved to edit]
And from now on, all your clean canvases will be converted to dataURI images, that you'll be able to export with your html file, which will be standalone.
<script> to dataURL
Note that there is also an third way to handle it (could be the best one actually depending on the nature of your original page):
You can convert all your <script> tags to dataURI, and keep your canvases in the document. This way, you'll still have an standalone working html file. But this implies that you don't need external resources.

Read a file purely in javascript on Firefox OS(B2G)

I have to read a file from the file system of my phone. Essentially its to check if the file contains a word. The file is located in the /sys folder of my phone. I know I can get the contents of the File using FileReader.readAsText(file) to get the contents as a string and then parse it for the word. But how do I make the "file" object to pass to the FileReader object. Thanks in advance!
Edit: Just wanted to add here:
Can I use the File constructor here?
var file = File("/path/to/file");
You can only read data from your app folder (via XMLHttpRequest) and from the SD Card. You cannot read data from any other place in a Firefox OS app.

FileWriter API: use blob to write data

i have a blob url like blob:blahblah that points to a file. I want to write the file behind this blob to local filesystem. The writer.write() documentation says it accepts a file object (from input-type-file) and a blob. But it throws a type mismatch error when try this
fileEntry.createWriter(function(writer) {
writer.write(blob); //blob is a var with the value set to the blob url
i know the problem is that the blob does not get accepted but i would like to know how can i store a blob to the filesystem. i created the said blob earlier in the script from input-type-file and stored it's value in a var.
EDIT
Ok so i think i should have given more code in the first place.
first i create a blob url and store it in a var like this
files[i]['blob'] = window.webkitURL.createObjectURL(files[i]);
files is from an input-type-file html tag and i is looped for number of files. you know the gig.
then the variable goes through a number of mediums, first through chrome's message passing api to another page and then from that page to a worker via postMessage and then finally back to the parent page via postMessage again.
on the final page i intend to use it to store the blob's file to local file system via file system api like this..
//loop code
fileSystem.root.getFile(files[i]['name'], {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.write(files[i]['blob']);
});
});
//loop code
but the writer.write throws Uncaught Error: TYPE_MISMATCH_ERR: DOM File Exception 11
i believe this error is because the variable supplied to writer.write is a text and not a blob object from something like createObjectUrl (directly and not after passing through multiple pages/scopes) or not a window.WebKitBlobBuilder. So how can a blob's url be used to store a file?
From your edited code snippet and description, it sounds like you're writing the blobURL to the filesystem rather than the File itself (e.g. files[i]['name'] is a URL). Instead, pass around the File object between main page -> other page -> worker -> main page. As of recent (in Chrome at least), your round trip is now possible. File objects can be passed to window.postMessage(), whereas before, the browser serialized the argument into a string.
You 'fashion' a handler/reference to a Blob with createObjectURL(). There's not really a way to go from blobURL back to a Blob. So in short, no need to create createObjectURL(). Just pass around files[i] directly.

Categories

Resources