|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- # 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()
|