Saturday, November 22, 2003
Fun hack of the day: picture postcards
You can now send any picture from my collection as a postcard. Here’s an example from the recent trip to Karwar.
Postcards are delivered as email attachments, not URLs, so they last forever. The font used is Comic Sans MS. If you have a suggestion for another free True Type font, tell me.
Here's the source code, available under a BSD-like license: part #1,
Postcards are delivered as email attachments, not URLs, so they last forever. The font used is Comic Sans MS. If you have a suggestion for another free True Type font, tell me.
Here's the source code, available under a BSD-like license: part #1,
the Web form in DTML, part #2, small middle layer, and part #3, the code that generates the postcard:
# Import ImageFile even though unnecessary to prevent conflict with # Zope's ImageFile module. from PIL import ImageFile, Image, ImageFont, ImageDraw from cStringIO import StringIO import os.path card_width = 620 outline_color = (0, 0, 0) text_color = (0, 0, 0) fontpath = '/Users/jace/Zope/Extensions' fonts = { 'Marker Felt': 'MarkerFeltWide.ttf', 'Comic Sans': 'comic.ttf', } fontsize = 16 linespacing = -3 padding = 7 class dummyRequest: class dummyRes: def setHeader(*args, **kw): pass def write(self, data): self.data = data def __init__(self): self.data = '' def get_header(*args, **kw): pass def setHeader(*args, **kw): pass def __init__(self): self.RESPONSE = dummyRequest.dummyRes() def makePostcard(imageob, message="Your message here.", fontface=''): """ Returns a postcard with the message written on it. """ # XXX: Utter ugliness thanks to gaps in the ExtFile API dreq = dummyRequest() imagedata = imageob.index_html(REQUEST=dreq, RESPONSE=dreq, display='postcard') if not imagedata: imagedata = dreq.RESPONSE.data infile = StringIO(imagedata) image = Image.open(infile) card = Image.new('RGB', (card_width, image.size[1]), (255, 255, 255)) draw = ImageDraw.Draw(card) fontfile = os.path.join(fontpath, fonts.get(fontface, 'comic.ttf')) font = ImageFont.truetype(fontfile, fontsize) # Paste image if image.mode == 'RGBA': card.paste(image, (0, 0), image) else: card.paste(image, (0, 0)) # Draw outline draw.rectangle((0,0,image.size[0]-1, card.size[1]-1), outline = outline_color) draw.rectangle((0,0,card_width-1, card.size[1]-1), outline = outline_color) # Write message -- tricky part message = message.strip() message = message.replace('\r\n', '\n') message = message.replace('\r', '\n') lines = message.split('\n') awidth = card.size[0] - image.size[0] - (padding*2) yoffset = 10 segments = [] for line in lines: line = line.replace('\t', ' ') lw = draw.textsize(line, font = font)[0] if lw <= awidth: segments.append(line) else: words = line.split(' ') while words: segment = '' wc = 0 for word in words: if draw.textsize((segment ' ' word).strip(), font=font)[0] > awidth: break segment = (segment ' ' word).strip() wc = 1 for x in range(wc): words.pop(0) # In case the word is too long: if segment == '': segment = words.pop(0) segments.append(segment) for segment in segments: draw.text((image.size[0] padding, yoffset), segment, fill = text_color, font = font) yoffset = draw.textsize(segment, font = font)[1] linespacing outfile = StringIO() card.save(outfile, 'JPEG', quality=100) outfile.seek(0) return outfile.read()
bluesmoon — Nov 22, 2003 12:01:57 PM — # ↩
BTW, where can I get a good hosting service? Even if it's only for my pics and travelogs... those are the things I need permanent links for.
hserus — Nov 22, 2003 5:35:35 PM — # ↩
satyap — Nov 22, 2003 7:16:48 PM — # ↩
hserus — Nov 22, 2003 7:32:25 PM — # ↩
ravi — Nov 22, 2003 5:09:11 PM — # ↩
Excellent work, that! I'm gonna use it, sometime.
How's Sparky doing? Damn, ages ... :
Kiran Jonnalagadda — Nov 23, 2003 3:21:09 AM — # ↩
Sparky's several hundred kilometres away from where I am right now. But I'll be seeing him in a week. He's three months short of eleven years now, and still active as ever.
tariquesani — Nov 23, 2003 1:04:02 AM — # ↩
Also as usability goes I would prefer an option of send as link OR send as attachment
Kiran Jonnalagadda — Nov 23, 2003 2:52:11 AM — # ↩
But you're right about the disclaimer. I'll add that and a notice that the postcard is sent as a mail attachment, not a link.
Anonymous — Nov 23, 2003 2:29:17 PM — # ↩
evan — Nov 25, 2003 12:42:41 AM — # ↩
Kiran Jonnalagadda — Nov 27, 2003 2:28:27 AM — # ↩
I've found a few interesting freeware and cheap shareware fonts. If PIL renders them decently enough, I'll add font selection support in a day or two.