240 comments

[ 4.4 ms ] story [ 343 ms ] thread
You really can't - the HN hug of death has killed it!
The image was dead in the first place, hence it cannot be downloaded or opened.

That’s the joke, i guess.

No, they DoS'd themselves with their "viewable but not save-as-able" technique. Leaving connections open will do that. The image is visible right now but the browser can't save what appears to be an incomplete file.
It's definitely hard to download an image that doesn't load. :(
If I wanted a non-downloadable image I would make it from 1px wide/tall colored divs.
I actually used this to generate graphs in JS/HTML in the 1990s. :-)
Out of curiosity, how was the performance (of course normalized to performance of that era)?
Here's a somewhat older approach splitting charts into linear runs of 1x1 images, which has some statistics at the bottom of each chart:

https://www.masswerk.at/demospace/relayWeb_en/chartset.htm

(Or see https://www.masswerk.at/demospace/relayWeb_en/welcome.htm and select "charts". Total time for calculations and rendering was then in the about 1 sec range. The real problem for using this in production was that these charts could be printed on Windows with Postscript printers only. I think, this was eventually fixed in Windows 98 SE.)

Pretty sure that was actually used in emails at some point, just with tables, to get around email clients not loading images.
Email clients generally don't load external images. The majority should still display images that are sent as part of a multipart/mixed message though, and those should take up significantly less space than thousands of divs/tds and color attributes.
I thought this is what it was going to be! Another method would be to generate a plane with the same number of vertices as pixels, store the pixel color values as an attribute, and then render the mesh to a canvas.
You can right-click canvas and save it as image.
Oh, you're right! I guess you'd have to disable the context menu too.
Which doesn't help either because in the Inspect view you can just click "Screenshot node" on the HTML element.
Results in an empty file.
Increase the time a bit, it looks like sometimes it takes more time to download curl --max-time 2 https://youcantdownloadthisimage.online/lisa.jpg > lisa.jpg
Nevermind, looks like MobaXterm shell provides a non-standard curl implementation:

$ which curl

curl: aliased to _tob curl

After installing curl with apt-get it works.

I hate it when people do that. You can wonder for hours why something obvious doesn't work as it should and in the end discover someone decided to implement something substandard, often for no good reason.
that's every distro and *nix derivation
Well, Windows too. I recently had to set up something simple on a Windows 10 machine, I quickly checked by tab-completion if a python binary is available so I copied by setup script only to discover someone smart decided to redirect the binary to the Windows Store. Yes, I know the rationale behind this, but still. Just like hijacking nxdomain.
Add -N, --no-buffer Disables the buffering of the output stream. In normal work situations, curl will use a standard buffered output stream that will have the effect that it will output the data in chunks, not necessarily exactly when the data arrives. Using this option will disable that buffering.

and it works

right click > copy image > paste somewhere

Works for me :) (I pasted in Telegram FYI)

It downloaded on Safari on iOS. Long press on the image and tap Add to photos.
Same for me, but the webpage gave the impression that it was still downloading, because after it download completely, at least in firefox on iPhone, it’s still showing that it was downloading.
I could copy the image from Firefox. Are you sure you downloaded it instead of copying it?
iPhone Safari - Instant Download, no problem!
iPhone > long press > Add to photos

What am I missing?

I posted the same snarky comment too. Seems the headline should be “You can’t download this exact image, but you can copy the presentation image via other means.”

More of a play on words for how copy and download often times mean the same thing even though technically they’re different.

I guess this is very similar to res.end() in nodejs servers
Load the website in Firefox with the Network Panel open, hit "Escape", and right-click "lisa.jpg" -> "Save Image As"
Hm opened chrome console and saved it from sources there, took 30 secs :)
The problem with leaving connections open is that there's a limit on how many you can have on the server... I think the author has committed self-DoS :)

https://en.wikipedia.org/wiki/Slowloris_(computer_security)

And now you can't download that image.
Yeah it's like a breeder reactor, it makes its own fuel.
Yep. Although with the right language, even on cheap hardware, that limit might be 1,000 or so.
1000… pft.. just holding open a connection and sending on average a few bytes a second hardly costs anything and the memory requirements on eg Linux are minimal. You can easily do 100k or more with python and a few hundred megs of memory. Millions are doable with something a little less memory hungry or throwing more memory at it.
Most programmers these days don't know what computers are capable of.
if you aren't using 14 layers of abstraction you clearly aren't a real programmer /s
In fairness to them, a lot of programmers didn't come up the way (we presumably) did - if you started using computers/programming in the 80's and building computers in the 90's your worldview is going to be fundamentally different to someone who started in 2018.

We came from a world where bytes mattered they come from a world where Gigabytes matter.

In some ways caring about that stuff can be detrimental, at the back of my mind there is always that little niggle - you could do this in 1/10th the runtime/memory cost but it'll take twice as long to write and you'll be the only one who understands it.

These days we don't optimise for the machine but instead for the human time and honestly, that's an acceptable trade off in many (but not all) cases.

It can be frustrating when you remember how much of an upgrade getting a 286 was over what you had, that I now routinely throw thousands of those (in equivalence) at a problem inefficiently and still get it done in under a second.

(comment deleted)
It would be possible to really close the connection but hack something to don't inform the client. (maybe just doing close() with SO_LINGER=0 and dropping outgoing RST in iptables would be enough)
The client would eventually time out though, right?
Yes, browsers probably have their own relatively short timeouts. (curiously enough, system TCP stack will never close idle connections by default, and even if application requests SO_KEEPALIVE, default intervals are usually in hours range)
Great! Just what we need these days: more tricks to screw around with the simple, straightforward implementation of the HTTP protocol! And just in time for Christmas.
Firefox mobile did hang when trying to download, but after pressing cancel the image was downloaded and viewable in my gallery app.
Same here
(comment deleted)
This does create a self inflicted Slowloris attack on the server hosting the image, so this site is probably more susceptible to the hug of death than most
When you usually try to download an image, your browser opens a connection to the server and sends a GET request asking for the image.

I'm not a web designer, but that seems rather ass-backwards. I'm already looking at the image, therefore the image is already residing either in my cache or in my RAM. Why it is downloaded a second time instead of just being copied onto my drive?

Oh no, it's still downloading the one it's displaying on screen. You can even see a spinny thing as the icon of the tab on Chrome.

The format allows for showing images when they are partially downloaded, and also allows pushing data that doesn't actually change the image.

Okay? So we still seem to have an accurate representation of the image we want. Why can't I just download that and what's the point of the rest of the data. If we already are seeing the image, the rest of the data is pointless no?
but the browser doesn't know that the image is already done, and since there's still data coming in, the browser is obliged to continue downloading.

you could right click, and copy image, rather than save as. It achieves what you wanted - save a copy of the image.

Certainly so, yes. But your browser doesn't know that.
I don't know about browser internals, but I would guess that the browser decodes the image once into a format that can be shown on the page (so from PNG/JPG/WEBP into a RGBA buffer) and then discards the original file. This saves a bit of memory in 99.99% of cases when the image is not immediately saved afterwards.
Interesting if that is the explanation. I wonder if any browsers offer a "privacy mode" where the original images are saved, thereby preventing the server from knowing which specific images you chose to save and were therefore interested in. I wonder how often that information is logged, and whether those logs, if they exist, have ever been put to a purpose such as in a court case.
More likely the original file is saved in the browser cache. That's why it loads faster when you reload the page, and slower when you do a full reload by holding down shift. In Firefox you can see the files with about:cache, and find them in ~/.cache/mozilla/firefox/e1wkkyx3.default/cache2/entries/ or similar (they have weird names with no extension, but the file command will identify them, in their original format). In Chrome they're packed into files with metadata like the URL at the start. You can extract the original file by looking at a file in the cache folder [1] and snipping the header off (you can guess where it is by looking at the file contents with xxd or a hex editor).

More info (and link to a Windows viewer tool) here: https://stackoverflow.com/questions/6133490/how-can-i-read-c...

[1] For me on Linux, Chrome's is ~/.cache/google-chrome/Default/Cache/

One cool related thing is that (I believe) modern graphics cards (even Intel) can store and use JPG blocks directly from GPU memory, so it's not necessarily beneficial in the long term to convert to RGBA in advance. Though I think no modern browser actually does this, especially given how power-cheap decoding jpeg (with SIMD) already is and how likely it is that gpu bugs would interfere.
I don't think they can use jpg directly, that would be a waste of transistors given that the graphics world use other compression formats like etc1, bc, astc and so on.

It is however perfectly possible to decode blocks of JPG on a GPU by using shader code.

I'm pretty sure that Safari (and probably most browsers) on MacOS renders JPEGs via CoreImage, and I have seen hints that CoreImage has various GPU-accelerated pathways, though I don't know whether those include DCT or JFIF on the GPU.
I'm pretty sure it only discards the original after x number of other (new) images have been decoded. (Or perhaps it's memory footprint based?)

I ran into a Chrome performance bug years ago with animations, because the animation had more frames than the decoded cache size. Everything ground to a halt on the machine when it happened. Meanwhile older unoptimized browsers ran it just fine.

This used to be common behavior, but changed over time in most browsers.

Your guess is as good as mine as to why.

As far as I remember from a previous project from a few years ago, the browser doesn't include a referrer for the download request, which can be used for a distinction. (You'll have to disable caching and E-Tags for this to work.)

However, this is easily defeated by the use of the console: Select the sources tab, locate the image and simply drag-and-drop the image from there, which will use the local cache instance for the source. Works also with this site, at least with Safari.

> [...] which will use the local cache instance for the source

I don't understand why browsers aren't always doing this. They already have the image, why redownload it?

> They already have the image, why redownload it?

They don’t already have the image. They have part of the image. Because the connection hasn’t closed, as far as the browser is concerned, it’s still in the process of downloading it.

I guess, this is for historical reasons. Mind that there is no such thing as a single, cached image. There's the downloaded content, a decoded bitmap derived from this, a buffer for any instance of the image, which may be clipped or distorted (and may have local color management applied, e.g., converted to 8-bit color range). (At least, it used to be that way. I faintly remember that this used to be a 4-step process.) When memory wasn't ample, any of these, but the instance buffer(s), may have been purged, and an instance buffer doesn't represent the original image anymore. So it makes sense to get a new clean image in the original encoding.
I have problem understanding what problem is this solving?

When the image is on my screen I can just screenshot it.

This is a common problem, using something in insecure environment, thats why companies are going into such extents to encrypt movies on whole train from source to the display and even those are regularly dumped.

And even if they figured out some DRM method to prevent screenshotting/screen recording, I can still point my phone camera at my monitor and capture it that way, if I really want to. There is always a way around whatever they try to do.

If I can see it, I can make a copy of it.

But because they try the rest of us suffer the consequences of more expensive and slower hardware and all kinds of other problems.
Yes. DRM always hurts the legitimate users more than the "pirates". Same with disabling right click or otherwise trying to prevent downloading images.
> I can still point my phone camera at my monitor and capture it that way

Back in the late 1990s/early 2000s (this was so long ago that I cannot quickly find a reference), there were proposals to require all non-professional audio and video recorders to detect a watermark and disable recording when one was found. Needless to say this was a terrible idea, for several reasons.

It's not "solving" anything, just demonstrating an interesting gimmick
Definitely a gimmick. Interesting might be a bit of a stretch
What’s the gimmick because I just save that image to photos on iOS?
You can totally "download" the image in your RAM by right clicking / long pressing -> "copy image" or equivalent in most browsers. It's just not going to be a byte by byte identical file, and may be in a different format, e.g. you get a public.tiff on the clipboard when you copy an image from Chrome or Safari on macOS, even if the source image is an image/svg+xml.
That's the first thing I tried, "copy image" then, on gimp, file->create->from clipboard.

And it just worked, with no hassle.

> When you usually try to download an image, your browser opens a connection to the server and sends a GET request asking for the image.

I can't vouch for chromium-*, but my Firefox does NOT do that. I've just tested it.

The site does not send a Content-Type header for the main web page, so I get a download dialog when trying to open it.
Drag and drop to Desktop on macOS works too.
On Google Pixel there is a new feature where I can go to the recent app screen and it defects images to click on them to do Google lense or save images or share image. I was able to save the image of size 506kb with 841x1252 1.1MP pic.
I just simply long tapped on the image and tapped save to photos on my iPhone and it was saved.