initial commit
This commit is contained in:
commit
72da13f349
6 changed files with 124 additions and 0 deletions
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# shirtgen - a maiacore t-shirt design generator
|
||||
|
||||
How to use:
|
||||
|
||||
* write a shirtfile (see example.shirt for an example and the comments in gen.py for a documentation of the format)
|
||||
* run `gen.py <shirtfile>` to generate a png
|
||||
|
||||
## Example
|
||||
|
||||
shirtfile:
|
||||
```
|
||||
m:b:fill FIRST
|
||||
m:r:fill second line
|
||||
r:r:400 third line
|
||||
```
|
||||
|
||||
output:
|
||||
![three lines of text, the first one is really big and says "first", the second line is smaller and says "second line" a third, even smaller line says "third line"](example.png)
|
BIN
example.png
Normal file
BIN
example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
3
example.shirt
Normal file
3
example.shirt
Normal file
|
@ -0,0 +1,3 @@
|
|||
m:b:fill FIRST
|
||||
m:r:fill second line
|
||||
r:r:400 third line
|
BIN
fonts/F25_Bank_Printer.ttf
Normal file
BIN
fonts/F25_Bank_Printer.ttf
Normal file
Binary file not shown.
BIN
fonts/F25_Bank_Printer_Bold.ttf
Normal file
BIN
fonts/F25_Bank_Printer_Bold.ttf
Normal file
Binary file not shown.
103
gen.py
Normal file
103
gen.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
from PIL import Image, ImageDraw, ImageFont
|
||||
import sys
|
||||
|
||||
# fonts are defined here
|
||||
fonts = {
|
||||
"r": "fonts/F25_Bank_Printer.ttf",
|
||||
"b": "fonts/F25_Bank_Printer_Bold.ttf",
|
||||
}
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print("please specify a path to a shirtfile")
|
||||
exit(1)
|
||||
|
||||
# parse shirtfile into list of tuples
|
||||
#
|
||||
# shirtfile syntax:
|
||||
# a shirtfile is a plain-text file made up of lines in the following format
|
||||
# {alignment}:{font}:{size} {text}
|
||||
# where:
|
||||
# - alignment can be:
|
||||
# * 'm' for centered text
|
||||
# * 'l' for left aligned text
|
||||
# * 'r' for right aligned text
|
||||
# - font can be one of the configured fonts above, included per default are:
|
||||
# * 'r' for F25 Bank Printer (regular)
|
||||
# * 'b' for F25 Bank Printer Bold
|
||||
# - size is either 'fill' to automatically calculate a font size to fill the width of the canvas
|
||||
# or a font size in pixels
|
||||
# - text is your desired line of text (with no line breaks)
|
||||
# the shirtfile parser treats lines starting with # as comments and ignores empty lines
|
||||
#
|
||||
texts = []
|
||||
with open(sys.argv[1], "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for line in lines:
|
||||
# skip comments and empyt lines
|
||||
if line.startswith("#") or len(line.strip()) == 0:
|
||||
continue
|
||||
|
||||
parts = line.strip().split(" ", 1)
|
||||
texts.append(tuple(parts[0].split(":")) + (parts[1],))
|
||||
|
||||
# create transparent 5000x5000 image
|
||||
im = Image.new("RGBA", (5000, 5000), (0, 0, 0, 0))
|
||||
|
||||
# quick maths
|
||||
# calculate appropriate text sizes and bounding box sizes for positioning later
|
||||
p_texts = []
|
||||
total_height = 0
|
||||
for text in texts:
|
||||
font_size = 50
|
||||
font_path = fonts[text[1]]
|
||||
bbox_size = (0, 0)
|
||||
font = None
|
||||
|
||||
if text[2] == "fill":
|
||||
# dynamic font size calc is hell
|
||||
# reload font at increasing size until we fill out the whole canvas width
|
||||
while bbox_size[0] < (im.size[0] - 5):
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
bbox = font.getbbox(text[3], anchor=f"{text[0]}b")
|
||||
bbox_size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
|
||||
font_size += 5
|
||||
else:
|
||||
# load font for configured size and do bbox calculation
|
||||
font_size = int(text[2])
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
bbox = font.getbbox(text[3], anchor=f"{text[0]}b")
|
||||
bbox_size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
|
||||
|
||||
print(f"selected font size {font_size}")
|
||||
|
||||
total_height += bbox[1]
|
||||
p_texts.append(text + (font, bbox_size))
|
||||
|
||||
# account for padding
|
||||
total_height += (len(texts) - 1) * 20
|
||||
|
||||
# draw the text
|
||||
draw = ImageDraw.Draw(im)
|
||||
y_offset = 0
|
||||
for text in p_texts:
|
||||
# set x location dependent on alignment
|
||||
loc_x = 0
|
||||
if text[0] == "m":
|
||||
loc_x = (im.size[0]/2)
|
||||
elif text[0] == "r":
|
||||
loc_x = im.size[0]
|
||||
|
||||
# calculate y location based on total height of all text + current line height to
|
||||
# center all text together in the center of the canvas
|
||||
loc_y = (im.size[1]/2 + total_height / 2) + text[5][1] + y_offset
|
||||
|
||||
draw.text((loc_x, loc_y), text[3], font=text[4], anchor=f"{text[0]}b")
|
||||
|
||||
# add height of this line to offset
|
||||
y_offset += text[5][1] + 20
|
||||
|
||||
# crop to content and save
|
||||
im = im.crop(im.getbbox())
|
||||
filename = sys.argv[1].removesuffix(".shirt")
|
||||
im.save(f"{filename}.png", 'PNG')
|
Loading…
Reference in a new issue