add support for color variants
parent
72da13f349
commit
b93c02bd3c
|
@ -9,10 +9,14 @@ How to use:
|
||||||
|
|
||||||
shirtfile:
|
shirtfile:
|
||||||
```
|
```
|
||||||
|
# define variants to be generated
|
||||||
|
variants: _black:0:0:0 _white:255:255:255 _red:255:0:0
|
||||||
|
|
||||||
|
# declare lines
|
||||||
m:b:fill FIRST
|
m:b:fill FIRST
|
||||||
m:r:fill second line
|
m:r:fill second line
|
||||||
r:r:400 third line
|
r:r:400 third line
|
||||||
```
|
```
|
||||||
|
|
||||||
output:
|
output (red variant):
|
||||||
![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)
|
![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_red.png)
|
BIN
example.png
BIN
example.png
Binary file not shown.
Before Width: | Height: | Size: 140 KiB |
|
@ -1,3 +1,7 @@
|
||||||
|
# define variants to be generated
|
||||||
|
variants: _black:0:0:0 _white:255:255:255 _red:255:0:0
|
||||||
|
|
||||||
|
# declare lines
|
||||||
m:b:fill FIRST
|
m:b:fill FIRST
|
||||||
m:r:fill second line
|
m:r:fill second line
|
||||||
r:r:400 third line
|
r:r:400 third line
|
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
47
gen.py
47
gen.py
|
@ -7,6 +7,9 @@ fonts = {
|
||||||
"b": "fonts/F25_Bank_Printer_Bold.ttf",
|
"b": "fonts/F25_Bank_Printer_Bold.ttf",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# image size is defined as 5000 x 5000 pixels
|
||||||
|
size = (5000, 5000)
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
print("please specify a path to a shirtfile")
|
print("please specify a path to a shirtfile")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -14,7 +17,16 @@ if len(sys.argv) == 1:
|
||||||
# parse shirtfile into list of tuples
|
# parse shirtfile into list of tuples
|
||||||
#
|
#
|
||||||
# shirtfile syntax:
|
# shirtfile syntax:
|
||||||
# a shirtfile is a plain-text file made up of lines in the following format
|
# a shirtfile is a plain-text file made up of the following compontents
|
||||||
|
#
|
||||||
|
# different text color variants are defined on a line as follows
|
||||||
|
# variants: [{file_suffix}:{r}:{g}:{b}] ...
|
||||||
|
# where:
|
||||||
|
# - file_suffix is the suffix to be added to a file of this variant, can be left empty
|
||||||
|
# - r, g and b are the red, green and blue color components respecively (0-255)
|
||||||
|
# if no variants are specified white text will be output to a file with no suffix
|
||||||
|
#
|
||||||
|
# lines of text are defined as lines in the following format
|
||||||
# {alignment}:{font}:{size} {text}
|
# {alignment}:{font}:{size} {text}
|
||||||
# where:
|
# where:
|
||||||
# - alignment can be:
|
# - alignment can be:
|
||||||
|
@ -27,8 +39,10 @@ if len(sys.argv) == 1:
|
||||||
# - size is either 'fill' to automatically calculate a font size to fill the width of the canvas
|
# - size is either 'fill' to automatically calculate a font size to fill the width of the canvas
|
||||||
# or a font size in pixels
|
# or a font size in pixels
|
||||||
# - text is your desired line of text (with no line breaks)
|
# - text is your desired line of text (with no line breaks)
|
||||||
|
#
|
||||||
# the shirtfile parser treats lines starting with # as comments and ignores empty lines
|
# the shirtfile parser treats lines starting with # as comments and ignores empty lines
|
||||||
#
|
#
|
||||||
|
variants = []
|
||||||
texts = []
|
texts = []
|
||||||
with open(sys.argv[1], "r") as f:
|
with open(sys.argv[1], "r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
|
@ -38,11 +52,25 @@ with open(sys.argv[1], "r") as f:
|
||||||
if line.startswith("#") or len(line.strip()) == 0:
|
if line.startswith("#") or len(line.strip()) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# parse variants
|
||||||
|
if line.startswith("variants:"):
|
||||||
|
if len(variants) > 0:
|
||||||
|
print("variants block can only appear once")
|
||||||
|
exit(1)
|
||||||
|
parts = line.strip().removeprefix("variants: ").split(" ")
|
||||||
|
for variant in parts:
|
||||||
|
subparts = variant.split(":")
|
||||||
|
variants.append(
|
||||||
|
(subparts[0], (int(subparts[1]), int(subparts[2]), int(subparts[3]))))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# parse lines
|
||||||
parts = line.strip().split(" ", 1)
|
parts = line.strip().split(" ", 1)
|
||||||
texts.append(tuple(parts[0].split(":")) + (parts[1],))
|
texts.append(tuple(parts[0].split(":")) + (parts[1],))
|
||||||
|
|
||||||
# create transparent 5000x5000 image
|
# default to white output with no filename suffix
|
||||||
im = Image.new("RGBA", (5000, 5000), (0, 0, 0, 0))
|
if len(variants) == 0:
|
||||||
|
variants.append(("", (255, 255, 255)))
|
||||||
|
|
||||||
# quick maths
|
# quick maths
|
||||||
# calculate appropriate text sizes and bounding box sizes for positioning later
|
# calculate appropriate text sizes and bounding box sizes for positioning later
|
||||||
|
@ -57,7 +85,7 @@ for text in texts:
|
||||||
if text[2] == "fill":
|
if text[2] == "fill":
|
||||||
# dynamic font size calc is hell
|
# dynamic font size calc is hell
|
||||||
# reload font at increasing size until we fill out the whole canvas width
|
# reload font at increasing size until we fill out the whole canvas width
|
||||||
while bbox_size[0] < (im.size[0] - 5):
|
while bbox_size[0] < (size[0] - 5):
|
||||||
font = ImageFont.truetype(font_path, font_size)
|
font = ImageFont.truetype(font_path, font_size)
|
||||||
bbox = font.getbbox(text[3], anchor=f"{text[0]}b")
|
bbox = font.getbbox(text[3], anchor=f"{text[0]}b")
|
||||||
bbox_size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
|
bbox_size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
|
||||||
|
@ -77,6 +105,12 @@ for text in texts:
|
||||||
# account for padding
|
# account for padding
|
||||||
total_height += (len(texts) - 1) * 20
|
total_height += (len(texts) - 1) * 20
|
||||||
|
|
||||||
|
p_variants = []
|
||||||
|
|
||||||
|
for variant in variants:
|
||||||
|
# create transparent image
|
||||||
|
im = Image.new("RGBA", size, (0, 0, 0, 0))
|
||||||
|
|
||||||
# draw the text
|
# draw the text
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
y_offset = 0
|
y_offset = 0
|
||||||
|
@ -92,7 +126,8 @@ for text in p_texts:
|
||||||
# center all text together in the center of the canvas
|
# center all text together in the center of the canvas
|
||||||
loc_y = (im.size[1]/2 + total_height / 2) + text[5][1] + y_offset
|
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")
|
draw.text((loc_x, loc_y), text[3], font=text[4],
|
||||||
|
anchor=f"{text[0]}b", fill=variant[1])
|
||||||
|
|
||||||
# add height of this line to offset
|
# add height of this line to offset
|
||||||
y_offset += text[5][1] + 20
|
y_offset += text[5][1] + 20
|
||||||
|
@ -100,4 +135,4 @@ for text in p_texts:
|
||||||
# crop to content and save
|
# crop to content and save
|
||||||
im = im.crop(im.getbbox())
|
im = im.crop(im.getbbox())
|
||||||
filename = sys.argv[1].removesuffix(".shirt")
|
filename = sys.argv[1].removesuffix(".shirt")
|
||||||
im.save(f"{filename}.png", 'PNG')
|
im.save(f"{filename}{variant[0]}.png", 'PNG')
|
||||||
|
|
Loading…
Reference in New Issue