Improved text image view
I just found this in my django-ego-feed: 23 excuses: Simple Django View for Dynamic Text Replacement
I’ve been using something similar to generate the titles for the site (look at the title above for an example), so I’m pretty familiar with the technique.
Andrew’s code over there is pretty good, but I’ve got a few improvements he and you might be interested in:
The business to writing to a temp file is ugly and will break as soon as you get two simultaneous requests. The right way to do this is by remembering that an
HTTPResponse
exposes a file-like interface, so you can write the image directly to it:response = HTTPResponse(mimetype="image/png") im.save(response, "PNG")
You’ll save on bandwidth and processor time if you add in E-tag support. This’ll let browsers cache your image locally and save you from generating and sending it each time.
This is actually pretty easy to do. At the start of the view, calculate the E-tag and check it against the
If-None-Match
header:etag = md5.new(header + fontalias).hexdigest() if request.META.get("HTTP_IF_NONE_MATCH") == etag: return HttpResponseNotModified()
Then, just before you return the response, insert the E-tag header:
response["e-tag"] = etag
As long as we’re being pedantic about HTTP, let’s return a
403 Forbidden
for a bad font file (instead of a200 OK
)
Here’s the complete view_header()
code with my modifications:
import md5
from django.conf import settings
from django.http import (HttpResponse,
HttpResponseNotModified,
HTTPResponseForbidden)
import Image, ImageFont, ImageDraw
def view_header(request, fontalias):
try:
fontfile = settings.DYNAMIC_FONT_ALIASES[fontalias]
except:
return HttpResponseForbidden("font alias not supported")
if request.GET.has_key('text'):
header = request.GET['text']
else:
header = 'Hello world'
etag = md5.new(header + fontalias).hexdigest()
if request.META.get("HTTP_IF_NONE_MATCH") == etag:
return HttpResponseNotModified()
imf = ImageFont.truetype(fontfile, 20)
size = imf.getsize(header)
im = Image.new("RGB", size)
draw = ImageDraw.Draw(im)
draw.text((0, 0), header, font=imf)
response = HTTPResponse(mimetype="image/png")
im.save(response, "PNG")
response["e-tag"] = etag
return response
Enjoy!