I'm writing a plugin to handle file uploads. I thought implementing a paste feature would be awesome (how often have you event just wanted to paste instead of having to open a photo editor and then save it as file and then upload, but I digress). What I'm doing so far works, except for when the file being pasted becomes too big. I cannot tell you what size 'too big' is, because I'm doing a screenshot selection and saving it to the clipboard.
My current code looks like
document.getElementById('AJS').onpaste = function (e) {
var items = (e.clipboardData || e.originalEvent.clipboardData).items,
blob = items[0].getAsFile();
if (blob && blob.type.match(T.s.accept) && T.currentlength < T.s.maxFiles) {
T.process(param1, param2, param3, param4, items[0].getAsFile());
}
};
T.process
T.process = function (file, i, changing, target, pasteblob) {
var fr = new FileReader();
fr.onload = function (e) {
var blob = pasteblob || new Blob([e.target.result], {type: file.type});
var dataURL = (win.URL || win.webkitURL).createObjectURL(blob);
var index = changing ? i : T.currentlength;
var filedata = {};
if (file.type.match('image/*')) {
var img = new Image();
img.onload = function () {
// Doing stuff
};
img.src = dataURL;
} else {
// Doing stuff
}
};
fr.readAsArrayBuffer(pasteblob || file);
};
For larger files, the blob from blob = items[0].getAsFile() returns a size of 0. Has anyone else experienced this problem and how have you been able to overcome it?
Note: I'm using the latest Chrome on Ubuntu 14.04
Although I don't have any references to anyone other than my own personal research into the matter, it seems as if there is a bug on the Ubuntu version of chrome that prevents users copying and pasting using the native JS api. If you attempt to paste a screenshot in a GMail message using Ubuntu Chrome, you get an error, but this error doesn't come up in any other version of chrome. It was also the same for my code above as well. I tested it on native windows and OS X environments running chrome that were pointing to my machine, and pasting using this script worked just fine!
Related
The below code works fine on google chrome only. Other browsers return Only mp3 file type allowed. Help fix please
$("#song").change(function () {
var file = this.files[0];
var songfile = file.type;
var match = ["audio/mp3"];
var addResult = "#music_formresult";
$(addResult).empty(); //remove previous error message
if (!((songfile == match))) {
$(addResult).html("**Only mp3 file type allowed.**");
$("#songName").html("Select Song");
return false;
} else {
var filename = $('#song').val().split('\\').pop();
$("#songName").html(filename);
}
});
You are comparing a string to an array, which is weird but probably will work fine on all browsers.
You have extra parenthesis on the if statement but that isn't the cause either, however I would remove them anyways.
My guess is the following is not being consistent across all browsers
var file = this.files[0];
var songfile = file.type;
In order for me to be able to help you, please provide a codepen sample of your code running, or place a breakpoint inside the function and show me the value for the above lines on a browser that is not Chrome.
I'm developing a web application which everyone can edit image on the internet directly.
While developing the site, I have faced a big problem with opening local system files.
Typically, we can do that with two ways as already known like below.
First, to use FileReader.
// render the image in our view
function renderImage(file) {
// generate a new FileReader object
var reader = new FileReader();
// inject an image with the src url
reader.onload = function(event) {
the_url = event.target.result
$('#some_container_div').html("<img src='" + the_url + "' />")
}
// when the file is read it triggers the onload event above.
reader.readAsDataURL(file);
}
// handle input changes
$("#the-file-input").change(function() {
console.log(this.files)
// grab the first image in the FileList object and pass it to the function
renderImage(this.files[0])
});
second, to use createObjectURL and revokeObjectURL.
window.URL = window.URL || window.webkitURL;
var fileSelect = document.getElementById("fileSelect"),
fileElem = document.getElementById("fileElem"),
fileList = document.getElementById("fileList");
fileSelect.addEventListener("click", function (e) {
if (fileElem) {
fileElem.click();
}
e.preventDefault(); // prevent navigation to "#"
}, false);
function handleFiles(files) {
if (!files.length) {
fileList.innerHTML = "<p>No files selected!</p>";
} else {
fileList.innerHTML = "";
var list = document.createElement("ul");
fileList.appendChild(list);
for (var i = 0; i < files.length; i++) {
var li = document.createElement("li");
list.appendChild(li);
var img = document.createElement("img");
img.src = window.URL.createObjectURL(files[i]);
img.height = 60;
img.onload = function() {
window.URL.revokeObjectURL(this.src);
}
li.appendChild(img);
var info = document.createElement("span");
info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
li.appendChild(info);
}
}
}
In my case, both of them do not work well in Chrome browser. (IE is fine)
I could open the local files by using both of them. But also, those always made memory leaking even though I exactly called revokeObjectURL when I used second way.
I have already checked that the blobs are released well from chrome://blob-internals/. All of blob had released well. But, Chrome had still hold physical memory and the memory was not released forever unless I refresh the page. Eventually, Chrome was crashed when the memory usage was up to 1.5GB.
FileReader showed me the same resulting although I released refs. Besides, the way showed terrible I/O performance.
http://ecobyte.com/tmp/chromecrash-1a.html (by logidelic)
Here is a test page. You can test this problem with just drop files onto the green DOM. The testing page is using createObjectURL/revokeObjectURL method.
When you do this testing, you could see the physical memory consumption from task manager (Shift + ESC) or your own OS task manager.
Did I miss something or is it a bug as already known?
Please, somebody help me! If you know another way to resolve this, please tell me.
I have the same problem with the createObjectURL method. In the end, I find that the memory can be released by adding the code in the onload function:
this.src = '';
However, the image will disappear from the web page, as you may expect.
In addition, I also notice that sometimes the chrome (50.0.2661.102) or chrome canary (52.0.2740.0) fails to release the memory even with this.src= ''. Once it happens, you need to restart chrome. Simply refresh the page doesn't work.
I have tried the readAsDataURL method, too. The memory can be released well (even as the chrome fails to release memory for createObjectURL with this.src=''.) However, the drawback is that the speed is rather slow (around 10x longer as compared to createObjectURL).
I am trying to make a webapp (developed with impact js game engine), able to run locally without the need of a localhost (using file:///C:/...) and I am required to make it work on chrome.
The main issue that it does not work on chrome is that chrome blocks my media (mainly images in png/jpg) from being loaded from media folder due to CORS issues.
After spending a few days reading up and trying a few methods I am not able to resolve this issue. Anybody with experience in this please tell me if it is possible and if it is, what methods should I go about on this.
Methods I have tried:
1) setting img.crossOrigin = "anonymous" (failed, this is still blocked by chrome)
2) opening chrome with flag --allow-file-access-from-files (worked, but not a feasible method for end user)
3) reading images and converting them to data uri format (failed, data uri conversion seems
to be not working due to inherent CORs issue)
4) attempted to use appcache to cache all images into browser cache (failed, do not seem to work as it is not being accessed from a webserver)
UPDATE: I am now trying to edit the impact.image source code to try to convert the src to data url at the point of loading into the image
load: function( loadCallback ) {
function getBase64Image(img) {
// Create an empty canvas element
var img2 = document.createElement("img");
var canvas2 = document.createElement("canvas");
// Copy the image contents to the canvas
var ctx2 = canvas2.getContext("2d");
img2.onload = function(){
canvas2.width = img2.width;
canvas2.height = img2.height;
};
img2.onerror = function() {console.log("Image failed!");};
img2.src = img + '?' + Date.now();
ctx2.drawImage(img2, 0, 0, img2.width, img2.height);
return canvas2.toDataURL("image/png");
}
if( this.loaded ) {
if( loadCallback ) {
loadCallback( this.path, true );
}
return;
}
else if( !this.loaded && ig.ready ) {
this.loadCallback = loadCallback || null;
this.data = new Image();
this.data.onload = this.onload.bind(this);
this.data.onerror = this.onerror.bind(this);
//this.data.src = ig.prefix + this.path + ig.nocache;
//old src sets to local file, new src sets to data url generated
this.data.src = getBase64Image(this.path);
}
else {
ig.addResource( this );
}
ig.Image.cache[this.path] = this;
},
for some reason the image is not being loaded into the function, will it work even if i get the image load to load into the getBase64Image function?
Short of saving everything as pre-generated, Base-64 data-uris, which you bake into a JS file, or a script tag on your "index.HTML" page, you aren't going to have much luck here -- especially if your intent is to distribute this to an audience disconnected from a webserver (to at least provide a domain for the appcache).
Mind you, in order to generate the data-uris, you, yourself are probably going to require localhost (or a build-tool).
I want to create an image upload widget that resizes (scales) images to a low res (say 640x640). I want to then upload these resized images to the server. Mainly to prevent huge file uploads.
What is the best way to implement it? I'm using JQuery and Django.
Browser support for this will be limited although you can mitigate this by writing Flash and Silverlight shims that do the same thing. I've seen a few html5 examples of how to do this as well.
Plupload is a nice tool for managing this and gives you all the shims and uploaders detailed above.
http://www.plupload.com/example_all_runtimes.php
if you look at the example embed code there is a resize object as part of the config in which you can define the parameters described in your post
Use Canvas and HTML5.
It's pretty simple, just use a FileReader (will not work on iOS/iPhone since they don't have files at a user level) to open on the File/File list you get back from an input type file element:
function fileSelectHandler(e) {
files = e.target.files;
var len = files.length;
for(var filei = 0; filei < len; filei += 1) {
var aFile = files[filei];
var fileReader = new FileReader();
fileReader.onload = (function (theFile) {
return function(e) {
if(e.target.result != null && e.target.result != undefined) {
var imge = new Image();
imge.src = e.target.result;
imageDataURLs[theFile.name] = imge;
imge.onload = (function () {
return function(e) {
draggables[0] = new Draggable(g3,imge);
draggableFlow.launch();
};
})();
}
};
})(aFile);
fileReader.readAsDataURL(aFile);
} // for next file
};
Then write the image to a canvas element and enable the user to drag it around and crop it. When they're happy grab the data from the canvas using CanvasRenderingContext2D.getImageData, and send that base64 string to the server in XHR.
I noticed a blog post from Google that mentions the ability to paste images directly from the clipboard into a Gmail message if you're using the latest version of Chrome. I tried this with my version of Chrome (12.0.742.91 beta-m) and it works great using control keys or the context menu.
From that behavior I need to assume that the latest version of webkit used in Chrome is able to deal with images in the Javascript paste event, but I have been unable to locate any references to such an enhancement. I believe ZeroClipboard binds to keypress events to trigger its flash functionality and as such wouldn't work through the context menu (also, ZeroClipboard is cross-browser and the post says this works only with Chrome).
So, how does this work and where the enhancement was made to Webkit (or Chrome) that enables the functionality?
I spent some time experimenting with this. It seems to sort of follow the new Clipboard API spec. You can define a "paste" event handler and look at event.clipboardData.items, and call getAsFile() on them to get a Blob. Once you have a Blob, you can use FileReader on it to see what's in it. This is how you can get a data url for the stuff you just pasted in Chrome:
document.onpaste = function (event) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
console.log(JSON.stringify(items)); // might give you mime types
for (var index in items) {
var item = items[index];
if (item.kind === 'file') {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function (event) {
console.log(event.target.result); // data url!
};
reader.readAsDataURL(blob);
}
}
};
Once you have a data url you can display the image on the page. If you want to upload it instead, you could use readAsBinaryString, or you could put it into an XHR using FormData.
Edit: Note that the item is of type DataTransferItem. JSON.stringify might not work on the items list, but you should be able to get mime type when you loop over items.
The answer by Nick seems to need small changes to still work :)
// window.addEventListener('paste', ... or
document.onpaste = function (event) {
// use event.originalEvent.clipboard for newer chrome versions
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
console.log(JSON.stringify(items)); // will give you the mime types
// find pasted image among pasted items
var blob = null;
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === 0) {
blob = items[i].getAsFile();
}
}
// load image if there is a pasted image
if (blob !== null) {
var reader = new FileReader();
reader.onload = function(event) {
console.log(event.target.result); // data url!
};
reader.readAsDataURL(blob);
}
}
Example running code: http://jsfiddle.net/bt7BU/225/
So the changes to nicks answer were:
var items = event.clipboardData.items;
to
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
Also I had to take the second element from the pasted items (first one seems to be text/html if you copy an image from another web page into the buffer). So I changed
var blob = items[0].getAsFile();
to a loop finding the item containing the image (see above)
I didn't know how to answer directly to Nick's answer, hope it is fine here :$ :)
As far as I know -
With HTML 5 features(File Api and the related) - accessing clipboard image data is now possible with plain javascript.
This however fails to work on IE (anything less than IE 10). Don't know much about IE10 support also.
For IE the optiens that I believe are the 'fallback' options are
either using Adobe's AIR api
or
using a signed applet