xkcd (3822B)
1 #!/usr/bin/env python 2 # 3 # grab a random xkcd comic, append title and alttext, and save to a dir 4 5 from os import environ 6 from re import search 7 from random import randrange 8 9 from PIL import Image, ImageDraw, ImageFont 10 from requests import get 11 12 DOWNLOAD_DIR = environ['HOME']+'/xkcd/' 13 TITLE_FONTSIZE = 28 14 ALT_FONTSIZE = 18 15 LINE_OFFSET = 10 16 17 def add_text(image, title, alt, tfont=DOWNLOAD_DIR+'xkcd.ttf', 18 afont=DOWNLOAD_DIR+'xkcd.ttf'): 19 try: 20 img = Image.open(image) 21 except OSError: 22 return 23 24 tfont = ImageFont.truetype(tfont, TITLE_FONTSIZE) 25 afont = ImageFont.truetype(afont, ALT_FONTSIZE) 26 27 line_padding = 5 28 draw = ImageDraw.Draw(img) 29 lines = text_wrap(tfont, title, img.size[0]) 30 lheight = max([tfont.getsize(" ".join(i))[1] for i in lines]) 31 lheight_total = (lheight+line_padding)*(len(lines))+line_padding*4 32 title_crop = (0, -1*lheight_total, img.size[0], img.size[1]) 33 img = img.crop(title_crop) 34 w, h = img.size 35 old_h = h 36 draw = ImageDraw.Draw(img) 37 lheight_total = line_padding 38 for i in lines: 39 draw.text((w/2-tfont.getsize(" ".join(i))[0]/2, lheight_total), 40 " ".join(i), font=tfont, fill=0xffffff) 41 lheight_total += lheight + line_padding 42 lheight_total = line_padding 43 lines = text_wrap(afont, alt, w) 44 lheight = max([afont.getsize(" ".join(i))[1] for i in lines]) 45 lheight_total = lheight*len(lines) 46 alt_crop = (0, 0, img.size[0], 47 img.size[1]+lheight_total+(len(lines)+3)*line_padding) 48 img = img.crop(alt_crop) 49 draw = ImageDraw.Draw(img) 50 lheight_total = old_h + line_padding 51 for i in lines: 52 if not i: 53 continue 54 draw.text((w/2-afont.getsize(" ".join(i))[0]/2, lheight_total), 55 " ".join(i), font=afont, fill=0xffffff) 56 lheight_total += lheight + line_padding 57 58 img.save(image) 59 print(image) 60 exit(0) 61 62 def text_wrap(font, text, image_width, i=0): 63 lines = [[]] 64 text = text.split(" ") 65 while text: 66 while text \ 67 and font.getsize(" ".join(lines[i]))[0] < image_width: 68 if font.getsize(text[0]+" "+" ".join(lines[i]))[0] > image_width * 0.95: 69 if len(lines[i]) == 0: 70 text[0] = text[0][:len(text[0])//2+1] \ 71 + " " + text[0][:len(text[0])//2+1:] 72 text = text[0].split(" ") + text[1:] 73 break 74 lines[i].append(text[0]) 75 text.pop(0) 76 i += 1 77 lines.append([]) 78 sub = [] 79 for e, i in enumerate(lines): 80 if font.getsize(" ".join(lines[e]))[0] > image_width: 81 temp_str = "" 82 for c in "".join(i): 83 if font.getsize(temp_str+c)[0] > image_width: 84 lines[i] = lines[i][:len(lines[i])//2] \ 85 + lines[i][len(lines[i])//2:] 86 break 87 temp_str += c 88 sub.append(temp_str) 89 del lines[e] 90 lines = [i for i in lines if len(i) != 0] 91 for c in [i for i in sub if len(i) != 0]: 92 lines.append(c) 93 return lines 94 95 def main(): 96 info = get("https://xkcd.com/info.0.json").json() 97 if not info: 98 exit(1) 99 info = get("https://xkcd.com/"+str(randrange(1, info['num']) + 1)+"/info.0.json").json() 100 101 title = info['safe_title'] 102 alt = info['alt'] 103 num = str(info['num']) 104 105 image = num+search("\.([a-z])+$", info['img']).group() 106 107 with open(DOWNLOAD_DIR+image, 'wb') as image_file: 108 req = get(info['img'], stream=True) 109 for block in req.iter_content(1024): 110 if block: 111 image_file.write(block) 112 image_file.flush() 113 if not search("\.gif", info['img']): 114 add_text(DOWNLOAD_DIR+image, title, alt) 115 116 main()