Skip to content
This repository

Support for Retina displays #175

Closed
jrief opened this Issue · 10 comments

3 participants

Jacob Rief Morgan Craft Chris Beaven
Jacob Rief

Owners of MacBook Pro's with Retina Display might miss high resolution images on their computer.
Since the original image is bigger than the thumbnailed one, it would be quite easy to produce a special high-resolution thumbnail with double resolution. Here is some information about how such a feature has been implemented for WordPress: http://wpmu.org/wordpress-retina/

Note, that browsers with Retina display do not send this information though their User-Agent header. They can however be induced to set a cookie, which passes their window.devicePixelRatio to the server. This avoids to load the same picture twice, once in normal and once in double resolution.

After reading the thumbnailing code, I came to the conclusion, that such a feature must be implemented in easy_thumnails.templatetags.ThumbnailNode.render(). Adding another image processor is of no help, because this feature requires access to Django's RequestContext object which is not available there, unless the API is changed to pass the RequestContext into get_thumbnailer(source).get_thumbnail(opts)

Jacob

Jacob Rief jrief referenced this issue in stefanfoulis/cmsplugin-filer
Open

Support for Retina displays #77

Morgan Craft

+1

Jacob Rief

No sign of activity on this feature request for 3 month now, and I would like implement this feature now.
Since one has to change the API of class ThumbnailNode it would be helpful to get some kind of feedback from the original authors of this project, about how to do it the proper way.
Jacob

Chris Beaven
Owner

Sorry, I did look at the issue but never got around to writing a reply.

I wondered about a separate thumbnail tag that looks for request on the context and can change the resolution based on that.
But this is really an edge case, and I don't want to put anything too specific in core, just make it easier for you to use it however you need.

The most basic suggestion would be that you use two aliases for each size (e.g. "square", "square_hd") and then use a conditional tag to pick the correct alias:

{% retina_alias "square" as alias %}
{{ obj.photo|thumbnail_url:alias }}
{% endretina_alias %}
Chris Beaven
Owner

Here's another good idea: use a context processor to just pass the correct aliases to the template.
It'd iterate the potential global aliases, and make a thumbnail_[name] for each one, substituting the "_hd" version for the correct user-agent requests.

Then you'd just have a simple {{ obj.photo|thumbnail_url:thumbnail_square }} in the template.

Yep, that is pretty enough that I'd consider that processor for core.

Chris Beaven
Owner

Well, reading the article again, I see that you can't just dump a larger size out, you need to change the width / height of the image too, which means that the context processor idea doesn't work.

It probably also actually makes #17 a prerequisite of this one.

And my latest imaginatory tag is:
{% get_hd_thumbnail obj.photo "square" as thumb %} {# adding a ThumbnailFile to context #}
{{ square.tag }}

After generating the thumbnail using the "square_hd" alias, it'll set _dimensions_cache to the percentage difference with "square" width/height.

Ok, enough rambling.

Jacob Rief

From my point of view, I would not put any responsibility for hq-thumbnails on the template designer. This causes more trouble than benefit. hq-thumbnails should integrate as seamlessly as possible. Therefore the existing and common templates shall do the job.

I digged through the code today, and I agree that accessing the RequestContext object is of no help here. I also believe, that the image URL written into the HTML code by templatetag {% thumbnail ... %} shall be the same, independently of the rendering browser. This is an important requirement for caching the rendered templates.

It also means, that a browser running on a retina display "sees" the same image URL as a browser running on a standard display.
Now, who decides which image shall be loaded from the media path? There are two approaches:
1. on a browser running on a retina display, after loading the html code, jQuery searches for all image tags and replaces the URL by appending @2x to itself.
2. a browser running on a retina display sets a special cookie value indicating that it desires double resolution images. Now, Apache or Nginx detect this cookie, and instead of delivering the standard definition image, they deliver the high definition image.

This means that during thumbnail generation, two thumbnails are generated: One as usual, and one in double resolution with @2x appended to its filename. This also means that Thumbnailer does not have to know, if the image was requested by a standard browser or a browser running on a retina display. Thumbnailer, now always generates two images, unless a configuration directive disables this feature.

I think we should consider this approach, since changing the HTML output depending to the browsers display, makes caching impossible.

What do you think?
Jacob

Jacob Rief

I have found two articles about this issue, and they share my opinion:
http://oliverspindler.com/articles/2012/04/05/conditionally-serving-high-resolution-images/
http://undefinedbehavior.net/2012/03/27/retina-rewrite/

During development, an alternative django.contrib.staticfiles middleware would help to server high resolution images for browsers running on retina displays.

Chris Beaven
Owner

Can't say I'm a fan of sharing the same url for high and low-res versions. This could easily mess with upstream caches. In my opinion, this is definitely in the realm of template logic.

I'm also trying to consider how to make this optional - it's a bad assumption that everyone wants to produce these 2x thumbnails. Perhaps there should be a thumbnailer option like "retina" that will produce the double sized image in addition to the standard one (this option being excluded from the filename generation).

Jacob Rief

Putting it into the realm of the template logic, can be even a bigger mess. Generated html pages almost always are cached, so what should the solution be here? Using HTTP header Vary certainly is not an option, because there is no such header (yet) indicating that hq images are desired.

If approach 1 (see above) is used, you dont even mess up with upstream caches. This also works for background-image in css using the @media all and (-webkit-min-device-pixel-ratio: 2)directive.

I wrote "unless a configuration directive disables this feature". Sure, it shall be configurable to enable the automatic generation of two different versions for each thumbnail.

We should look how other frameworks solved this problem. Can you point me onto a proposal, which favors your approach?

Jacob

Jacob Rief jrief referenced this issue from a commit in jrief/easy-thumbnails
Jacob Rief jrief Possible solution for issue #175 c727181
Jacob Rief jrief referenced this issue from a commit in jrief/easy-thumbnails
Jacob Rief jrief Fixed annotation 2 of #175 262b1a7
Chris Beaven
Owner

This got fixed. Not sure why it didn't get closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.