init
This commit is contained in:
commit
9809bb55e5
6 changed files with 305 additions and 0 deletions
33
mcdraw.py
Normal file
33
mcdraw.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
from PIL import ImageFont, Image, ImageDraw
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype("wqy-zenhei.ttc", 24, 1)
|
||||||
|
emfont = ImageFont.truetype("NotoEmoji-Regular.ttf", 24, 0)
|
||||||
|
except OSError:
|
||||||
|
print("Please download these fonts to the current dir:\n"
|
||||||
|
"wqy-zenhei.ttc\n\tfrom https://downloads.sourceforge.net/project/wqy/wqy-zenhei/0.9.45%20%28Fighting-state%20RC1%29/wqy-zenhei-0.9.45.tar.gz"
|
||||||
|
"\n"
|
||||||
|
"NotoEmoji-Regular.ttf\n\tfrom https://github.com/googlefonts/noto-emoji/raw/2f1ffdd6fbbd05d6f382138a3d3adcd89c5ce800/fonts/NotoEmoji-Regular.ttf"
|
||||||
|
"\n\n"
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def text_to_im(text="紧密团结在鱼塔同志周围"):
|
||||||
|
emoji = re.compile("^[" u"\U0001F600-\U0001F64F" u"\U0001F300-\U0001F5FF" u"\U0001F680-\U0001F6FF" u"\U0001F1E0-\U0001F1FF" "]$", flags=re.UNICODE)
|
||||||
|
brush_location = [0]
|
||||||
|
def draw_single_char(ch, draw=None):
|
||||||
|
m = emoji.match(ch)
|
||||||
|
myfont = emfont if m else font
|
||||||
|
width = myfont.getsize(ch)[0]
|
||||||
|
if draw:
|
||||||
|
draw.text((brush_location[0], -2 if m else 0), ch, fill="black", font=myfont, spacing=0)
|
||||||
|
brush_location[0] += width
|
||||||
|
return width
|
||||||
|
def max_height(text):
|
||||||
|
return max(*[font.getsize(ch)[1] for ch in text], *[emfont.getsize(ch)[1] for ch in text])
|
||||||
|
width, height = sum(draw_single_char(ch) for ch in text), max_height(text)
|
||||||
|
im = Image.new('1', (width, height), color="white")
|
||||||
|
draw = ImageDraw.Draw(im)
|
||||||
|
for ch in text:
|
||||||
|
draw_single_char(ch, draw)
|
||||||
|
return im
|
20
minecraft-concrete.gpl
Normal file
20
minecraft-concrete.gpl
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: minecraft-concrete
|
||||||
|
Columns: 0
|
||||||
|
#
|
||||||
|
208 214 215 white_concrete
|
||||||
|
226 98 0 orange_concrete
|
||||||
|
170 45 160 magenta_concrete
|
||||||
|
30 137 198 light_blue_concrete
|
||||||
|
242 176 13 yellow_concrete
|
||||||
|
96 171 19 lime_concrete
|
||||||
|
214 100 143 pink_concrete
|
||||||
|
51 55 59 gray_concrete
|
||||||
|
126 126 116 light_gray_concrete
|
||||||
|
15 121 138 cyan_concrete
|
||||||
|
101 26 158 purple_concrete
|
||||||
|
40 42 144 blue_concrete
|
||||||
|
97 59 27 brown_concrete
|
||||||
|
71 90 31 green_concrete
|
||||||
|
144 29 29 red_concrete
|
||||||
|
2 3 7 black_concrete
|
57
minecraft-fullblock.gpl
Normal file
57
minecraft-fullblock.gpl
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: minecraft-fullblock
|
||||||
|
Columns: 0
|
||||||
|
#
|
||||||
|
247 233 163 smooth_sandstone
|
||||||
|
199 199 199 mushroom_stem[east=true,west=true,north=true,south=true,up=true,down=true]
|
||||||
|
255 0 0 redstone_block
|
||||||
|
160 160 255 packed_ice
|
||||||
|
167 167 167 iron_block
|
||||||
|
0 124 0 oak_leaves[distance=7,persistent=true]
|
||||||
|
255 255 255 white_concrete
|
||||||
|
164 168 184 clay
|
||||||
|
151 109 77 dirt
|
||||||
|
112 112 112 stone
|
||||||
|
143 119 72 oak_planks
|
||||||
|
255 252 245 quartz_block
|
||||||
|
216 127 51 orange_concrete
|
||||||
|
178 76 216 magenta_concrete
|
||||||
|
102 153 216 light_blue_concrete
|
||||||
|
229 229 51 yellow_concrete
|
||||||
|
127 204 25 lime_concrete
|
||||||
|
242 127 165 pink_concrete
|
||||||
|
76 76 76 gray_concrete
|
||||||
|
153 153 153 light_gray_concrete
|
||||||
|
76 127 153 cyan_concrete
|
||||||
|
127 63 178 purple_concrete
|
||||||
|
51 76 178 blue_concrete
|
||||||
|
102 76 51 brown_concrete
|
||||||
|
102 127 51 green_concrete
|
||||||
|
153 51 51 red_concrete
|
||||||
|
25 25 25 black_concrete
|
||||||
|
250 238 77 gold_block
|
||||||
|
92 219 213 diamond_block
|
||||||
|
74 128 255 lapis_block
|
||||||
|
0 217 58 emerald_block
|
||||||
|
112 2 0 netherrack
|
||||||
|
209 177 161 white_terracotta
|
||||||
|
159 82 36 orange_terracotta
|
||||||
|
149 87 108 magenta_terracotta
|
||||||
|
112 108 138 light_blue_terracotta
|
||||||
|
186 133 36 yellow_terracotta
|
||||||
|
103 117 53 lime_terracotta
|
||||||
|
160 77 78 pink_terracotta
|
||||||
|
57 41 35 gray_terracotta
|
||||||
|
135 107 98 light_gray_terracotta
|
||||||
|
87 92 92 cyan_terracotta
|
||||||
|
122 73 88 purple_terracotta
|
||||||
|
76 62 92 blue_terracotta
|
||||||
|
76 50 35 brown_terracotta
|
||||||
|
76 82 42 green_terracotta
|
||||||
|
142 60 46 red_terracotta
|
||||||
|
37 22 16 black_terracotta
|
||||||
|
189 48 49 crimson_nylium
|
||||||
|
148 63 97 crimson_planks
|
||||||
|
22 126 134 warped_nylium
|
||||||
|
58 142 140 warped_planks
|
||||||
|
20 180 133 warped_wart_block
|
62
minecraft.gpl
Normal file
62
minecraft.gpl
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
GIMP Palette
|
||||||
|
Name: minecraft
|
||||||
|
Columns: 0
|
||||||
|
#
|
||||||
|
127 178 56 grass_block[snowy=false]
|
||||||
|
247 233 163 smooth_sandstone
|
||||||
|
199 199 199 mushroom_stem[east=true,west=true,north=true,south=true,up=true,down=true]
|
||||||
|
255 0 0 redstone_block
|
||||||
|
160 160 255 packed_ice
|
||||||
|
167 167 167 iron_block
|
||||||
|
0 124 0 oak_leaves[distance=7,persistent=true]
|
||||||
|
255 255 255 white_concrete
|
||||||
|
164 168 184 clay
|
||||||
|
151 109 77 dirt
|
||||||
|
112 112 112 stone
|
||||||
|
64 64 255 water[level=0]
|
||||||
|
143 119 72 oak_planks
|
||||||
|
255 252 245 quartz_block
|
||||||
|
216 127 51 orange_concrete
|
||||||
|
178 76 216 magenta_concrete
|
||||||
|
102 153 216 light_blue_concrete
|
||||||
|
229 229 51 yellow_concrete
|
||||||
|
127 204 25 lime_concrete
|
||||||
|
242 127 165 pink_concrete
|
||||||
|
76 76 76 gray_concrete
|
||||||
|
153 153 153 light_gray_concrete
|
||||||
|
76 127 153 cyan_concrete
|
||||||
|
127 63 178 purple_concrete
|
||||||
|
51 76 178 blue_concrete
|
||||||
|
102 76 51 brown_concrete
|
||||||
|
102 127 51 green_concrete
|
||||||
|
153 51 51 red_concrete
|
||||||
|
25 25 25 black_concrete
|
||||||
|
250 238 77 gold_block
|
||||||
|
92 219 213 diamond_block
|
||||||
|
74 128 255 lapis_block
|
||||||
|
0 217 58 emerald_block
|
||||||
|
129 86 49 podzol[snowy=false]
|
||||||
|
112 2 0 netherrack
|
||||||
|
209 177 161 white_terracotta
|
||||||
|
159 82 36 orange_terracotta
|
||||||
|
149 87 108 magenta_terracotta
|
||||||
|
112 108 138 light_blue_terracotta
|
||||||
|
186 133 36 yellow_terracotta
|
||||||
|
103 117 53 lime_terracotta
|
||||||
|
160 77 78 pink_terracotta
|
||||||
|
57 41 35 gray_terracotta
|
||||||
|
135 107 98 light_gray_terracotta
|
||||||
|
87 92 92 cyan_terracotta
|
||||||
|
122 73 88 purple_terracotta
|
||||||
|
76 62 92 blue_terracotta
|
||||||
|
76 50 35 brown_terracotta
|
||||||
|
76 82 42 green_terracotta
|
||||||
|
142 60 46 red_terracotta
|
||||||
|
37 22 16 black_terracotta
|
||||||
|
189 48 49 crimson_nylium
|
||||||
|
148 63 97 crimson_planks
|
||||||
|
92 25 29 crimson_hyphae[axis=y]
|
||||||
|
22 126 134 warped_nylium
|
||||||
|
58 142 140 warped_planks
|
||||||
|
86 44 62 warped_hyphae[axis=y]
|
||||||
|
20 180 133 warped_wart_block
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pillow==8.3.2
|
||||||
|
PyNBT==3.1.0
|
131
schemgen.py
Normal file
131
schemgen.py
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
from PIL import Image
|
||||||
|
from pathlib import Path
|
||||||
|
from itertools import zip_longest
|
||||||
|
import re
|
||||||
|
|
||||||
|
def read_palette(text):
|
||||||
|
palette = dict()
|
||||||
|
metadata = dict()
|
||||||
|
in_body = False
|
||||||
|
for line in text.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line == "GIMP Palette":
|
||||||
|
continue
|
||||||
|
if line == '#':
|
||||||
|
in_body = True
|
||||||
|
continue
|
||||||
|
if in_body:
|
||||||
|
*rgb, name = line.split()
|
||||||
|
r, g, b = [int(x) for x in rgb]
|
||||||
|
index = len(palette)
|
||||||
|
palette[f"{r:02x}{g:02x}{b:02x}"] = {"rgb": (r, g, b), "name": name if name.startswith("minecraft:") else f"minecraft:{name}", "index": index}
|
||||||
|
else:
|
||||||
|
k, *v = line.split(':')
|
||||||
|
k, v = k.strip(), ':'.join(v).strip()
|
||||||
|
metadata[k] = v
|
||||||
|
return {"metadata": metadata, "palette": palette}
|
||||||
|
|
||||||
|
def read_imtuple(impath, palette_path):
|
||||||
|
palette = read_palette(Path(palette_path).read_text())
|
||||||
|
im = Image.open(impath)
|
||||||
|
im = im.rotate(180)
|
||||||
|
im = im.convert('RGB')
|
||||||
|
used_color_hex = tuple(set(f"{r:02x}{g:02x}{b:02x}" for r, g, b in im.getdata()))
|
||||||
|
used_mc_palette = tuple(palette["palette"][h]["name"] for h in used_color_hex)
|
||||||
|
imdata = (used_color_hex.index(f"{r:02x}{g:02x}{b:02x}") for r, g, b in im.getdata())
|
||||||
|
#imtuple = tuple(zip_longest(*([iter(imdata)] * im.width), fillvalue=0))
|
||||||
|
#assert len(imtuple) == im.height
|
||||||
|
imtuple = imdata
|
||||||
|
return (used_mc_palette, imtuple, im.width, im.height)
|
||||||
|
|
||||||
|
def read_text(text):
|
||||||
|
from mcdraw import text_to_im
|
||||||
|
im = text_to_im(text)
|
||||||
|
used_mc_palette = ('minecraft:air', 'minecraft:stone')
|
||||||
|
imdata = (0 if i else 1 for i in im.getdata())
|
||||||
|
imtuple = imdata
|
||||||
|
return (used_mc_palette, imtuple, im.width, im.height)
|
||||||
|
|
||||||
|
import gzip
|
||||||
|
from pynbt import NBTFile, TAG_Int, TAG_Compound, TAG_Short, TAG_Byte_Array, TAG_List, TAG_Int_Array
|
||||||
|
from io import BytesIO
|
||||||
|
import struct
|
||||||
|
|
||||||
|
class VarInt:
|
||||||
|
MAX_BYTES = 5
|
||||||
|
def __init__(self, io, set_value=None):
|
||||||
|
self._io = io
|
||||||
|
if set_value:
|
||||||
|
self.setval(set_value)
|
||||||
|
def setval(self, value):
|
||||||
|
ret = bytes()
|
||||||
|
while True:
|
||||||
|
byte = value & 0x7F
|
||||||
|
value >>= 7
|
||||||
|
ret += struct.pack("B", byte | (0x80 if value > 0 else 0))
|
||||||
|
if value == 0:
|
||||||
|
break
|
||||||
|
if len(ret) > self.MAX_BYTES:
|
||||||
|
raise ValueError("Tried to write too long of a VarInt")
|
||||||
|
self._io.write(ret)
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
number = 0
|
||||||
|
bytes_encountered = 0
|
||||||
|
while True:
|
||||||
|
byte = self._io.read(1)
|
||||||
|
if len(byte) < 1:
|
||||||
|
raise EOFError("Unexpected end of message.")
|
||||||
|
byteord = ord(byte)
|
||||||
|
number |= (byteord & 0x7F) << 7 * bytes_encountered
|
||||||
|
if not byteord & 0x80:
|
||||||
|
break
|
||||||
|
|
||||||
|
bytes_encountered += 1
|
||||||
|
if bytes_encountered > self.MAX_BYTES:
|
||||||
|
raise ValueError("Tried to read too long of a VarInt")
|
||||||
|
return number
|
||||||
|
|
||||||
|
def assemble_nbtfile(used_mc_palette, imtuple, width, height):
|
||||||
|
blackdataio = BytesIO()
|
||||||
|
varint = VarInt(blackdataio)
|
||||||
|
for i in imtuple:
|
||||||
|
varint.setval(i)
|
||||||
|
nbtvalue = {
|
||||||
|
'Version': TAG_Int(2),
|
||||||
|
'PaletteMax': TAG_Int(len(used_mc_palette)),
|
||||||
|
'Palette': TAG_Compound(
|
||||||
|
{name: TAG_Int(i) for i, name in enumerate(used_mc_palette)}
|
||||||
|
),
|
||||||
|
'Metadata': TAG_Compound({
|
||||||
|
'WEOffsetX': TAG_Int(0),
|
||||||
|
'WEOffsetY': TAG_Int(0),
|
||||||
|
'WEOffsetZ': TAG_Int(0)
|
||||||
|
}),
|
||||||
|
'Width': TAG_Short(width),
|
||||||
|
'Height': TAG_Short(1),
|
||||||
|
'Length': TAG_Short(height),
|
||||||
|
'DataVersion': TAG_Int(2586),
|
||||||
|
'BlockData': TAG_Byte_Array(blackdataio.getvalue()),
|
||||||
|
'BlockEntities': TAG_List(TAG_Compound),
|
||||||
|
'Offset': TAG_Int_Array([0, 0, 0])
|
||||||
|
}
|
||||||
|
nbt = NBTFile(value=nbtvalue, name='Schematic')
|
||||||
|
return nbt
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser(description='schemgen')
|
||||||
|
parser.add_argument('-o', '--output', default='output.schem', help='output worldedit schema file')
|
||||||
|
parser.add_argument('-i', '--input', type=str, default="input.png", help='input image')
|
||||||
|
parser.add_argument('-t', '--text', type=str, default="", help='input text')
|
||||||
|
parser.add_argument('-p', '--palette', type=str, default="minecraft.gpl", help='gimp palette file')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.text:
|
||||||
|
nbt = assemble_nbtfile(*read_text(args.text))
|
||||||
|
else:
|
||||||
|
nbt = assemble_nbtfile(*read_imtuple(args.input, args.palette))
|
||||||
|
print(nbt.pretty())
|
||||||
|
with gzip.open(args.output, 'w') as f:
|
||||||
|
nbt.save(f)
|
Loading…
Reference in a new issue