Luminous Weaver Python GUI

👤 Sharing: AI
import tkinter as tk
from tkinter import ttk, colorchooser, filedialog
from PIL import Image, ImageDraw, ImageTk
import random

class ImageEditor:
    def __init__(self, master):
        self.master = master
        master.title("Luminous Weaver: Creative Image Editor")

        self.image = None
        self.image_tk = None
        self.draw = None
        self.filename = None

        # --- UI Elements ---
        self.canvas_width = 600
        self.canvas_height = 400
        self.canvas = tk.Canvas(master, width=self.canvas_width, height=self.canvas_height, bg='white')
        self.canvas.pack(pady=10)

        self.toolbar = ttk.Frame(master)
        self.toolbar.pack(pady=5)

        # Open Button
        self.open_button = ttk.Button(self.toolbar, text="Open Image", command=self.open_image)
        self.open_button.grid(row=0, column=0, padx=5)

        # Save Button
        self.save_button = ttk.Button(self.toolbar, text="Save Image", command=self.save_image, state=tk.DISABLED)
        self.save_button.grid(row=0, column=1, padx=5)

        # Color Picker
        self.color_button = ttk.Button(self.toolbar, text="Choose Color", command=self.choose_color)
        self.color_button.grid(row=0, column=2, padx=5)
        self.current_color = 'black'

        # Brush Size
        self.brush_size_label = ttk.Label(self.toolbar, text="Brush Size:")
        self.brush_size_label.grid(row=0, column=3, padx=5)
        self.brush_size = tk.IntVar(value=5)
        self.brush_size_scale = tk.Scale(self.toolbar, from_=1, to=20, orient=tk.HORIZONTAL, variable=self.brush_size, command=self.update_brush_size, width=10, length=100)
        self.brush_size_scale.grid(row=0, column=4, padx=5)

        # Draw Button
        self.draw_button = ttk.Button(self.toolbar, text="Draw", command=self.activate_draw)
        self.draw_button.grid(row=0, column=5, padx=5)
        self.drawing = False
        self.last_x = None
        self.last_y = None

        # Clear Button
        self.clear_button = ttk.Button(self.toolbar, text="Clear", command=self.clear_canvas)
        self.clear_button.grid(row=0, column=6, padx=5)

        # Effects Menu
        self.effects_menu_button = ttk.Menubutton(self.toolbar, text="Effects")
        self.effects_menu_button.grid(row=0, column=7, padx=5)
        self.effects_menu = tk.Menu(self.effects_menu_button, tearoff=0)
        self.effects_menu_button["menu"] = self.effects_menu

        self.effects_menu.add_command(label="Grayscale", command=self.apply_grayscale)
        self.effects_menu.add_command(label="Blur", command=self.apply_blur)
        self.effects_menu.add_command(label="Invert Colors", command=self.apply_invert)
        self.effects_menu.add_command(label="Pixelate", command=self.apply_pixelate)

        # Details Button
        self.details_button = ttk.Button(master, text="Details", command=self.show_details)
        self.details_button.pack(pady=5)

        # --- Event Binding ---
        self.canvas.bind("<B1-Motion>", self.paint)
        self.canvas.bind("<ButtonRelease-1>", self.reset)

    def open_image(self):
        self.filename = filedialog.askopenfilename(initialdir=".", title="Select an Image", filetypes=(("Image Files", "*.png;*.jpg;*.jpeg;*.bmp"), ("all files", "*.*")))
        if self.filename:
            self.image = Image.open(self.filename)
            self.image_tk = ImageTk.PhotoImage(self.image)
            self.canvas_width = self.image.width
            self.canvas_height = self.image.height
            self.canvas.config(width=self.canvas_width, height=self.canvas_height)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
            self.draw = ImageDraw.Draw(self.image)
            self.save_button['state'] = tk.NORMAL

    def save_image(self):
        if self.filename:
            file_extension = self.filename.split(".")[-1].lower()
            if file_extension in ["jpg", "jpeg"]
                save_file_extension = "jpeg"
            else:
                save_file_extension = "png"

            save_filename = filedialog.asksaveasfilename(defaultextension=f".{save_file_extension}", filetypes=(("PNG files", "*.png"), ("JPEG files", "*.jpg"), ("All files", "*.*")))
            if save_filename:
                self.image.save(save_filename)

    def choose_color(self):
        color_code = colorchooser.askcolor(title="Choose a color")[1]
        if color_code:
            self.current_color = color_code

    def update_brush_size(self, event=None):
        pass # Brush size is already handled by the self.brush_size variable

    def activate_draw(self):
        self.drawing = True

    def paint(self, event):
        if self.drawing and self.image:
            x, y = event.x, event.y
            if self.last_x is not None and self.last_y is not None:
                self.canvas.create_line((self.last_x, self.last_y, x, y), width=self.brush_size.get(), fill=self.current_color, capstyle=tk.ROUND, smooth=tk.TRUE)
                self.draw.line((self.last_x, self.last_y, x, y), width=self.brush_size.get(), fill=self.current_color, joint='curve')

            self.last_x = x
            self.last_y = y

    def reset(self, event):
        self.last_x = None
        self.last_y = None

    def clear_canvas(self):
        if self.image:
            self.image = Image.new("RGB", (self.canvas_width, self.canvas_height), "white")
            self.image_tk = ImageTk.PhotoImage(self.image)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
            self.draw = ImageDraw.Draw(self.image)
            self.save_button['state'] = tk.NORMAL
        else:
            self.canvas.delete("all")  # Clear canvas even if no image is loaded


    def apply_grayscale(self):
        if self.image:
            self.image = self.image.convert('L').convert('RGB') # Convert to grayscale then back to RGB to ensure compatibility with drawing
            self.image_tk = ImageTk.PhotoImage(self.image)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
            self.draw = ImageDraw.Draw(self.image)

    def apply_blur(self):
        if self.image:
            from PIL import ImageFilter
            self.image = self.image.filter(ImageFilter.BLUR)
            self.image_tk = ImageTk.PhotoImage(self.image)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
            self.draw = ImageDraw.Draw(self.image)

    def apply_invert(self):
      if self.image:
        self.image = Image.eval(self.image, lambda x: 255 - x)
        self.image_tk = ImageTk.PhotoImage(self.image)
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
        self.draw = ImageDraw.Draw(self.image)

    def apply_pixelate(self):
        if self.image:
            # Reduce image size
            small_size = (self.image.width // 10, self.image.height // 10)
            img = self.image.resize(small_size, Image.NEAREST)

            # Scale it back up
            self.image = img.resize(self.image.size, Image.NEAREST)
            self.image_tk = ImageTk.PhotoImage(self.image)
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image_tk)
            self.draw = ImageDraw.Draw(self.image)


    def show_details(self):
        details_window = tk.Toplevel(self.master)
        details_window.title("Program Details")
        details_text = tk.Text(details_window, wrap=tk.WORD)
        details_text.pack(padx=10, pady=10)
        details_text.insert(tk.END, "Luminous Weaver is a versatile image editor designed for both beginners and experienced users. It allows you to open, edit, and save images in various formats. Key features include: drawing with customizable colors and brush sizes, applying various image effects (grayscale, blur, invert colors, pixelate), and a user-friendly interface.  You can easily load an image, apply modifications using the provided tools, and save the result.  The effects are designed to be quick and easy to apply, enhancing your workflow.")
        details_text.config(state=tk.DISABLED)

root = tk.Tk()
editor = ImageEditor(root)
root.mainloop()
👁️ Viewed: 7

Comments