0<0# : ^
'''
@echo off
set script=%~f0
python -x "%script%" %*
exit /b 0
'''
import tkinter as tk
from tkinter import filedialog, font
from PIL import Image as PILImage, ImageDraw, ImageFont, ImageTk
from PIL import Image
import time
import os
try:
from PIL import Image as PILImage, ImageFont, ImageTk, ImageGrab
pillow_available = True
except ImportError:
pillow_available = False
if pillow_available:
print("Pillow library is available.")
else:
install_pillow = messagebox.askyesno(
"Pillow Not Installed",
"Pillow library is required for this application. Do you want to install it?"
)
if install_pillow:
try:
import subprocess
subprocess.run(["pip", "install", "Pillow"], check=True)
from PIL import Image, ImageDraw, ImageFont, ImageTk, ImageGrab
pillow_available = True
print("Pillow library installed successfully.")
except Exception as install_error:
messagebox.showerror(
"Installation Error",
f"Error installing Pillow: {install_error}\nPlease install Pillow manually using 'pip install Pillow'."
)
exit(1)
else:
exit(1)
class FontEditorApp:
def __init__(self, root):
self.root = root
self.root.title("Font Editor")
self.generated_font_canvas = tk.Canvas(self.root, width=600, height=600, borderwidth=0, highlightthickness=0)
self.generated_font_canvas.pack(side=tk.RIGHT, padx=10)
self.font_path = tk.StringVar()
self.font_size_x = tk.IntVar(value=30)
self.scaling = tk.DoubleVar(value=100.0)
scaling_factor = self.scaling.get() / 100.0
self.font_shift_y = tk.IntVar(value=0)
self.font_shift_x = tk.IntVar(value=0)
self.extra_scaling = tk.DoubleVar(value=100.0)
self.extra_shift_y = tk.IntVar(value=0)
self.empty_cell_color = tk.StringVar(value="50,0,0")
self.font_color = tk.StringVar(value="255,150,0")
self.font_symbol = tk.StringVar(value="A")
self.skip_symbols = tk.StringVar(value="") # Add skip_symbols attribute
self.skip_symbols = tk.StringVar(value="@[]()")
self.zoomed_canvas = tk.Canvas(self.root, width=4 * self.font_size_x.get(), height=4 * self.font_size_x.get(), borderwidth=0, highlightthickness=0)
self.zoomed_canvas.pack(side=tk.TOP, padx=10, pady=10)
self.result_img_rgb = None
self.auto_apply_changes_on_startup = False
self.load_default_font()
self.create_widgets()
self.load_default_font()
def create_widgets(self):
choose_font_button = tk.Button(self.root, text="CHOOSE TRUETYPE FONT", command=self.choose_font, font=("Arial", 14, "bold"), fg="red")
choose_font_button.pack(pady=10)
font_size_x_label = tk.Label(self.root, text="Font Size (X):", font=("Arial", 10, "bold"), fg="blue")
font_size_x_label.pack()
font_size_x_entry = tk.Entry(self.root, textvariable=self.font_size_x, font=("Arial", 10, "bold"), fg="red")
font_size_x_entry.pack()
scaling_label = tk.Label(self.root, text="Scaling Percentage:", font=("Arial", 10, "bold"), fg="blue")
scaling_label.pack()
scaling_entry = tk.Entry(self.root, textvariable=self.scaling, font=("Arial", 10, "bold"), fg="red")
scaling_entry.pack()
scaling_entry.bind('<KeyRelease>', lambda event: self.generate_full_image())
font_shift_x_label = tk.Label(self.root, text="Font Shift (X):", font=("Arial", 10, "bold"), fg="blue")
font_shift_x_label.pack()
font_shift_x_entry = tk.Entry(self.root, textvariable=self.font_shift_x, font=("Arial", 10, "bold"), fg="red")
font_shift_x_entry.pack()
font_shift_y_label = tk.Label(self.root, text="Font Shift (Y):", font=("Arial", 10, "bold"), fg="blue")
font_shift_y_label.pack()
font_shift_y_entry = tk.Entry(self.root, textvariable=self.font_shift_y, font=("Arial", 10, "bold"), fg="red")
font_shift_y_entry.pack()
empty_cell_color_label = tk.Label(self.root, text="Background Color (RGB):", font=("Arial", 10, "bold"), fg="blue")
empty_cell_color_label.pack()
empty_cell_color_entry = tk.Entry(self.root, textvariable=self.empty_cell_color, font=("Arial", 10, "bold"), fg="red")
empty_cell_color_entry.pack()
font_color_label = tk.Label(self.root, text="Font Color (RGB):", font=("Arial", 10, "bold"), fg="blue")
font_color_label.pack()
font_color_entry = tk.Entry(self.root, textvariable=self.font_color, font=("Arial", 10, "bold"), fg="red")
font_color_entry.pack()
skip_symbols_label = tk.Label(self.root, text="Skip Symbols:", font=("Arial", 10, "bold"), fg="blue")
skip_symbols_label.pack()
skip_symbols_entry = tk.Entry(self.root, textvariable=self.skip_symbols, font=("Arial", 10, "bold"), fg="red")
skip_symbols_entry.pack()
apply_button = tk.Button(self.root, text="GENERATE", command=self.generate_full_image, font=("Arial", 14, "bold"), fg="red")
apply_button.pack(pady=10)
save_button = tk.Button(self.root, text="SAVE FONT", command=lambda: self.generate_full_image(save=True), font=("Arial", 14, "bold"), fg="red")
save_button.pack(pady=10)
for entry_widget in [font_size_x_entry, scaling_entry, font_shift_y_entry,
empty_cell_color_entry, font_color_entry, skip_symbols_entry]:
entry_widget.bind('<KeyRelease>', self.on_entry_key_release)
self.root.bind_all("<MouseWheel>", self.on_mousewheel)
def on_entry_key_release(self, event):
self.generate_full_image()
def on_mousewheel(self, event):
focused_widget = self.root.focus_get()
self.root.after(500, self.generate_full_image)
if hasattr(self, 'result_img_rgb') and self.result_img_rgb:
self.display_zoomed_view(self.result_img_rgb)
if isinstance(focused_widget, tk.Entry):
if focused_widget.cget('textvariable') in [self.empty_cell_color, self.font_color]:
current_value = focused_widget.get()
rgb_values = [int(val) for val in current_value.split(',')]
increment = 1
for i in range(3):
rgb_values[i] = max(0, min(rgb_values[i] + increment if event.delta > 0 else rgb_values[i] - increment, 255))
new_value = ','.join(map(str, rgb_values))
else:
try:
current_value = float(focused_widget.get())
increment = 1
new_value = current_value + increment if event.delta > 0 else current_value - increment
focused_widget.delete(0, tk.END)
focused_widget.insert(0, str(new_value))
except ValueError:
pass
focused_widget.focus_set()
def choose_font(self):
font_path = filedialog.askopenfilename(filetypes=[("Font files", "*.ttf;*.otf")])
if font_path:
self.font_path.set(font_path)
self.display_temporary_message(f"FONT: {os.path.basename(font_path)}", duration=2000)
self.generate_full_image()
self.display_zoomed_view(self.result_img_rgb)
def load_default_font(self):
script_folder = os.path.dirname(os.path.abspath(__file__))
files = os.listdir(script_folder)
font_files = [f for f in files if f.lower().endswith(('.ttf', '.otf'))]
if font_files:
default_font_path = os.path.join(script_folder, font_files[0])
self.font_path.set(default_font_path)
print(f"Default font loaded: {default_font_path}")
self.display_temporary_message(f"FONT: {default_font_path}", duration=2000)
self.generate_full_image()
self.display_zoomed_view(self.result_img_rgb)
if not self.auto_apply_changes_on_startup:
return
self.apply_changes()
else:
print("No TrueType font found in the script's folder. Please choose a font.")
def display_temporary_message(self, message, duration):
existing_label = getattr(self, '_temp_label', None)
if existing_label:
existing_label.destroy()
temp_label = tk.Label(self.root, text=message, font=("Arial", 20, "bold"), fg="red")
temp_label.pack()
self.root.after(duration, temp_label.destroy)
self._temp_label = temp_label
def apply_changes(self):
self.generated_font_canvas.delete("all")
font_shift_x_value = self.font_shift_x.get()
empty_cell_rgb = tuple(map(int, self.empty_cell_color.get().split(',')))
font_color_rgb = tuple(map(int, self.font_color.get().split(',')))
font_size = self.font_size_x.get()
try:
font_path = self.font_path.get()
fnt = ImageFont.truetype(font_path, font_size)
img = Image.new("RGBA", (font_size, font_size), empty_cell_rgb + (0,))
draw = ImageDraw.Draw(img)
draw.text((0, 0), text=self.font_symbol.get(), font=fnt, fill=font_color_rgb)
self.generate_full_image()
except OSError as e:
print(f"Error loading font: {e}")
def generate_full_image(self, save=False):
self.generated_font_canvas.delete("all")
if self.scaling.get() == 0 or self.font_size_x.get() == 0:
return
pattern = [
"0123456789ABCDEF",
"0123456789ABCDEF",
" !\"#$%&´()*+,-./",
"0123456789:;{=?",
"@ABCDEFGHIJKLMNO",
"PQRSTUVWXYZ[\\]^_",
"`abcdefghijklmno",
"pqrstuvwxyz ",
" ",
" ",
" ",
" EMPTY ",
" ",
" ",
" ",
" ",
]
empty_cell_rgb = tuple(map(int, self.empty_cell_color.get().split(',')))
font_color_rgb = tuple(map(int, self.font_color.get().split(',')))
font_size = self.font_size_x.get()
scaling_factor = self.scaling.get() / 100.0
font_shift_y_value = self.font_shift_y.get()
font_shift_x_value = self.font_shift_x.get()
symbol_size = int(font_size * scaling_factor)
font_path = self.font_path.get()
full_img = Image.new("RGBA", (len(pattern[0]) * font_size, len(pattern) * font_size), (0, 0, 0, 0))
skip_symbols = set(self.skip_symbols.get()) # Get skip symbols
for row, line in enumerate(pattern):
max_height_in_row = 0 # Track the maximum height in the current row
for col, char in enumerate(line):
if char in skip_symbols:
continue # Skip rendering the specified symbol
additional_space = symbol_size // 2
img = Image.new("RGBA", (symbol_size, symbol_size + 2 * additional_space), (255, 255, 255, 0))
char_draw = ImageDraw.Draw(img)
fnt = ImageFont.truetype(font_path, symbol_size)
char_draw.text((0, additional_space), text=char, font=fnt, fill=font_color_rgb)
bbox = img.getbbox()
center_x = col * font_size + font_size / 2
center_y = row * font_size + font_size / 2
paste_x = int(col * font_size + font_shift_x_value)
paste_y = int(center_y - max_height_in_row / 2 - font_size / 1.5 - additional_space + font_shift_y_value)
full_img.paste(img, (paste_x, paste_y), img)
grid_color = (255, 255, 255, 255)
grid_size_x = len(pattern[0])
grid_size_y = len(pattern)
cell_size = font_size
result_img_rgb = full_img.convert("RGBA")
draw = ImageDraw.Draw(result_img_rgb)
for x in range(0, grid_size_x * cell_size, cell_size):
draw.line([(x, 0), (x, grid_size_y * cell_size)], fill=grid_color, width=1)
for y in range(0, grid_size_y * cell_size, cell_size):
draw.line([(0, y), (grid_size_x * cell_size, y)], fill=grid_color, width=1)
black_img = Image.new("RGBA", full_img.size, empty_cell_rgb + (255,))
result_img = Image.alpha_composite(black_img, result_img_rgb)
result_img_rgb = result_img.convert("RGB")
full_image_tk = ImageTk.PhotoImage(result_img_rgb)
self.generated_font_canvas.image = full_image_tk
self.generated_font_canvas.create_image(0, 0, anchor=tk.NW, image=full_image_tk)
self.result_img_rgb = result_img_rgb
if save:
current_time = time.strftime("%Y%m%d%H%M%S")
file_name = f"font_{current_time}.png"
result_img_rgb = result_img_rgb.convert("RGBA")
black_img = Image.new("RGBA", full_img.size, empty_cell_rgb + (255,))
full_img_with_alpha = Image.alpha_composite(black_img, full_img.convert("RGBA"))
full_img_with_alpha.convert("RGB").save(file_name)
print(f"Image saved as: {file_name}")
message = tk.Label(self.root, text=f"SAVED: {file_name}", font=("Arial", 14, "bold"), fg="red")
message.pack(pady=10)
self.root.after(2000, message.destroy)
def display_zoomed_view(self, full_img_rgb):
crop_x = 2 * self.font_size_x.get()
crop_y = 2 * self.font_size_x.get()
cropped_img = full_img_rgb.crop((0, 2, crop_x, crop_y))
zoomed_img = cropped_img.resize((2 * crop_x, 2 * crop_y), Image.NEAREST)
zoomed_img_tk = ImageTk.PhotoImage(zoomed_img)
self.zoomed_canvas.image = zoomed_img_tk
self.zoomed_canvas.create_image(0, 0, anchor=tk.NW, image=zoomed_img_tk)
if __name__ == "__main__":
root = tk.Tk()
app = FontEditorApp(root)
root.mainloop()