I'm making an application in HTML5 where you choose a video file, and then the application plays it with the HTML5 video tag and the window.URL.createObjectURL(). The problem is that I want to save the data about this video in localStorage and play it again when the user uses my application, but as Mozilla MDN states about the results of this method:
Browsers will release these automatically when the document is unloaded
So is it possible to do what I'm trying to do? Or do the same thing without the window.URL.createObjectURL() but with something else?
I haven't used createObjectURL(), but if I understand correctly, it's essentially a temporary reference to a file or an in-memory object. If you want to save the actual video, it won't be useful, because the video itself will no longer be referenced by this pointer the next time the user visits the application.
I think you might be able to do this with a data: URL instead, as that URL actually includes the full data from the file. This example demonstrates using a FileReader to generate a data URL. I think you should be able to do this:
var reader = new FileReader();
reader.onload = function(e) {
var myDataUrl = e.target.result;
// do something with the URL in the DOM,
// then save it to local storage
};
reader.readAsDataURL(file);
Update: If you want to go up to 1GB, as you note in your comment, you'd probably be better served by the FileSystem API. This would require you to get the local file, save a copy of the file to persistent filesystem storage, and then use createObjectURL() to get a URL for the file copy. You still have a problem with disk space - you just added 1GB of duplicative file content to the user's filesystem - but I don't think it's possible to keep a persistent reference to a file outside of the browser sandbox otherwise.
Related
I have two client-only (backend is static file server) applications written in JS. One is a recorder that records videos (e.g. the webcam) via the MediaRecorder API (this results in a Blob object). The other application is a video editor (don't mind how that one is implemented).
The two applications are deployed on different domains (e.g. foo-recorder.com and foo-editor.com). My goal is to make editing your recordings as easy as possible. I would like the recorder to have a button "edit recording in editor" that opens the editor with the recording already loaded.
A naive solution would be to URL.createObjectUrl(blob) in the recorder, URL-encode that URL and pass it as query parameter to the editor. E.g. https://foo-editor.com?video=blob://.... However, as far as I can tell, browsers do not allow sites to access blob URLs from another domain. (That's probably for good privacy reasons.)
I also thought about:
Storing the blob as a file on the user's device and pass the path to the other site. But we can't just willy nilly write files with JS.
Storing the blob in local storage: local storage usually is limited to a few MB and can't be access cross-domain either.
Passing the whole video base64 encoded as query parameter: that's ridiculous. No.
So I can't come up with a working solution. And I wouldn't be surprised if it doesn't work at all because it's probably very tricky privacy and security wise.
Does anyone have an idea how I could pass this blob from one app to the other? Obviously, the blob should not be uploaded.
Thanks to Musa's hint, I found a solution: postMessage allows me to pass the Blob to the editor, even if it's deployed on another domain. The recorder has to open a new browsing contect with the editor loaded. This can be:
windows.open to open a popup window
An <iframe> with the editor as src. Acquire the context via iframeDomNode.contentWindow.
It's now possible to use postMessage to send a message to that context:
const iframe = document.getElementById('editor-iframe');
iframe.contentWindow.postMessage(videoBlob, "*");
// ^ TODO: change "*" to the specific target origin in production code!!!
On the editor side, I can receive that message via:
window.addEventListener("message", event => {
// TODO: in real code, you should check `event.origin` here!
const v = document.getElementById("a-video-element");
v.src = URL.createObjectURL(event.data);
}, false);
Note: if you generate the blob URL on the recorder side, pass that to the editor, the editor still cannot access that. So you need to pass the blob directly.
Also note that sending a Blob via postMessage is not expensive and does not copy the Blob data.
I am trying to build a local video player in nwjs (node-webkit). I was able to play the local files by adding their path as the video element's src attribute, but now I want to make use of MediaSource and ,probably necessary, URL.createObjectUrl().
The problem is I haven't found any documentation that allowed me to achieve this, during my tests I am unable to append a new source to MediaSource as the local file. I tried direct paths and XHR requests, the closest I have been was with the XHR request of the file but I cannot convert the xhr.response into a usable item for my purpose, such as a objecturl.
For some reason just changing the src attribute directly each time a new video is selected causes the memory usage to grow constantly, which is why I would like to try doing this via the MediaSource api.
Since there's a lack of such information I would appreciate if anyone could help.
I was able to discover how this could be done, first there needs to be a mediasource object with which you use URL.createObjectUrl to link to the video.src, and then you create a buffer on it. It is to that buffer that is appended the media which is loaded via XMLHttpRequest with the Content-type set as an arraybuffer.
Careful with big files, if you don't segment them and load everything at once it will eat your ram and even crash your application.
We are developing an app that is to download files from HTTP URLs, the extensions/file types of which we will not know until runtime. We've been following this tutorial as a starting point, but since we aren't dealing with images, it hasn't helped us.
The issue is that the code in the tutorial will get you a Blob object and I can't find any code that will allow us to either:
Convert the Blob to a byte array.
Save the Blob straight to the file system.
The ultimate goal is to seamlessly save the file at the given URL to the file system and launch it with the default application, or to just launch it from the URL directly (without the save prompt you get if you just call Windows.System.Launcher.launchUriAsync(uri);).
Any insight anyone might have is greatly appreciated.
Regarding downloading content into byte array:
Using WinJS.xhr with the responseType option as 'arraybuffer' will return the contents in ArrayBuffer. A javascript typed array can be instantiated from the ArrayBuffer for example UInt8Array. This way contents can be read into byte array. code should look something like this:
// todo add other options reqd
var options = { url: url, responseType: 'arraybuffer' };
WinJS.xhr(options).then(function onxhr(ab)
{
var bytes = new Uint8Array(ab, 0, ab.byteLength);
}, function onerror()
{
// handle error
});
Once you take care of permissions to save the file to file system either by user explicitly picking the save file location using SaveFilePicker or pick folder using folder picker - file can be saved on local file system. Also, file can be saved to app data folder.
AFAIK, html/js/css files from local file system or the app data cannot be loaded for security reasons. Although DOM can be manipulated under constraints, to add content. I am not sure of your application requirements. You might need to consider alternatives instead of launching downloaded html files.
I want to load an image file from the computer directly to any js object without using any server-side component. For example, I want to select a picture from the local machine and display it on a webpage. Is there a way to avoid file upload to the server?
In fact I want to write a kind of multiple image loader, but before loading to the server I want to rotate some images, create an xml-file with some data like user id, image file names list and to zip all images and this xml and then send it to the server. How can I do that on the client side?
There is a way with HTML5, but it requires the user to have dropped the file into a drop target or used a <input type="file"/> box, since otherwise it would be a security issue.
Using the File API you can read files, and specifically you can use the FileReader.readAsDataURL method to set the content as a data: URL for the image tag.
Here's an example:
$('#f').on('change', function(ev) {
var f = ev.target.files[0];
var fr = new FileReader();
fr.onload = function(ev2) {
console.dir(ev2);
$('#i').attr('src', ev2.target.result);
};
fr.readAsDataURL(f);
});
http://jsfiddle.net/alnitak/Qszjg/
Using the new File APIs, it is possible to access content from the local disk.
You put a traditional <input type="file"> upload field on your page, and handle the onchange event.
MDN has a good writeup with all of the details.
Your event handler gets a FileList containing Files. From there, you can call FileReader.readAsDataURL(File) to fetch the content of the image and then pass that data URL to an <img> or a <canvas> to do rotation.
You can use createObjectURL method of the window.URL object, this doesn't have much browser support though
http://jsfiddle.net/LvAqp/ only works in chrome and firefox
When a user is uploading an image, is there a way I can load the image client side and show it to them first, before uploading it to the server? Preferably using javascript/jquery only, but using flash would be acceptable too.
It is possible with the new FileReader interface defined in HTML5 and works on Firefox currently.
A file input has an associated files property which tracks the list of files currently selected for that input. To display a file from this list, create a new FileReader object, initialize its onload event handler, and read the file as a data URL.
// get the first file, foo is a file input field
var file = document.getElementById('foo').files[0];
// setup the reader and the load complete callback
var reader = new FileReader();
reader.onload = function(e) {
var image = new Image();
// string representing the image
image.src = e.target.result;
document.body.appendChild(image);
};
// read the file as a data url
reader.readAsDataURL(file);
Once the file is loaded, you will have access to its contents in a data url scheme, for instance:
data:image/jpeg;base64,...aqHI7sNyPGFjdtQvFr/2Q==
Create a new Image and set its src attribute to this data string.
See a working example here. Firefox only.
You can't really do this cross-browser in JavaScript alone due security restrictions that are in place, there are a few flash versions available though, here's one example (the free version does what you're after).
There are probably more free flash versions out there as well.
Since HTML 5 those things are possible, thanks to the File Object, File Reader and the ´files´ property of the input element.
See here for more information: http://demos.hacks.mozilla.org/openweb/ & http://hacks.mozilla.org/2009/12/file-drag-and-drop-in-firefox-3-6/.
Example (only for demonstration, requires FF 3.5+):
See here: http://gist.github.com/536024
In case you wonder, File.url is brand new, with it you dont anymore need to read the whole file into the memory, and assign the whole DataUrl (data:image/src,base64;DF15EDFE86..) to the src property.
Well, the <img> tag needs a path to the image. That path can be to something on the web, or to a local file. So far, so good. The trick is, how do you tell your javascript the path on the local system, so it can set the IMG SRC attribute.
The path of the file <input> tag is unavailable to javascript (as a security precaution --- you don't want a want page upload files from you system behind your back).
On the other hand, if you can get your users to enter a correct file path name into a text <input> field, then it should be possible.