Django ImageBundle tag, an implementation of image bundle by google: http://code.google.com/p/google-web-toolkit/wiki/ImageBundleDesign. Here is how to use it: http://www.djangosnippets.org/snippets/278/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | from django.template import Library, Node, TemplateSyntaxError, \
resolve_variable, VariableDoesNotExist
from django.newforms.util import flatatt
from django.conf import settings
import Image, md5
from mx.Misc.OrderedMapping import OrderedMapping
register = Library()
# img tag # {{{
class ImgNode(Node):
def __init__(self, parts):
self.params = self.clean(parts)
def clean(self, parts):
""" validates the content, and returns a dict """
d = {}
for part in parts:
try:
name, value = part.split("=", 1)
except ValueError:
raise TemplateSyntaxError, "Syntax Error, part: %s" % part
d[name] = value
if "src" not in d:
raise TemplateSyntaxError, "SRC attribute is mandatory"
return d
def get(self, key, context, default=""):
if not key in self.params: return default
try:
return resolve_variable(str(self.params[key]), context)
except VariableDoesNotExist:
return str(self.params[key])
except Exception, e: print "big problem", e, "while key=", key
def digest(self, context):
""" returns a dict with varaibles resolved """
d = {}
for key, value in self.params.iteritems():
d[key] = self.get(key, context)
return d
def render(self, context):
d = dict(self.digest(context))
return """<img src="/static2/clear.gif" style="background-image:url(%(src)s); background-position:%(pos-x)s %(pos-y)s; width:%(width)s; height:%(height)s">""" % d
#@register.tag()
def img(parser, token):
return ImgNode(token.split_contents()[1:])
img = register.tag(img)
# }}}
# imgbundle tag # {{{
class ImgBundleNode(Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
# the main magic happens here
imgs = {}
names = []
for imgnode in self.nodelist.get_nodes_by_type(ImgNode):
src = imgnode.get("src", context)
imgs.setdefault(src, [])
imgs[src].append(imgnode)
names.append("%s:%s:%s" % (src, imgnode.params.get("width",""), imgnode.params.get("height","")))
names = "".join(names)
img_name = "/static2/%s.jpg" % md5.new(names).hexdigest()
current_x = 0
max_y = 0
final_images = OrderedMapping()
for src, nodelist in imgs.iteritems():
# as of now we only support images that are in /static/
m = Image.open(settings.SETTINGS_FILE_FOLDER.joinpath('static').joinpath(src.split("/")[-1])).convert("RGB")
for n in nodelist:
n.params["src"], n.params["pos-y"] = img_name, 0
# there are 4 cases:
if not n.params.get("width") and not n.params.get("height"):
# neither width nor height is set
w, h = m.size
elif not n.params.get("width") and n.params.get("height"):
# width not given, but height given
w, h = ((m.size[0] * 1.0) / m.size[1]) * int(n.params["height"][1:-3]), int(n.params["height"][1:-3])
elif n.params.get("width") and not n.params.get("height"):
w, h = int(n.params["width"][1:-3]), ((m.size[1] * 1.0) / m.size[0]) * int(n.params["width"][1:-3])
else:
w, h = int(n.params["width"][1:-3]), int(n.params["height"][1:-3])
if final_images.has_key("%s:%s:%s" % (src, w, h)):
i, pos_x = final_images["%s:%s:%s" % (src, w, h)]
else:
new_image = m.resize((w, h), Image.ANTIALIAS)
final_images["%s:%s:%s" % (src, w, h)] = (new_image, current_x)
pos_x = current_x
current_x += new_image.size[0]
if max_y < new_image.size[1]: max_y = new_image.size[1]
n.params["width"], n.params["height"], n.params["pos-x"] = (w, h, -pos_x)
if not settings.SETTINGS_FILE_FOLDER.joinpath('static').joinpath(img_name.split("/")[-1]).exists():
n = Image.new("RGB", (current_x, max_y))
print final_images, current_x
for k in final_images.keys():
i, p = final_images[k]
n.paste(i, (p, 0, p + i.size[0], i.size[1]))
n.save(settings.SETTINGS_FILE_FOLDER.joinpath('static').joinpath(img_name.split("/")[-1]))
return self.nodelist.render(context)
#@register.tag()
def imgbundle(parser, token):
"""
For optimizing page load in browser, the number of http requests to
server should be minimized. Javascripts can be bundled, or inlined in
the html page, and so can be CSS, but there is no way to include images.
Further, in a typical page, there are a lot of small images, icons for
example, that lead to a lot of http request by browser.
It is a well known optimization to bundle all the images into one, in
this case, we join the images end to end horizontally, and create a
single image, that will be fetched by the browser, and we will use CSS
to make sure they line up.
Put
{% imgbundle %}
at the beginning of the page, and
{% endimgbundle %}
near the bottom.
Instead of using <img>, use, {% img %} tag, which takes the same
parameters as <img> html tag.
Also in CSS, instead of using url(), use {% cssimg %}.
"""
nodelist = parser.parse(('endimgbundle', ))
parser.delete_first_token()
return ImgBundleNode(nodelist)
imgbundle = register.tag(imgbundle)
# }}}
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.