from tkinter import * from tkinter import filedialog from tkinter import ttk import struct class CanvasDot: def __init__(self, canvas, origin, fill): #self.size = tuple(map(lambda x : x[0] + x[1], zip(origin, (0,0,50,50)))) self.size = origin self.fill = fill self.outline = "#000000" self.canvas = canvas self.object = canvas.create_rectangle(self.size, fill=self.fill, outline=self.outline) canvas.tag_bind(self.object, '', self.changeColor) canvas.tag_bind(self.object, '', self.update_position) def changeColor(self, _): global currentColor, spriteDots, colors spriteDots[self.object - 1] = colors.index(currentColor) self.fill = currentColor self.canvas.itemconfig(self.object, fill=self.fill) def update_position(self, _): global position position.config(text="{}, {}".format(self.size[0]//20, self.size[1]//20)) def __exit__(self): self.canvas.delete(self.object) class PalleteColor: def __init__(self, canvas, origin, fill): self.size = tuple(map(lambda x : x[0] + x[1], zip(origin, (0,0,41,41)))) self.fill = fill self.outline = "#000000" self.canvas = canvas self.object = canvas.create_rectangle(self.size, fill=self.fill, outline=self.outline) canvas.tag_bind(self.object, '', self.changeColor) def changeColor(self, _): global currentColor currentColor = self.fill def spriteToBytes(spriteDots): global canvasSize result = bytearray() even = [] odd = [] for i, x in enumerate(spriteDots): if (i // canvasSize[0]) % 2: odd.append(x) else: even.append(x) for i in range(0, len(even), 4): result += ((even[i]<<6) + (even[i + 1]<<4) + (even[i + 2]<<2) + even[i + 3]).to_bytes() for i in range(0, len(odd), 4): result += ((odd[i]<<6) + (odd[i + 1]<<4) + (odd[i + 2]<<2) + odd[i + 3]).to_bytes() return result def bytesToSprite(spriteBytes): global canvasSize result = [] even = [] odd = [] for i in range(0, len(spriteBytes) // 2): even.append((spriteBytes[i]) >> 6) even.append((spriteBytes[i] >> 4) % 4) even.append((spriteBytes[i] >> 2) % 4) even.append((spriteBytes[i]) % 4) for i in range(len(spriteBytes) // 2, len(spriteBytes)): odd.append((spriteBytes[i]) >> 6) odd.append((spriteBytes[i] >> 4) % 4) odd.append((spriteBytes[i] >> 2) % 4) odd.append((spriteBytes[i]) % 4) for i in range(0, len(even) * 2): if (i // canvasSize[0]) % 2: result.append(odd[(i % canvasSize[0]) + ((i // canvasSize[0]) // 2)*canvasSize[0]]) else: result.append(even[(i % canvasSize[0]) + ((i // canvasSize[0]) // 2)*canvasSize[0]]) return result def newSprite(): global dots, canvasSize, canvas, colors, palette, paletteColors dots.clear() spriteDots = [len(colors) - 1 for _ in range(canvasSize[0] * canvasSize[1])] canvas.destroy() palette.destroy() canvas = Canvas(bg="white", width=canvasSize[0] * 20 - 1, height=20 * canvasSize[1] - 1) for i in range(canvasSize[1]): for j in range(canvasSize[0]): dots.append(CanvasDot(canvas, (20 * j, 20 * i, 20 * j + 20, 20 * i + 20), colors[3])) paletteColors = [] palette = Canvas(master=root, bg="white", width=40, height=40 * len(colors)) for i, color in enumerate(colors): paletteColors.append(PalleteColor(palette, (0, 40 * i, 0, 40 * i + 1), color)) canvas.pack(side=LEFT, expand=1) palette.pack(side=LEFT, expand=0) def loadSprite(): with open(filedialog.askopenfilename(), "rb") as file: spriteBytes = file.read() global dots, canvasSize, canvas, colors, palette, paletteColors, spriteDots spriteDots = bytesToSprite(spriteBytes) dots.clear() canvas.destroy() palette.destroy() canvas = Canvas(bg="white", width=canvasSize[0] * 20 - 1, height=20 * canvasSize[1] - 1) for i in range(canvasSize[1]): for j in range(canvasSize[0]): dots.append(CanvasDot(canvas, (20 * j, 20 * i, 20 * j + 20, 20 * i + 20), colors[spriteDots[i * canvasSize[0] + j]])) paletteColors = [] palette = Canvas(master=root, bg="white", width=40, height=40 * len(colors)) for i, color in enumerate(colors): paletteColors.append(PalleteColor(palette, (0, 40 * i, 0, 40 * i + 1), color)) canvas.pack(side=LEFT, expand=1) palette.pack(side=LEFT, expand=0) def saveSprite(): global spriteDots with open(filedialog.asksaveasfilename(), "wb") as file: file.write(spriteToBytes(spriteDots)) root = Tk() root.title("CGA Spriter") root.geometry("800x800") ttk.Style().theme_use("classic") file_menu = Menu() file_menu.add_command(label="New", command=newSprite) file_menu.add_command(label="Save", command=saveSprite) file_menu.add_command(label="Open", command=loadSprite) file_menu.add_separator() file_menu.add_command(label="Exit", command=exit) main_menu = Menu() main_menu.add_cascade(label="File", menu=file_menu) main_menu.add_cascade(label="About") toolsframe = ttk.Frame(borderwidth=1,relief=SOLID, padding=[8,10]) toolsframe.pack(fill=X) canvasSize = (32, 64) canvas = Canvas(bg="white", width=canvasSize[0] * 20 - 1, height=20 * canvasSize[1] - 1) canvas.pack(side=LEFT, expand=1) colors = ["#000000", "#55FFFF", "#FF55FF", "#FFFFFF"] currentColor = colors[1] paletteColors = [] palette = Canvas(master=root, bg="white", width=40, height=40 * len(colors)) for i, color in enumerate(colors): paletteColors.append(PalleteColor(palette, (0, 40 * i, 0, 40 * i + 1), color)) palette.pack(side=LEFT, expand=0) dots = [] spriteDots = [len(colors) - 1 for _ in range(canvasSize[0] * canvasSize[1])] for i in range(canvasSize[1]): for j in range(canvasSize[0]): dots.append(CanvasDot(canvas, (20 * j, 20 * i, 20 * j + 20, 20 * i + 20), colors[3])) position = Label(toolsframe, text='0, 0') position.pack(expand=1) position.pack_propagate(0) root.config(menu=main_menu) root.mainloop()