Embed external images for use in HTML canvas? - javascript

I'm using JavaScript to load an image into my Canvas element in Firefox. This works fine for local images, but throws a security exception for external images. Is there any way to avoid this security exception, one that does not involve my server having to act as proxy to load the image locally (because that would stress my server)?
PS: The current code is similar to this:
var img = new Image();
var contextSource = canvasSource.getContext('2d');
contextSource.drawImage(img, 0, 0);
// get image data to do stuff with pixels
var imageDataSource = contextSource.getImageData(0, 0, width - 1, height - 1);

Actually it might be as well possible by utilizing XHR level 2 and UrlData. Check out my blog post.

This is doable for images under 25.6k in size. Use YQL's data:uri converter to grab the image and hand you back the base-64 encoded block. Then create an image in the client and set its source to the data you received from YQL. Example here:
http://kentbrewster.com/avatar-portraits
Here's a link to the right YQL data table.
[edited to fix; it's 25.6k, not 256]

I don't think this is possible, because this could open the browser to cross domain attacks.

Related

Reliable way to check image URL with JavaScript

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.

Is it possible to avoid "The operation is insecure" when using Canvas?

I have a HTML canvas (using KineticJS, however canvas aficionados should still chime in) that loads an image from another domain, places it onto the canvas and overlays some other information to product a final image. When I try to use canvas.toDataURL () to output the file, I receive the message "The operation is insecure.", obviously due to cross-domain restrictions.
I was wondering if anyone knows of any methods to work around this error (preferably cross-browser compatible). I was thinking a solution would be to copy the canvas to another canvas, kind of like a screenshot, but I can't find any method of doing so in the way that would avoid the error as I think it copies all canvas properties along with it.
Does anyone have any ideas?
If the images are coming from a domain you don't control, then you're stuck with CORS limitations.
If you have access to configuring your own server, you can enable cross-origin sharing by setting this heading (read more about server security when doing this):
Access-Control-Allow-Origin: <origin> | *
Alternatively, if you host your images on a CORS enabled site like www.dropbox.com you can fetch images without the security errors like this:
var image1=new Image();
image1.onload=function(){
context.drawImage(image1,0,0);
}
image1.crossOrigin="anonymous";
image1.src="https://dl.dropboxusercontent.com/u/99999999/yourCORSenabledPic.jpg";

Force image caching with javascript

I am trying to clone an image which is generated randomly.
Although I am using the exact same url a different image is load. (tested in chrome and firefox)
I can't change the image server so I am looking for a pure javascript/jQuery solution.
How do you force the browser to reuse the first image?
Firefox:
Chrome:
Try it yourself (maybe you have to reload it several times to see it)
Code:
http://jsfiddle.net/TRUbK/
$("<img/>").attr('src', img_src)
$("<div/>").css('background', background)
$("#source").clone()
Demo:
http://jsfiddle.net/TRUbK/embedded/result/
You can't change the image server if it isn't yours, but you can trivially write something on your own server to handle it for you.
First write something in your server-side language of choice (PHP, ASP.NET, whatever) that:
Hits http://a.random-image.net/handler.aspx?username=chaosdragon&randomizername=goat&random=292.3402&fromrandomrandomizer=yes and downloads it. You generate a key in one of two way. Either get a hash of the whole thing (MD5 should be fine, it's not a security-related use so worries that it's too weak these days don't apply). Or get the size of the image - the latter could have a few duplicates, but is faster to produce.
If the image isn't already stored, save it in a location using that key as part of its filename, and the content-type as another part (in case there's a mixture of JPEGs and PNGs)
Respond with an XML or JSON response with the URI for the next stage.
In your client side-code, you hit that URI through XmlHttpRequest to obtain the URI to use with your images. If you want a new random one, hit that first URI again, if you want the same image for two or more places, use the same result.
That URI hits something like http://yourserver/storedRandImage?id=XXX where XXX is the key (hash or size as decided above). The handler for that looks up the stored copies of the images, and sends the file down the response stream, with the correct content-type.
This is all really easy technically, but the possible issue is a legal one, since you're storing copies of the images on another server, you may no longer be within the terms of your agreement with the service sending the random images.
You can try saving the base64 representation of the image.
Load the image in an hidden div/canvas, then convert it in base64. (I'm not sure if a canvas can be hidden, nor if it is possible to convery the img using html4 tag)
Now you can store the "stringified" image in a cookie, and use it unlimited times...
The headers being sent from your random image generator script include a Cache-Control: max-age=0 declaration which is in essence telling the browser not to cache the image.
You need to modify your image generator script/server to send proper caching headers if you want the result to be cached.
You also need to make sure that the URL stays the same (I didn't look at that aspect since there were tons of parameter being passed).
There seems to be two workarounds:
If you go with the Canvas method, see if you can get the image to load onto the Canvas itself so that you can manipulate the image data directly instead of making a 2nd http request for the image. You can feed the image data directly onto a 2nd Canvas.
If you're going to build a proxy, you can have the proxy remove the No-Cache directive so that subsequent requests by your browser use the cache (no guarantees here - depends on browser/user settings).
First off, you can "force" anything on the web. If you need to force things, then web development is the wrong medium for you.
What you could try, is to use a canvas element to copy the image. See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Using_images for examples.
Tell it to stop getting a random image, seems to work the way you want when I add this third replace call:
// Get the canvas element.
var background = ($("#test").css('background-image')),
img_src = background.replace(/^.+\('?"?/, '').replace(/'?"?\).*$/, '').replace(/&fromrandomrandomizer=yes/,'')
try:
var myImg = new Image();
myImg.src = img_src;
and then append "myImg" to where you want:
$(document).append(myImg);
I did this with your fiddler scripts and got the same image every time
#test {
background:url(http://a.random-image.net.nyud.net/handler.aspx?username=chaosdragon&randomizername=goat&random=292.3402&fromrandomrandomizer=yes);
width: 150px;
height: 150px;
}
note the .nyud.net after the domain name.

Javascript reusable images caching?

Is it possible to avoid asking server for 304 header for reusable images via jQuery or clean javascript?
Thanks ;)
The HTTP image caching is done between webserver and webbrowser. You won’t be able to influence it with JavaScript, as the expiration/modification headers are HTTP headers, which will be handled by the browser, and not passed to JavaScript.
You could try saving the images as javascript objects, ie.
var image = new Image();
image.src = "/test.png";
You can inject this object in the DOM as many times as you want and it will only request the image once.

HTML5 save canvas to file on server

i need to create a component using html5 canvas that given an image the user can paint on it and directly (via a kind of save button) upload it's customized version on the server.
Can i use html canvas for it ?
Any suggestion ?
thx in advance
You can get the image as data-url like this:
var dataUrl = document.getElementById('your-canvas').toDataURL();
You could then send this (very long string) to the server and save it to a file after decoding it (it is encoded in base64).
EDIT: Remember to submit this via POST, as suggested in the comments. GET has some length-limits in various browsers, so its likely to exceed those limits with such a huge amout of data.
Note that this is currently dead-on-arrival for Android (up to and including 2.3). Please star this issue - http://code.google.com/p/android/issues/detail?id=7901

Categories