I have written a GUI program which takes a black and white image, converts it into 2 character ASCII art and counts the sections of characters in each row. It's really hard to explain so I'll paste the code below so you can see what it does.
The program is for my wife, to help her do some sort of knitting technique, it saves her from writing it down.
I want to make a button on the second window which, when clicked, highlights a certain amount of characters from a single line in the Multiline element (e.g. the first row of '.'s in the line get selected, then the first row of '#'s, then the next row or '.' etc).
I'm using PySimpleGUI and I've looked through all the documentation I could find, I've tried Google but I cant seem to find what I want, or work it out. I don't mind if the text if selected or highlighted a different colour.
Here is my code:
import PIL.Image
import os
from itertools import groupby
import PySimpleGUI as sg
import time
def main_window():
#Set theme and layout
sg.theme('reddit')
layout = [
[sg.Text("This program is designed to turn a black and white image into a double-knit template")],
[sg.Text("If your image doesn't display as desired, adjusting the contrast might help.")],
[sg.Text("Enter file name + extention (eg. 'image.jpg')"), sg.InputText(size=(50),key='pic')],
[sg.Text("Enter the size you'd like in # of stitches"), sg.Text("Width: "), sg.InputText(size=(10),key='wth'), sg.Text("Length: "), sg.InputText(size=(10),key='lth')],
[sg.Text("Contrast"), sg.Slider(range=(1,11), default_value=6, orientation='h', key='sli')],
[sg.Button('Generate')],
[sg.ProgressBar(50, orientation='h', border_width=4, key='pbar')]
]
window = sg.Window('Knitify', layout)
#Contrast variables
chars1 = ["#", ".", ".", ".", ".", ".", ".", ".", ".", ".", "."]
chars2 = ["#", "#", ".", ".", ".", ".", ".", ".", ".", ".", "."]
chars3 = ["#", "#", "#", ".", ".", ".", ".", ".", ".", ".", "."]
chars4 = ["#", "#", "#", "#", ".", ".", ".", ".", ".", ".", "."]
chars5 = ["#", "#", "#", "#", "#", ".", ".", ".", ".", ".", "."]
chars6 = ["#", "#", "#", "#", "#", "#", ".", ".", ".", ".", "."]
chars7 = ["#", "#", "#", "#", "#", "#", "#", ".", ".", ".", "."]
chars8 = ["#", "#", "#", "#", "#", "#", "#", "#", ".", ".", "."]
chars9 = ["#", "#", "#", "#", "#", "#", "#", "#", "#", ".", "."]
chars10 = ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "."]
chars11 = ["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]
while True:
event, values = window.read()
print(event, values)
#Get contrast slider value
i = int(values['sli'])
#Get Image file
p = str(values['pic'])
#Grab contrast level
if i == 1:
con = chars1
elif i ==2:
con = chars2
elif i ==3:
con = chars3
elif i ==4:
con = chars4
elif i ==5:
con = chars5
elif i ==6:
con = chars6
elif i ==7:
con = chars7
elif i ==8:
con = chars8
elif i ==9:
con = chars9
elif i ==10:
con = chars10
elif i ==11:
con = chars11
if event == sg.WIN_CLOSED:
break
if event == 'Generate':
#Check if given image file exists, if not, do nothing, wait for valid image.
if os.path.exists(p):
#Check if output file already exists, if it does, delete and replace with newly generated image.
if os.path.exists('convertedImage.txt'):
os.remove('convertedImage.txt')
#Open and prepare image with Pillow
path = values['pic']
img = PIL.Image.open(path)
width, height = img.size
aspect_ratio = height/width
#Get user to enter desired width and height (in stitches) of output image
new_width = int(values['wth'])
new_height = int(values['lth'])
#If values are impossible to deal with then terminate and wait for correct values
if new_width <= 0:
break
if new_height <= 0:
break
#Resize and convert image to ASCII
img = img.resize((int(new_width), int(new_height)))
img = img.convert('L')
pixels = img.getdata()
new_pixels = [con[pixel//25] for pixel in pixels]
new_pixels = ''.join(new_pixels)
new_pixels_count = len(new_pixels)
ascii_image = [new_pixels[index:index + new_width] for index in range(0, new_pixels_count, new_width)]
ascii_image = "\n".join(ascii_image)
#Save ASCII image to temp file
with open('testout.txt', 'w') as f:
f.write(ascii_image)
f.close()
#Use temp file to scan each line and number alternating stitches in each row
with open('testout.txt', 'r') as f:
for line in map(lambda l: l.strip(), f):
runs = [sum(1 for _ in g) for _, g in groupby(line)]
x = f"{line} {' '.join(map(str, runs))}"
#Write result to new file
with open("convertedImage.txt", 'a') as n:
n.write("\n" + x)
n.close()
f.close()
#Remove temp file
os.remove('testout.txt')
#Progress bar bit
bar = 1
for i in range(8):
window['pbar'].update_bar(bar)
bar = bar+bar
time.sleep(0.2)
#Open second window
output_window()
window['pbar'].update_bar(0)
window.close()
def output_window():
#Read contents of converted image
with open('convertedImage.txt', 'r') as f:
contents = f.read()
f.close()
#Find the length of the longest line and set multiline box to that width.
#Paste the contents of convertedImage to multiline box
long = max(open('convertedImage.txt'), key=len)
layout = [
[sg.Multiline(size=(len(long),50), font='Consolas', default_text=contents)]
]
window = sg.Window("Knitified", layout, modal=True)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
main_window()