I was playing around with my links page which is populated dynamically by del.icio.us and came across their example to show favicon pictures alongside each list entry which looked quite nice I thought.
What I noticed as I was playing with and reloading the page was the number of slow outbound image requests my browser was making, fetching the (sometimes non-existent) images from each of the remote servers listed. I figured it should be easy enough to reference a dynamic image in Zope that downloads the remote images dynamically and keeps a cached copy for next time.
After a bit of research, I wrote up the following fairly simplistic Zope Extension (save in your Zope Extensions folder under your active Zope instance, not the original source directory) and the Python script that calls it as well:
# Copyright (C) 2006, Michael T. Babcock <firstname.lastname@example.org> # Feel free to reuse at will; BSD or Zope licensing applies at your discretion. # Consider giving me credit somewhere if you appreciated this. import urllib from StringIO import StringIO def imagefetch(self, domain): """Return the favicon.ico file stored at http://domain/favicon.ico converted to PNG format and resized to 16x16 just in case""" image_file = StringIO() image_data = "" try: remote_image = urllib.urlopen("http://%s/favicon.ico" % domain) image_data = remote_image.read() except: return None if len(image_data) == 0: return False try: # write image_file image_file.write(image_data) image_file.seek(0) except: return None # Convert to PNG import PIL png_image = PIL.Image.open(image_file) png_image = png_image.convert('RGB') png_image = png_image.resize((16,16),PIL.Image.ANTIALIAS) png_image_file = StringIO() png_image.save(png_image_file, "PNG") # Create image in cache image_id = "%s.png" % domain try: favicons = self['favicons'] if favicons.hasObject(image_id): favicons.manage_delObjects([image_id]) favicons.manage_addProduct['OFSP'].manage_addImage(image_id, png_image_file, 'favicon for %s' % domain) except: return None #image_info = getattr(self, image_id) return image_id
Once the above script is in your Extensions folder, add an extension to your images directory on your Zope server (or wherever you like) from within the browser interface specifying the function name (imagefetch) and the extension name (Zdynimage). You'll now be able to use the following Zope Script to dynamically load and cache remote images:
request = container.REQUEST RESPONSE = request.RESPONSE if not request.traverse_subpath[-1] == "favicon.png": return "<P>Usage: <code>/thisscript/<em>sitename</em>/favicon.png</code></P>" # Take the final path element, use as domain name try: domain = str(request.traverse_subpath[-2]) except: return "<P>Error: specify path after filename</P>" url = "http://%s/favicon.ico" % domain data = "" image_id = "%s.png" % domain # if not exists cached image, load it into cache from site if not context.favicons.hasObject(image_id): ret = context.imagefetch(domain) # return data of cached image try: if 0: return "<P>image %s in favicons</P>" % image_id data = context.favicons[image_id].data # line 25 except KeyError, e: data = context['delicious_medium_png'].data RESPONSE.setHeader('Content-Type','image/png') return data
I'll bother typing this in shortly. For now I hope the code above helps you out.
I scale all the images to the size I want to display them in so as not to save more image data than necessary and also convert them to PNG format in the process. This may not be appropriate for other uses. Removing this functionality would be simple enough; its only a few lines of PIL code (and the Python Imaging Library is wonderful to work with).
Please note there's no domain matching. I'm writing a quick check that will make sure the script is called only from your own pages, to avoid remote abuse. Ironically this could lead to massive abuse of your server if you don't implement such measures (ironic since the purpose is to partly to avoid abusing remotely referenced servers).
Also realize there is no cache expiry supported or negative caching. The images downloaded stay on your server in the configured directory until you manually delete them and sites without said images will be probed for them on every reference (although this is already normal for normal page loads of those sites).
As stated above, I need to write a little one or two-liner that makes sure the site referrer is within my domain(s). I'd also like to make its functionality a little more generic for the sake of other users. I'm not sure if its worth it for my favicons at a few kilobytes each, but dynamically expiring the images and/or actually doing HTTP ETag/Last-Modified checks like a real caching provider would be interesting (of course, this would already happen if I checked them every time since my webserver is behind a caching proxy for outbound requests). Deleting old, unreferenced images would obviously make sense and setting a configurable cache membership property within Zope would be good to avoid refresh delays. Any volunteers?
Page Copyright © 2014, Michael T. Babcock. All Rights Reserved.
To contact me, send an E-mail to
sawyoursite at this domain.
If you'd really like your mail server reported for spam, send me some junk mail to email@example.com or firstname.lastname@example.org. This site powered by djbdns