general mindustry schematic tools
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# modified from ado1928/pix2msch

try:
    import struct, zlib, os, base64
    from PIL import Image
except Exception as e:
    print("You're missing a package!")
    print()
    print(e)
    input()
    
colorarray = [
    217, 157, 115,
    140, 127, 169,
    235, 238, 245,
    178, 198, 210,
    247, 203, 164,
    39, 39, 39,
    141, 161, 227,
    249, 163, 199,
    119, 119, 119,
    83, 86, 92,
    203,217, 127,
    244,186, 110,
    243, 233, 121,
    116, 87, 206,
    255, 121, 94,
    255, 170, 95
    ]

#convert array of ints into a list of tuples, then into a palette
tuple_array = [tuple(colorarray[t*3:t*3+3]) for t in range(len(colorarray)//3)]
palette = Image.new("P", (16, 16))
palette.putpalette(colorarray*16)
palette.load()

def quantize(img, dither, transparency_treshold):
    #invalid input checking
    img = Image.open(img)
    transparency_treshold = int(transparency_treshold)
    
    #sphagetti
    img = img.convert("RGBA") # image 
    imgq = img.convert("RGB") # fully opaque image
    imgq = imgq._new(imgq.im.convert("P", 1 if dither else 0, palette.im)) #where the actual quantization happens

    imgA = Image.new("RGBA", img.size)
    pixels = imgA.load()
    imgq = imgq.convert("RGB")
    
    for y in range(img.size[1]):
        for x in range(img.size[0]):
            if img.getpixel((x, y))[3] >= transparency_treshold: #transparency treshold
                pixels[x, y] = imgq.getpixel((x, y))
            else:
                pixels[x, y] = (0, 0, 0, 0)

    # print("Quantization complete")

    return imgA


# imgfile - Path to the image
# name - Name of the schematic
# save_location - Save location, i guess
# dither - Whether to use dithering (True or False, 1 or 0)
# transparency_treshold - Below which alpha level to stop displaying (0-255), where 0 is show everything and 255 is show only fully opaque
# mode - Either "path" or "clipboard". Whether to save the schematic as .msch or to copy it into clipboard

def pix2msch(imgfile               = None,
             name                  = "schematic",
             save_location         = None,
             dither                = True,
             transparency_treshold = 127,
             mode                  = "path"
             ): #sad face
    
    tiles = []
    #input checking
    if mode == "path" and not(os.path.isdir(os.path.expandvars(save_location))):
        print("not a path")
        exit()
        
    img = quantize(imgfile, dither, transparency_treshold)
    
    img = img.rotate(-90, expand=True)
    
    width, height = img.size
    for y in range(height):
        for x in range(width):
            if img.getpixel((x, y))[3] > 1:
                tiles.append((x, y, tuple_array.index(img.getpixel((x, y))[0:3])))

    # print("Converted pixels into an array of tiles")

    class ByteBuffer(): #so desparate i had to write my own byte buffer
        def __init__(self, data=bytearray()):
            self.data = data
            
        def writeShort(self, int):
            self.data += struct.pack(">H", int)

        def writeUTF(self, str):
            self.writeShort(len(str))
            self.data += bytes(str.encode("UTF"))
            
        def writeByte(self, int):
            self.data += struct.pack("b", int)
            
        def writeInt(self, int):
            self.data += struct.pack(">i", int)
            
    #write header and all of that stuff
    data = ByteBuffer()

    data.writeShort(height)
    data.writeShort(width)

    data.writeByte(1)

    data.writeUTF("name")
    data.writeUTF(name)

    data.writeByte(1)

    data.writeUTF("sorter")
    data.writeInt(len(tiles))

    # print("Header written")

    for tile in tiles: #write tiles
        data.writeByte(0)
        data.writeShort(tile[1])
        data.writeShort(tile[0])
        data.writeInt(tile[2])
        data.writeByte(0)

    # print("Tile data written")
    
    
    if mode == "path":
        os.chdir(os.path.expandvars(save_location))
        file = open(name + ".msch", "wb")
        file.write(b"msch\x00"+zlib.compress(data.data))
        file.close()

        # print("Successfully saved {0} ".format(name + ".msch"))
        
    else:
        try:
            import pyperclip
        except ImportError:
            print("To use this feature, you need to have the pyperclip module")
            exit()
        else:
            pyperclip.copy(base64.standard_b64encode(b"msch\x00"+zlib.compress(data.data)).decode())
            print("Schematic converted to base64, and put into clipboard")