# coding: utf-8 """ Converts pixel-art images into cross-stitch patterns. This tool assumes that 1px = 1 stitch. TODO: * Accept image name from command line. (DONE) * Change characters to symbols for ease of reading. * Expand number of symbols. * Create image from symbolized pixels instead of just printing to screen. (DONE) * Add grid lines and edge labels to image. (DONE) * Add legend to image, based on the `symbols` dictionary. (DONE) * Correspond hex colors to floss colors, where possible. * (Maybe) add stitch count for each color. (DONE) * (Maybe) add GUI. (DONE) * Make sure legend width doesn't exceed image width. """ __author__ = "Noƫlle Anthony" __version__ = "0.4.0" import sys from PIL import Image, ImageDraw from collections import defaultdict from gooey import Gooey, GooeyParser def create_stitch(img_name, img_out, display): img = Image.open(img_name) #oimg_name_bits = img_name.split(".") #oimg_name = "".join(oimg_name_bits[:-1]) + "_pattern." + oimg_name_bits[-1] oimg_name = img_out w,h = img.size symbols = defaultdict(str) symbols["transparent"] = " " characters = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" symbol_counts = defaultdict(int) # l = 0 lines = [] for i in range(h): line = [] # k = 0 for j in range(w): c = "".join(["{}{}".format(hex(x//16).split('x')[-1], hex(x%16).split('x')[-1]) for x in list(img.getpixel((j,i)))]) d = " " if c[-2:] == "ff": cs = c[:-2] if j == 0 and i == 0: symbols[cs] = " " elif cs not in symbols.keys(): symbols[cs] = characters[0] characters = characters[1:] symbol_counts[cs] += 1 d = symbols[cs] line.append(d) # print(d, end="") # k += 1 # if k == 9: # print("|", end="") # k = 0 lines.append(line) # print() # l += 1 # if l == 9: # for ww in range(int(w*1.1)+1): # if (ww+1)%10 == 0: # print("+", end="") # else: # print("-", end="") # l = 0 # print() # print("\nLEGEND") legend = [] keys = 0 for k,v in symbols.items(): if v != " ": keys += 1 legend.append("{}: #{} ({}ct)".format(v, k, symbol_counts[k])) print("{} keys".format(keys)) # print("\n".join(legend)) owid, ohgt = (w*10)+10, (h*10)+20+(15*(int(keys/3)+1)) print((owid, ohgt)) oimg = Image.new("RGB", (owid, ohgt), "white") draw = ImageDraw.Draw(oimg) woff, hoff = int(((w)%10)/2)+1, int(((h)%10)/2)+1 for ww in range(1, w+1): posx = ww * 10 linecolor = 0 if (posx-(woff*10)) % 100 == 0 else (128,128,128) linewidth = 2 if (posx-(woff*10)) % 100 == 0 else 1 draw.line((posx, 10, posx, ((h+1)*10)), fill=linecolor, width=linewidth) for hh in range(1, h+2): posy = hh * 10 linecolor = 0 if (posy-(hoff*10)) % 100 == 0 else (128,128,128) linewidth = 2 if (posy-(hoff*10)) % 100 == 0 else 1 draw.line((10, posy, owid, posy), fill=linecolor, width=linewidth) char_positions = [x*10+4 for x in range(1,max(h,w)+1)] # print(char_positions) #char_colors = {" ": (0,0,0), "A": (0,0,0), "B": (128,0,0), "C": (0,128,0), "D": (0,255,255), "E": (128,128,0), "F": (128,0,128), "G": (0,0,0)} adjust = 0 for line in lines: for char in range(len(line)): # print(char_positions[char]) # print(line[char]) try: draw.text((char_positions[char], char_positions[0]-4+adjust), line[char], fill=0) except: pass adjust += 10 legend_out = "" item_ct = 0 for item in legend: item_ct += 1 legend_out += item if item_ct % 3 == 0: legend_out += "\n" else: legend_out += " " draw.text((20, (h*10)+20), legend_out, fill=0) oimg.save(oimg_name) print("Saved {}".format(oimg_name)) if display: oimg.show() @Gooey def main(): parser = GooeyParser() parser.add_argument("img_name", help="The image file you want to convert", widget="FileChooser") parser.add_argument("img_out", help="The name of the output pattern", widget="FileSaver") parser.add_argument("--display", help="Display the image after creation", action="store_true") args = parser.parse_args() create_stitch(args.img_name, args.img_out, args.display) if __name__ == "__main__": main()