txkcd - scripts - random scripts
 (HTM) git clone https://git.parazyd.org/scripts
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       txkcd (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()