1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#!/usr/bin/env python3
import argparse
from math import floor
import os
# python3 -m pip install pillow
from PIL import Image
import sys
# (row, col)
TEX_SZ = (2048, 2048)
IMG_SZ_PX = 256
IMG_PER_ROW = int(TEX_SZ[0] / IMG_SZ_PX)
IMG_PER_COL = int(TEX_SZ[1] / IMG_SZ_PX)
# TODO(yum) this should live in a config file.
# Note: the name of the emote must be no longer than 6 characters.
IMG_TEX_DATA = []
IMG_TEX_DATA.append(("Images/Emotes/xdd.png", "xdd"))
IMG_TEX_DATA.append(("Images/Emotes/pog.png", "pog"))
IMG_TEX_DATA.append(("Images/Emotes/lulw.png", "laugh"))
IMG_TEX_DATA.append(("Images/Emotes/bighardo.png", "hard"))
IMG_TEX_DATA.append(("Images/Emotes/peepoHappy.png", "happy"))
IMG_TEX_DATA.append(("Images/Emotes/peepoSad.png", "sad"))
IMG_TEX_DATA.append(("Images/Emotes/bedge.png", "bed"))
IMG_TEX_DATA.append(("Images/Emotes/reallymad.png", "mad"))
IMG_TEX_DATA.append(("Images/Emotes/clueless.png", "surely"))
IMG_TEX_DATA.append(("Images/Emotes/what.png", "what"))
IMG_TEX_DATA.append(("Images/Emotes/based.png", "based"))
IMG_TEX_DATA.append(("Images/Emotes/chad.png", "chad"))
IMG_TEX_DATA.append(("Images/Emotes/aware.png", "aware"))
IMG_TEX_DATA.append(("Images/Emotes/girl.png", "girl"))
IMG_TEX_KEYWORD_TO_COORD = {}
for i in range(0, len(IMG_TEX_DATA)):
IMG_TEX_KEYWORD_TO_COORD[IMG_TEX_DATA[i][1]] = i
# We treat images like words. To keep things simple, they're the same height as
# a word, and they're a fixed width.
IMG_SZ_LETTER_ROWS = 1
IMG_SZ_LETTER_COLS = 6
def lookup(word: str):
word = word.lower()
word = ''.join(c for c in word.lower() if c.isalpha())
if word in IMG_TEX_KEYWORD_TO_COORD.keys():
return word, IMG_TEX_KEYWORD_TO_COORD[word]
return None, None
def openTexture(tex_path: str):
if not os.path.exists(args.texture_path):
return Image.new("RGB", TEX_SZ)
tex = Image.open(args.texture_path)
if tex.size != TEX_SZ:
print("Texture at {} has mismatching size {}, creating new texture".format(
tex_path, tex.size), file=sys.stderr)
return Image.new("RGB", TEX_SZ)
return tex
# Add an image to the texture at the coordinates (x, y). x and y should be in
# the range [0, IMG_PER_COL) and [0, IMG_PER_ROW) respectively.
def addImageToTexture(tex: Image, img_path: str, x: int, y:int):
# Transparent images will be composited on top of a black background.
img = Image.open(img_path).convert('RGBA')
img_bg = Image.new('RGBA', img.size, (0, 0, 0))
img = Image.alpha_composite(img_bg, img).convert('RGB')
max_px = IMG_SZ_PX
# Scale the image up so it uses as much space as is given to it.
# I originally planned to support multiple scales, but this proved to be
# too much work - getting line wrapping to work with this would be a pain.
# So for now, all images are the same height as words.
scale = 1
img_x, img_y = img.size
max_dim = max(img_x, img_y)
img_scale = (max_px / max_dim) * scale
new_sz = (int(floor(img.size[0] * img_scale)),
int(floor(img.size[1] * img_scale)))
print("Add image {}".format(img_path))
print(" Original size: {}".format(img.size))
print(" Scaled size: {}".format(new_sz))
img = img.resize(new_sz)
# Center the image within its new coordinate space.
padded_img_sz = (IMG_SZ_PX * scale, IMG_SZ_PX * scale)
padded_img = Image.new("RGB", padded_img_sz)
centered_x = int(floor((padded_img_sz[0] - new_sz[0]) / 2))
centered_y = int(floor((padded_img_sz[1] - new_sz[1]) / 2))
padded_img.paste(img, box=(centered_x, centered_y))
img = padded_img
# Break the image into tiles and write them into the texture.
for slot in range(0, scale * scale):
tile_x = slot % scale
tile_y = int(floor(slot / scale))
tile_bbox = (tile_x * IMG_SZ_PX, tile_y * IMG_SZ_PX, (tile_x + 1) * IMG_SZ_PX, (tile_y + 1) * IMG_SZ_PX)
tile = img.crop(tile_bbox)
print(" tile {},{} (bbox={})".format(tile_x, tile_y, tile_bbox))
slot_x = x + slot % IMG_PER_ROW
slot_y = y + int(floor(slot / IMG_PER_ROW))
slot_x_px = slot_x * IMG_SZ_PX
slot_y_px = slot_y * IMG_SZ_PX
print(" Add img at {},{} (px {},{})".format(slot_x, slot_y, slot_x_px, slot_y_px))
tex.paste(tile, box=(slot_x_px, slot_y_px))
def parseArgs():
parser = argparse.ArgumentParser()
parser.add_argument("--texture_path", type=str, help="Path to save the generated texture.")
args = parser.parse_args()
if not args.texture_path:
args.texture_path = "img_texture.png"
return args
if __name__ == "__main__":
args = parseArgs()
tex = openTexture(args.texture_path)
for i in range(0, len(IMG_TEX_DATA)):
filename = IMG_TEX_DATA[i][0]
x = i % IMG_PER_ROW
y = int(floor(i / IMG_PER_ROW))
addImageToTexture(tex, filename, x, y)
tex.save(args.texture_path)
|