I help moderate a forum online, and on this forum we restrict the size of signatures. At the moment we test this via a simple Greasemonkey script I wrote; we wrap all signatures with a <div>, the script looks for them, and then measures the div's height and width.
All the script does right now is make sure the signature resides in a particular height/width. I would like to start measuring the file size of the images inside of a signature automatically so that the script can automatically flag users who are including huge images in their signature. However, I can't seem to find a way to measure the size of images loaded on the page. I've searched and found a property special to IE (element.fileSize) but I obviously can't use that in my Greasemonkey script.
Is there a way to find out the file size of an image in Firefox via JavaScript?
Edit: People are misinterpreting the problem. The forums themselves do not host images; we host the BBCode that people enter as their signature. So, for example, people enter this:
This is my signature, check out my [url=http://google.com]awesome website[/url]!
This image is cool! [img]http://image.gif[/img]
I want to be able to check on these images via Greasemonkey. I could write a batch script to scan all of these instead, but I'm just wondering if there's a way to augment my current script.
As you know IE supports the fileSize property of an image. No such luck in other browsers ... however, you should be able to modify this script:
http://natbat.net/2008/Aug/27/addSizes/
It uses JSON to read HTTP headers of files and display their actual file size. That should help you prevent people uploading large animated GIFs.
As for getting the dimensions:
var img = new Image();
theImage.src = "someimage.jpg";
actualwidth = theImage.width;
actualheight = theImage.height;
This of course is a pure client-side approach to something best handled server-side.
Actually, with HTML5, this is now possible,
read more information here.
Short answer, you cannot
Also, Check on jGuru How can you check the file size from JavaScript in a form with an input type of file?
You will find some important points
Well the answer is very simple, you cannot.
Reason: The browser security does not allow the scripts
(Javascript/VBScript) or even applets and ActiveX Controls to read
files from the local hard disk. You can only read files if your code
is signed by some Certificate Authority (CA). Now the input type
"FILE" also does not have the permission to read files. We cannot do
anything about that since thats what HTML says. So since it cannot
read files, it cannot find the size of the file with which the input
tag is associated. Since it cannot find the file size, there is no
function exposed by JavaScript/VBScript to return the file size. But
if you need to find the file size, say in order to restrict the size
of the file uploaded to your web-server. Then you can do so by
counting the file contents on the server-side, once the user submits
it to the server. Thats what many of the free e-mail providers like
www.hotmail.com do.
Server side validation is always a better bet, but in your case, I can see why you would want to do this client side.
Also, it seems that others may have misread the question, and that the images that Daniel want to test are already uploaded, in which case there is a fairly simple method of doing so (provided the images are on the same domain as the script).
var getFileSize = function(address, responseHandler) {
var req = new XMLHttpRequest();
req.open('head', address, true);
req.onreadystatechange = responseHandler;
req.send(null);
}
var responseHandler = function(resp) {
if ( this.readyState == 1 ) {
this.abort();
}
console.log(this.getResponseHeader("Content-length"));
};
getFileSize("http://stackoverflow.com/content/img/so/logo.png", responseHandler);
Boom. This example works in FF3 and probably 2. Since you're using Greasemonkey to do this, browser compatibility doesn't seem like an issue.
I'm not certain if Greasemonkey shares the same XML RPC domain restrictions, but if the images files that you need are on a different domain than the script, then you might need to look into using some iframe magic.
Client side validation is insufficient to accomplish your goal. A simple post request will allow the user to upload any image they want no matter what html or javascript you serve them.
You could set a maximum file size in your HTML where they upload files.
<input type="hidden" name="MAX_FILE_SIZE" value="10000000">
(max_file_size in bytes).
However, this is an "undocumented/unsupported" item of some browsers. You are best to actually check the filesize on the server once it's been uploaded.
You could also use a Flash or Java applet to handle the upload and check the filesize there. See http://www.masrizal.com/product/custom%20tag/cf_flashmultiupload/docs%20&%20examples/example.cfm and http://www.saschawenning.de/labor/flash8/fileUpload/ for examples.
The DOM attribute img.fileSize will return the actual file size of the referenced <img>. Access to the img object can be obtained using JQuery or the DOM 'images' collection. However, this is an IE only extension.
Another approach is to omit the height and width attributes in the <img> tag, so that the full image is downloaded, then use img.height and img.width to determine the size of the downloaded image. This code could be put into the user's profile editor page as an intermediate step between having someone enter their signature as HTML, then showing them a preview of their signature. Clunky, I have to admit, but possible.
If you are worried about huge images, set a max upload size as Richy C. mentioned, but also resize the uploaded image on the server and use the resized version.
Facebook does this for most of the uploaded images so that reasonably size images are served. Even converting them to png format in some (most?) cases, which drive the creative group nuts because of "lost quality".
What you should be able to do is an AJAX HEAD request of the image url, which just gets the header of the file rather than the contents, so is much faster. One of the headers you will get back is Content-Length, and that will tell you the size of the image in bytes.
More details here.
You can do that file HTML5 JS File API
You can test run the below codes in my web IDE (but please use google chrome or FF):
http://codesocialist.com/#/?s=bN
The below codes retrieve the filetype and filesize for you :)
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ', f.size, ' bytes </strong></li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
// Bind Event Listener
document.getElementById('files').addEventListener('change', handleFileSelect, false);
} else {
alert('The File APIs are not fully supported in this browser.');
}
Related
In my web app, I'm having bunch of URLs types by users. My view is showing either link icon or image preview, depending on whether URL points to an image or not.
What is the most reliable way to display image previews only if it's really an image? Should I create <img> and check dimensions on load, use new Image() object, or maybe something else?
Any advice highly appreciated! :)
The most reliable and compatible way to check if the source point is a valid image is to use the Image object. If it can load it as an image onload will trigger, if not onerror will trigger:
var img = new Image;
img.onload = function() { /* OK */ };
img.onerror = function() { /* cannot read this as an image */ };
img.onabort = function() { /* connection or source was reset */ };
img.src = "URLtoCheckHere";
The drawback is of course that the whole image would be loaded before you could find out if the browser can read and decode it.
If Image for some reason can't be used you could read the source point via XHR but that comes with its own restrictions, one being cross-origin resource sharing. If the image is not of the same origin (protocol, domain, port etc.) and the external server does not allow cors-usage, reading would simply fail.
However, if these limitations aren't a problem (i.e. the images comes from the same server as the page or a cors-friendly site) then you could read in part of the image as ArrayBuffer and check the magic numbers for the image types you want to support. Be aware of byte-order.
To specify a range use the Range header (it's not sure the server will respect it though).
Assuming the part of the file has been read into an ArrayBuffer:
var reader = new DataView(arrBuffer);
if (reader.getUint32(0) === 0x89504E47 &&
reader.getUint32(4) === 0x0D0A1A0A) {
// this seem to be a PNG file
}
else ... etc.
But, even if the file is detected as a valid image file, there is no guarantee of that the file is not corrupt and so forth. There is no way to validate the file using this method (unless you chose to write a parser yourselves).
So in conclusion, Image is the best option in most scenarios. It has been through several iterations over the years in the main browsers and is pretty robust and stable.
I'm working on an HTML/javascript app intended to be run locally.
When dealing with img tags, it is possible to set the src attribute to a file name with a relative path and thereby quickly and easily load an image from the app's directory. I would like to use a similar method to retrieve a text file from the app's directory.
I have used TideSDK, but it is less lightweight. And I am aware of HTTP requests, but if I remember correctly only Firefox has taken kindly to my use of this for local file access (although accessing local images with src does not appear to be an issue). I am also aware of the FileReader object; however, my interface requires that I load a file based on the file name and not based on a file-browser selection as with <input type="file">.
Is there some way of accomplishing this type of file access, or am I stuck with the methods mentioned above?
The browser will not permit you to access files like that but you can make javascript files instead of text files like this:
text1.js:
document.write('This is the text I want to show in here.'); //this is the content of the javascript file
Now call it anywhere you like:
<script type="text/javascript" src="text1.js"></script>
There are too many security issues (restrictions) within browsers making many local web-apps impossible to implement so my solution to a similar problem was to move out of browsers and into node-webkit which combines Chromium + Node.js + your scripts, into an executable with full disk I/O.
http://nwjs.io/
[edit] I'm sorry I thought you wanted to do this with TideSDK, I'll let my answer in case you want to give another try to TideSDK [/edit]
I'm not sure if it's what you're looking for but I will try to explain my case.
I've an application which allow the user to save the state of his progress. To do this, I allow him to select a folder, enter a filename and write this file. When the user open the app, he can open the saved file, and get back his progress. So I assume this enhancement is similar of what you are looking for.
In my case, I use the native File Select to allow the user to select a specific save (I'm using CoffeeScript) :
Ti.UI.currentWindow.openFileChooserDialog(_fileSelected, {
title: 'Select a file'
path: Ti.Filesystem.getDocumentsDirectory().nativePath()
multiple: false
})
(related doc http://tidesdk.multipart.net/docs/user-dev/generated/#!/api/Ti.UI.UserWindow-method-openFileChooserDialog)
When this step is done I will open the selected file :
if !filePath?
fileToLoad = Ti.Filesystem.getFile(scope.fileSelected.nativePath())
else
fileToLoad = Ti.Filesystem.getFile(filePath)
data = Ti.JSON.parse(fileToLoad.read())
(related doc http://tidesdk.multipart.net/docs/user-dev/generated/#!/api/Ti.Filesystem)
Please note that those snippets are copy/paste from my project and they will not work without the rest of my code but I think it's enough to illustrate you how I manage to open a file, and read his content.
In this case I'm using Ti.JSON.parse because there is only javascript object in these files but in your case you can just get the content. The openFileChooserDialog isn't mandatory, if you already know the file name, or if you get it from another way you can use Ti.Filesystem in your own way.
have a browser program that lets the user play chess - move pieces etc. trying to let the user download the resultant pgn (Content-Type: PGN) directly from browser.
does it have something to do with data:URI? is there some example somewhere?
only interested in modern browsers
I am not quite sure if I understand your question correctly. Do you mean you generate an image in PNG format but the browser does not offer download, instead shows the image directly?
If so, the solution is to indicate a file for download by setting the appriopriate MIME type as HTTP header "content type".
In PHP you do it like this:
header("Content-Type: application/force-download");
or
header("Content-Type: application/octet-stream");
When the browser receives this MIME type it will not try to display the content itself.
You can use a Data URI but there are some limitations. Here's an example, based on my answer to an earlier question. The first thing you'll note is that you can't really control the filename, but it works OK in Firefox and Chrome other than that, but probably not so well in IE (I've not tried it).
Assuming you can already generate the PGN as a string, the code to create a Data URI is quite straightforward:
function exportData(data, target) {
var exportLink = document.createElement('a');
exportLink.setAttribute('href', 'data:application/x-chess-pgn;base64,' + window.btoa(data));
exportLink.appendChild(document.createTextNode('sample.pgn'));
document.getElementById(target).appendChild(exportLink);
}
Just set data with whatever you're generating and set up an element to hold the link once it's created.
In the future we'll have better solutions for this sort of issue, but there's no browser support for it yet.
is there a way to load the full binary of an image in javascript?
what i want to do is to allow the user to preview an image before uploading it.
ie the user selects an image on his local drive (C:\image.jpg) , view it, and decides to upload or cancel.
i tried to set the source to the image path, but it didn't work since it is outside the webapplication project folder.
any help?
thx for your posts, but i ended up creating a temp folder on the server that stores the uploaded image using ajax. and when the user saves the data, the image is moved to another location, and the temp folder is deleted.
You can do something like this:
<img id="preview" src="" style="display:none;" />
<form>
....
<input type="file" id="file" />
....
</form>
<script type="text/javascript">
var file = document.getElementById("file");
var img = document.getElementById("preview");
file.onchange = function(){
img.src = file.value;
img.style.display = 'block';
};
</script>
There is no easy way, what You could do:
Preload image with some ajax file uploader to temp area and then let user decide
Use some third party written solution (f.ex. some flash component)
Here there is also similar question:
is it possible to preview local images before uploading them via a form?
You need server cooperation to access the image binary data. You won't be able to use the "Upload Form" to access the file info without uploading it to a server.
You could however do something like tell the user to paste the source binary data of the image in a textarea or something, then you can use JavaScript to load that binary data and display the actual image.
This is available in some browsers via the HTML5 file access API. Here is the Firefox documentation for file access.
As answered several times, you can't do this with plain HTML/JavaScript due to security restrictions. You need to send the image anyway. You can however handle this using a Java Applet since it runs entirely at the client machine and offers more control than HTML/JS. There are several free and ready-to-use ones. JumpLoader looks good and some major sites also uses it. With Flash it should also be possible, but I am not sure which ones offers this functionality. Check/tryout some Flash Multi File Uploaders.
I'm currently creating an extension for google chrome which can save all images or links to images on the harddrive.
The problem is I don't know how to save file on disk with JS or with Google Chrome Extension API.
Have you got an idea ?
You can use HTML5 FileSystem features to write to disk using the Download API. That is the only way to download files to disk and it is limited.
You could take a look at NPAPI plugin. Another way to do what you need is simply send a request to an external website via XHR POST and then another GET request to retrieve the file back which will appear as a save file dialog.
For example, for my browser extension My Hangouts I created a utility to download a photo from HTML5 Canvas directly to disk. You can take a look at the code here capture_gallery_downloader.js the code that does that is:
var url = window.webkitURL || window.URL || window.mozURL || window.msURL;
var a = document.createElement('a');
a.download = 'MyHangouts-MomentCapture.jpg';
a.href = url.createObjectURL(dataURIToBlob(data.active, 'jpg'));
a.textContent = 'Click here to download!';
a.dataset.downloadurl = ['jpg', a.download, a.href].join(':');
If you would like the implementation of converting a URI to a Blob in HTML5 here is how I did it:
/**
* Converts the Data Image URI to a Blob.
*
* #param {string} dataURI base64 data image URI.
* #param {string} mimetype the image mimetype.
*/
var dataURIToBlob = function(dataURI, mimetype) {
var BASE64_MARKER = ';base64,';
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
var bb = new this.BlobBuilder();
bb.append(uInt8Array.buffer);
return bb.getBlob(mimetype);
};
Then after the user clicks on the download button, it will use the "download" HTML5 File API to download the blob URI into a file.
I had long been wishing to make a chrome extension for myself to batch download images. Yet every time I got frustrated because the only seemingly applicable option is NPAPI, which both chrome and firefox seem to have not desire in supporting any longer.
I suggest those who still wanted to implement 'save-file-on-disk' functionality to have a look at this Stackoverflow post, the comment below this post help me a lot.
Now since chrome 31+, the chrome.downloads API became stable. We can use it to programmatically download file. If the user didn't set the ask me before every download advance option in chrome setting, we can save file without prompting user to confirm!
Here is what I use (at extension's background page):
// remember to add "permissions": ["downloads"] to manifest.json
// this snippet is inside a onMessage() listener function
var imgurl = "https://www.google.com.hk/images/srpr/logo11w.png";
chrome.downloads.download({url:imgurl},function(downloadId){
console.log("download begin, the downId is:" + downloadId);
});
Though it's a pity that chrome still doesn't provide an Event when the download completes.chrome.downloads.download's callback function is called when the download begin successfully (not on completed)
The Official documentation about chrome.downloadsis here.
It's not my original idea about the solution, but I posted here hoping that it may be of some use to someone.
There's no way that I know of to silently save files to the user's drive, which is what it seems like you're hoping to do. I think you can ASK for files to be saved one at a time (prompting the user each time) using something like:
function saveAsMe (filename)
{
document.execCommand('SaveAs',null,filename)
}
If you wanted to only prompt the user once, you could grab all the images silently, zip them up in a bundle, then have the user download that. This might mean doing XmlHttpRequest on all the files, zipping them in Javascript, UPLOADING them to a staging area, and then asking the user if they would like to download the zip file. Sounds absurd, I know.
There are local storage options in the browser, but they are only for the developer's use, within the sandbox, as far as I know. (e.g. Gmail offline caching.) See recent announcements from Google like this one.
Google Webstore
Github
I made an extension that does something like this, if anyone here is still interested.
It uses an XMLHTTPRequest to grab the object, which in this case is presumed to be an image, then makes an ObjectURL to it, a link to that ObjectUrl, and clicks on the imaginary link.
Consider using the HTML5 FileSystem features that make writing to files possible using Javascript.
Looks like reading and writing files from browsers has become possible. Some newer Chromium based browsers can use the "Native File System API". This 2020 blog post shows code examples of reading from and writing to the local file system with JavaScript.
https://blog.merzlabs.com/posts/native-file-system/
This link shows which browsers support the Native File System API.
https://caniuse.com/native-filesystem-api
Since Javascript hitch-hikes to your computer with webpages from just about anywhere, it would be dangerous to give it the ability to write to your disk.
It's not allowed. Are you thinking that the Chrome extension will require user interaction? Otherwise it might fall into the same category.