Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import random
- import time
- import sys
- import argparse
- from collections import defaultdict
- import board
- import busio
- import adafruit_ssd1306
- from PIL import Image, ImageDraw, ImageFont
- parser = argparse.ArgumentParser()
- parser.add_argument('spell', help='The emojimagick spell string, including '
- 'the binding emoji on start and end.')
- parser.add_argument('--width', type=int, default=128,
- help='Width of the OLED (default: 128)')
- parser.add_argument('--height', type=int, default=32,
- help='Height of the OLED (default: 32)')
- parser.add_argument('--font', default='./Symbola.otf',
- help='Emoji font to use (default: ./Symbola.otf)')
- parser.add_argument('--font-size', type=int, default=19,
- help='The font size (default: 19)')
- parser.add_argument('--rounds', type=int, default=7,
- help='How many times to cycle the spell at each binding '
- '(default: 7)')
- parser.add_argument('--showtime', type=float, default=0.7,
- help='How long to show each emoji cast, in seconds '
- '(default: 0.7)')
- parser.add_argument('--binding_showtime', type=float, default=None,
- help='Timestep of binding animation (default: showtime/77)')
- args = parser.parse_args()
- if not args.binding_showtime:
- args.binding_showtime = args.showtime/77
- class EmojiAutoCaster():
- def __init__(self, spell, oled, font: ImageFont,
- rounds: int, showtime: float, binding_showtime: float,
- ):
- (self.spell, self.oled, self.font,
- self.rounds, self.showtime, self.binding_showtime) = (
- spell, oled, font, rounds, showtime, binding_showtime)
- # the emojimagick binding characters
- self.binding_start = self.spell[0]
- self.binding_end = self.spell[-1]
- # '1' = 1-bit color.
- self.image = Image.new("1", (oled.width, oled.height))
- self.draw = ImageDraw.Draw(self.image)
- # this dict is used to clear characters before redraw.
- #
- # each character has an arbitrary name, and the dictionary keeps track
- # of the previous rectangle that contained that named character.
- self.previous = defaultdict(lambda: None)
- self.oled.fill(0) # clear
- def drawborder(self, margin:int=1, mirror:bool=False, fill:int=1):
- left=0+margin
- top=0+margin
- bottom=self.oled.height-margin
- right=self.oled.width-margin
- for x in range(left, right):
- if mirror:
- self.draw.point((right-x, top), fill=fill)
- self.draw.point((x, bottom), fill=fill)
- else:
- self.draw.point((x, top), fill=fill)
- self.draw.point((right-x, bottom), fill=fill)
- self.oled.image(self.image)
- self.oled.show()
- def redrawborder(self, margin:int=1):
- self.drawborder(mirror=True, fill=0)
- self.drawborder(mirror=False, fill=1)
- def cast_emoji_centred(self,
- emoji: str,
- charname: str,
- x: int,
- y: int=0,
- previous_rect: (int,int,int,int)=None) \
- -> (int, int, int, int):
- '''Draw centred on x,y. Returns rect of drawing.
- charname is an arbitrary identifier; if a character with this
- identifier was drawn before, its rectangle will be erased first.'''
- if self.previous[charname]:
- self.draw.rectangle(self.previous[charname], fill=0)
- (emoji_width, emoji_height) = self.font.getsize(emoji)
- x = x - emoji_width / 2
- y = y - emoji_height / 2
- self.draw.text(
- (x, y),
- emoji,
- font=self.font,
- fill=1,
- )
- previous_rect = (x, y, x+emoji_width, y+emoji_height)
- self.previous[charname] = previous_rect
- def initial_bind(self):
- y = self.oled.height/2
- x = 0
- while x <= self.oled.width/2:
- self.cast_emoji_centred(
- self.binding_start,
- 'binding start',
- x, y)
- self.cast_emoji_centred(
- self.binding_end,
- 'binding end',
- self.oled.width-x, y)
- self.oled.image(self.image)
- self.oled.show()
- time.sleep(self.binding_showtime)
- x += 1
- def cast(self):
- working=self.spell[1:-1]
- i=0
- self.drawborder()
- self.initial_bind()
- # loop over one emoji at a time
- while True:
- if i == self.rounds * (len(working)):
- self.redrawborder()
- self.initial_bind()
- i=0
- working_element=working[i%len(working)]
- # working_element=working_element[0] # modifiers not well rendered
- # always redraw the binding (invisibly) first
- (binding_start_width, binding_start_height) = self.font.getsize(self.binding_start)
- self.cast_emoji_centred(self.binding_start, 'binding start',
- self.oled.width/2-binding_start_width-7,
- self.oled.height/2)
- self.oled.image(self.image)
- self.cast_emoji_centred(working_element, 'working element',
- self.oled.width/2, self.oled.height/2,)
- self.oled.image(self.image)
- (binding_end_width, binding_end_height) = self.font.getsize(self.binding_end)
- self.cast_emoji_centred(self.binding_start, 'binding end',
- self.oled.width/2+binding_end_width+7,
- self.oled.height/2,)
- self.oled.image(self.image)
- self.oled.show()
- time.sleep(self.showtime)
- i+=1
- def getCaster():
- i2c = busio.I2C(board.SCL, board.SDA)
- oled = adafruit_ssd1306.SSD1306_I2C(args.width, args.height, i2c)
- try:
- emojifont = ImageFont.truetype(args.font, args.font_size)
- except OSError as e:
- sys.stderr.write(f"Could not open font {args.font}:\n")
- sys.stderr.write(str(e))
- sys.stderr.write("\n")
- sys.exit(1)
- return EmojiAutoCaster(args.spell, oled, emojifont,
- args.rounds, args.showtime, args.binding_showtime,
- )
- getCaster().cast()
Advertisement
Add Comment
Please, Sign In to add comment