8

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: Firefox Demo

Chrome: Chrome Demo

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/

jantimon
  • 36,840
  • 23
  • 122
  • 185
  • Random issues aside, if you manage to get this working, you're still going to have an issue as soon as you start working with the image-data, because the [image came from a different domain](http://stackoverflow.com/questions/9972049/cross-origin-data-in-html5-canvas). The error is expected per the spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#security-with-canvas-elements – Steve Campbell Aug 20 '12 at 18:14

8 Answers8

6

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:

  1. 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.
  2. 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)
  3. 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.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • This approach is a clever one however it doesn't solve my problem. The image itself is provided by a third party service and included by their javascript library and is login(cookie) dependent. (I used random-image.net only for demonstration) – jantimon Aug 16 '12 at 09:43
  • As in the user of your app is logged into theirs? Won't work on that one, no :( – Jon Hanna Aug 16 '12 at 10:06
  • As there won't be a working solution as I had in mind I reward the bounty to the answer with the most votes. Thanks for your effort! – jantimon Aug 22 '12 at 17:21
2

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...

Tommaso
  • 520
  • 1
  • 6
  • 20
1

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).

Mike Brant
  • 70,514
  • 10
  • 99
  • 103
  • I am not able to change the image headers as I don't own the image server. The url is the same. – jantimon Aug 10 '12 at 19:01
  • @Ghommey Well you probably are out of options then. That is what tells the browser how it should cache the item. – Mike Brant Aug 10 '12 at 19:05
  • @Ghommey because cloning that node is not going to force a new request to download an image that has already been loaded. However when you reload the page it will. For me I am seeing all 4 images the same. But in your case my guess is that specifically setting the src attr may cause some browsers to reload. As an aside, I did since see a case where a max-age=1 header was sent, so there could be cases where the cache is still valid for a second. – Mike Brant Aug 10 '12 at 19:16
  • The max-age is actually 1 (second). Whether you get the same image depends a lot on the timeouts in the jsfiddle example. – Steve Campbell Aug 20 '12 at 18:17
1

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.

Andressa
  • 44
  • 4
RoToRa
  • 37,635
  • 12
  • 69
  • 105
  • 3
    Please don't tell me what I can and cannot force! I use forces all the time in web development. If you want, I can teach you. – HandiworkNYC.com Aug 16 '12 at 08:59
  • 4
    @j-man86 You didn't force anything. You just did something that happened to work in all scenarios you tested (possibly even purposely ignoring ones you knew it wouldn't work in). Name one thing you "forced" and I can can name a scenario where it won't work (and yes those scenarios may be unlikely or even concieved, but that won't change the fact that your "forcing" wouldn't work, and thus it's not "forcing"). – RoToRa Aug 16 '12 at 09:09
  • Thanks @RoToRa this works for firefox but not for chrome :( http://jsfiddle.net/VT8c5/ – jantimon Aug 16 '12 at 09:47
  • @Ghommey The main problem is that there is no way to tell the browser not to re-fetch the image when ever it feel like. Maybe you could explain why you need to do this? What is the point of "cloning" the image? Why are you using this image service, if you can't change it? – RoToRa Aug 16 '12 at 10:28
1

There seems to be two workarounds:

  1. 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.
  2. 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).
badunk
  • 4,310
  • 5
  • 27
  • 47
0

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/,'')  
Dameo
  • 334
  • 2
  • 7
  • Thanks but the given url is just an example and I want to have random images so unfortunately this approach does not work for me. – jantimon Aug 10 '12 at 19:13
  • But I am only removing the random image part WHEN cloning. It's part of that process not saying you can't use random images. So once the original image is generated, it's not going to get a random image during the cloning. – Dameo Aug 10 '12 at 19:16
  • The cloned image should be the same image like the previous random image. – jantimon Aug 11 '12 at 11:55
0

try:

var myImg = new Image();
myImg.src = img_src;

and then append "myImg" to where you want:

$(document).append(myImg);
  • Thanks but it doesn't work. Reload the following page several times: http://jsfiddle.net/9ykXq/embedded/result/ – jantimon Aug 10 '12 at 19:20
0

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.

joocer
  • 1,111
  • 1
  • 7
  • 11