DR-Image-Magic / app.py
kirikir13's picture
Rename dr_image_magic_FULL.py to app.py
ae9536f verified
#!/usr/bin/env python3
"""
DR-Image-Magic - FULL FEATURED GUI
All features, no database needed!
"""
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, scrolledtext
from PIL import Image, ImageTk, ImageEnhance, ImageFilter, ImageOps, ImageDraw, ImageFont
import os
from pathlib import Path
import numpy as np
from datetime import datetime
class DrImageMagicFull:
def __init__(self, root):
self.root = root
self.root.title("DR-Image-Magic - FULL EDITION")
self.root.geometry("1200x900")
self.root.configure(bg='#0a0a0a')
self.current_image = None
self.original_image = None
self.image_path = None
self.history = [] # Undo history
self.setup_ui()
def setup_ui(self):
# Main container with scrollbar
main_canvas = tk.Canvas(self.root, bg='#0a0a0a', highlightthickness=0)
scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=main_canvas.yview)
scrollable_frame = tk.Frame(main_canvas, bg='#0a0a0a')
scrollable_frame.bind(
"<Configure>",
lambda e: main_canvas.configure(scrollregion=main_canvas.bbox("all"))
)
main_canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
main_canvas.configure(yscrollcommand=scrollbar.set)
main_canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Enable mousewheel scrolling
def _on_mousewheel(event):
main_canvas.yview_scroll(int(-1*(event.delta/120)), "units")
main_canvas.bind_all("<MouseWheel>", _on_mousewheel)
# Header
header = tk.Label(
scrollable_frame,
text="🎨 DR-IMAGE-MAGIC",
font=("Arial", 32, "bold"),
bg='#0a0a0a',
fg='#ff6600'
)
header.pack(pady=15)
subtitle = tk.Label(
scrollable_frame,
text="FULL FEATURED EDITION - All Tools, No Limits",
font=("Arial", 12),
bg='#0a0a0a',
fg='#888'
)
subtitle.pack()
# Upload Section
upload_frame = tk.Frame(scrollable_frame, bg='#0a0a0a')
upload_frame.pack(pady=15)
upload_btn = tk.Button(
upload_frame,
text="📁 UPLOAD IMAGE",
command=self.upload_image,
font=("Arial", 16, "bold"),
bg='#ff6600',
fg='white',
padx=30,
pady=12,
cursor='hand2',
relief=tk.FLAT
)
upload_btn.pack()
# Image Preview
preview_frame = tk.Frame(scrollable_frame, bg='#1a1a1a', relief=tk.SUNKEN, bd=2)
preview_frame.pack(pady=10, padx=20, fill=tk.BOTH)
self.image_label = tk.Label(
preview_frame,
bg='#1a1a1a',
text="No Image Loaded\n\nDrag & Drop or Click Upload",
fg='#666',
font=("Arial", 14)
)
self.image_label.pack(pady=40, padx=20)
# Quick Actions
quick_frame = tk.Frame(scrollable_frame, bg='#0a0a0a')
quick_frame.pack(pady=10)
quick_btns = [
("🔄 UNDO", self.undo_last, '#ff9900'),
("↺ RESET", self.reset_image, '#cc0000'),
("💾 SAVE", self.save_image, '#00cc00'),
("📦 BATCH SAVE", self.batch_save, '#0066cc'),
]
for text, cmd, color in quick_btns:
btn = tk.Button(
quick_frame,
text=text,
command=cmd,
font=("Arial", 11, "bold"),
bg=color,
fg='white',
padx=15,
pady=8,
cursor='hand2',
relief=tk.FLAT
)
btn.pack(side=tk.LEFT, padx=5)
# EFFECTS SECTIONS
self.create_effects_section(scrollable_frame)
def create_effects_section(self, parent):
# Section 1: ESSENTIAL ENHANCEMENTS
self.create_section(parent, "⚡ ESSENTIAL ENHANCEMENTS", [
("✨ Auto Enhance", self.auto_enhance, "Smart enhancement"),
("💎 Super Sharpen", self.super_sharpen, "Crystal clear"),
("🌈 Color Pop", self.color_pop, "Vibrant colors"),
("🔥 HDR Effect", self.hdr_effect, "High dynamic range"),
])
# Section 2: ARTISTIC STYLES
self.create_section(parent, "🎨 ARTISTIC STYLES", [
("🖼️ Oil Painting", self.oil_painting, "Classic art"),
("📸 Film Noir", self.film_noir, "Black & white drama"),
("🌅 Golden Hour", self.golden_hour, "Warm sunset glow"),
("❄️ Ice Cold", self.ice_cold, "Cool blue tones"),
("🔴 Infrared", self.infrared, "IR photography"),
("⚫ High Key B&W", self.high_key_bw, "Bright grayscale"),
])
# Section 3: DRAMATIC EFFECTS
self.create_section(parent, "💥 DRAMATIC EFFECTS", [
("🌙 Dark Fantasy", self.dark_fantasy, "Gothic mood"),
("☀️ Sunburst", self.sunburst, "Intense brightness"),
("🎭 Vignette Drama", self.vignette_drama, "Dark edges"),
("✨ Glow", self.glow_effect, "Soft luminous"),
("🔆 Cross Process", self.cross_process, "Film effect"),
])
# Section 4: VINTAGE & RETRO
self.create_section(parent, "📷 VINTAGE & RETRO", [
("📼 VHS Glitch", self.vhs_glitch, "80s video"),
("📺 CRT Monitor", self.crt_effect, "Old screen"),
("🎞️ 70s Film", self.seventies_film, "Retro warm"),
("📟 Polaroid", self.polaroid, "Instant camera"),
("🌄 Faded Memory", self.faded_memory, "Old photo"),
])
# Section 5: MODERN & DIGITAL
self.create_section(parent, "🚀 MODERN & DIGITAL", [
("💻 Cyberpunk", self.cyberpunk, "Neon future"),
("🌐 Glitch Art", self.glitch_art, "Digital chaos"),
("🎮 Pixel Art", self.pixel_art, "8-bit style"),
("🌌 Vaporwave", self.vaporwave, "A E S T H E T I C"),
("⚡ Neon Lights", self.neon_lights, "Bright neon"),
])
# Section 6: PRO PRESETS
self.create_section(parent, "🏆 PRO PRESETS", [
("📱 Instagram Pro", self.instagram_pro, "Social ready"),
("🖼️ Gallery Print", self.gallery_print, "Museum quality"),
("💼 Professional", self.professional, "Business look"),
("🎪 Artistic Bold", self.artistic_bold, "Creative statement"),
("🕯️ Candlelight Sketch", self.candlelight_sketch, "Pencil + warm glow"),
])
# Section 7: IMAGE TOOLS
self.create_section(parent, "🔧 IMAGE TOOLS", [
("🔲 Expand Canvas", self.expand_canvas, "Extend image"),
("📐 Upscale 2x", self.upscale_image, "Make bigger"),
("🎨 Style Transfer", self.style_transfer, "Apply style"),
("🔄 Rotate 90°", self.rotate_90, "Quick rotate"),
("↔️ Flip Horizontal", self.flip_horizontal, "Mirror"),
("↕️ Flip Vertical", self.flip_vertical, "Flip"),
])
def create_section(self, parent, title, effects):
section = tk.LabelFrame(
parent,
text=title,
font=("Arial", 14, "bold"),
bg='#0a0a0a',
fg='#ff6600',
relief=tk.GROOVE,
bd=2
)
section.pack(pady=15, padx=20, fill=tk.X)
grid_frame = tk.Frame(section, bg='#0a0a0a')
grid_frame.pack(pady=10, padx=10)
row, col = 0, 0
for name, cmd, desc in effects:
btn_frame = tk.Frame(grid_frame, bg='#1a1a1a', relief=tk.RAISED, bd=1)
btn_frame.grid(row=row, column=col, padx=5, pady=5, sticky='ew')
btn = tk.Button(
btn_frame,
text=name,
command=cmd,
font=("Arial", 10, "bold"),
bg='#1a1a1a',
fg='#ff6600',
padx=12,
pady=8,
cursor='hand2',
relief=tk.FLAT
)
btn.pack(fill=tk.X)
desc_label = tk.Label(
btn_frame,
text=desc,
font=("Arial", 8),
bg='#1a1a1a',
fg='#666'
)
desc_label.pack()
col += 1
if col > 3: # 4 columns
col = 0
row += 1
def upload_image(self):
file_path = filedialog.askopenfilename(
title="Select Image",
filetypes=[("Images", "*.png *.jpg *.jpeg *.webp *.bmp"), ("All", "*.*")]
)
if file_path:
try:
self.image_path = file_path
self.original_image = Image.open(file_path).convert('RGB')
self.current_image = self.original_image.copy()
self.history = [self.current_image.copy()]
self.display_image(self.current_image)
except Exception as e:
messagebox.showerror("Error", f"Failed to load: {e}")
def display_image(self, image):
display_img = image.copy()
display_img.thumbnail((600, 400), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(display_img)
self.image_label.configure(image=photo, text="")
self.image_label.image = photo
def save_to_history(self):
if self.current_image:
self.history.append(self.current_image.copy())
if len(self.history) > 20: # Keep last 20
self.history.pop(0)
def check_image(self):
if not self.current_image:
messagebox.showwarning("No Image", "Upload an image first!")
return False
return True
def apply_effect(self, effect_func):
if not self.check_image(): return
self.save_to_history()
try:
self.current_image = effect_func(self.current_image)
self.display_image(self.current_image)
except Exception as e:
messagebox.showerror("Effect Error", str(e))
# === ESSENTIAL ENHANCEMENTS ===
def auto_enhance(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Contrast(img).enhance(1.2)
img = ImageEnhance.Sharpness(img).enhance(1.3)
img = ImageEnhance.Color(img).enhance(1.1)
self.current_image = img
self.display_image(img)
def super_sharpen(self):
self.apply_effect(lambda img: img.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)))
def color_pop(self):
self.apply_effect(lambda img: ImageEnhance.Color(img).enhance(1.8))
def hdr_effect(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Contrast(img).enhance(1.5)
img = ImageEnhance.Brightness(img).enhance(0.95)
img = ImageEnhance.Color(img).enhance(1.3)
self.current_image = img
self.display_image(img)
# === ARTISTIC STYLES ===
def oil_painting(self):
self.apply_effect(lambda img: img.filter(ImageFilter.SMOOTH_MORE).filter(ImageFilter.EDGE_ENHANCE))
def film_noir(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image.convert('L').convert('RGB')
img = ImageEnhance.Contrast(img).enhance(1.6)
self.current_image = img
self.display_image(img)
def golden_hour(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: min(255, int(i * 1.15)))
g = g.point(lambda i: min(255, int(i * 1.08)))
b = b.point(lambda i: int(i * 0.88))
img = Image.merge('RGB', (r, g, b))
img = ImageEnhance.Brightness(img).enhance(1.05)
self.current_image = img
self.display_image(img)
def ice_cold(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: int(i * 0.85))
g = g.point(lambda i: int(i * 0.92))
b = b.point(lambda i: min(255, int(i * 1.15)))
self.current_image = Image.merge('RGB', (r, g, b))
self.display_image(self.current_image)
def infrared(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image.convert('L')
img = ImageOps.invert(img)
img = ImageEnhance.Contrast(img).enhance(1.3)
r = img
g = img
b = img.point(lambda i: int(i * 0.7))
self.current_image = Image.merge('RGB', (r, g, b))
self.display_image(self.current_image)
def high_key_bw(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image.convert('L').convert('RGB')
img = ImageEnhance.Brightness(img).enhance(1.2)
img = ImageEnhance.Contrast(img).enhance(0.8)
self.current_image = img
self.display_image(img)
# === DRAMATIC EFFECTS ===
def dark_fantasy(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Brightness(img).enhance(0.6)
img = ImageEnhance.Contrast(img).enhance(1.6)
img = ImageEnhance.Color(img).enhance(0.8)
self.current_image = img
self.display_image(img)
def sunburst(self):
self.apply_effect(lambda img: ImageEnhance.Brightness(img).enhance(1.4))
def vignette_drama(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
width, height = img.size
mask = Image.new('L', (width, height), 0)
draw = ImageDraw.Draw(mask)
for i in range(min(width, height) // 4):
alpha = int(255 * (i / (min(width, height) // 4)))
draw.ellipse(
[i, i, width-i, height-i],
fill=alpha
)
dark = Image.new('RGB', img.size, (0, 0, 0))
self.current_image = Image.composite(img, dark, mask)
self.display_image(self.current_image)
def glow_effect(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
glow = img.filter(ImageFilter.GaussianBlur(15))
glow = ImageEnhance.Brightness(glow).enhance(1.5)
self.current_image = Image.blend(img, glow, 0.3)
self.display_image(self.current_image)
def cross_process(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: min(255, int(i * 1.1)))
g = g.point(lambda i: int(i * 0.95))
b = b.point(lambda i: min(255, int(i * 1.15)))
img = Image.merge('RGB', (r, g, b))
img = ImageEnhance.Contrast(img).enhance(1.3)
self.current_image = img
self.display_image(img)
# === VINTAGE & RETRO ===
def vhs_glitch(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Contrast(img).enhance(1.2)
img = ImageEnhance.Color(img).enhance(0.8)
self.current_image = img
self.display_image(img)
def crt_effect(self):
self.apply_effect(lambda img: ImageEnhance.Brightness(img).enhance(1.1))
def seventies_film(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: min(255, int(i * 1.12)))
g = g.point(lambda i: min(255, int(i * 1.05)))
b = b.point(lambda i: int(i * 0.9))
img = Image.merge('RGB', (r, g, b))
img = ImageEnhance.Contrast(img).enhance(0.9)
self.current_image = img
self.display_image(img)
def polaroid(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Brightness(img).enhance(1.1)
img = ImageEnhance.Color(img).enhance(0.85)
img = ImageEnhance.Contrast(img).enhance(0.95)
self.current_image = img
self.display_image(img)
def faded_memory(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Color(img).enhance(0.6)
img = ImageEnhance.Brightness(img).enhance(1.15)
img = ImageEnhance.Contrast(img).enhance(0.8)
self.current_image = img
self.display_image(img)
# === MODERN & DIGITAL ===
def cyberpunk(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: min(255, int(i * 1.2)))
g = g.point(lambda i: int(i * 0.9))
b = b.point(lambda i: min(255, int(i * 1.3)))
img = Image.merge('RGB', (r, g, b))
img = ImageEnhance.Contrast(img).enhance(1.4)
self.current_image = img
self.display_image(img)
def glitch_art(self):
self.apply_effect(lambda img: img.filter(ImageFilter.EDGE_ENHANCE_MORE))
def pixel_art(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
small = img.resize((img.width // 16, img.height // 16), Image.Resampling.NEAREST)
self.current_image = small.resize(img.size, Image.Resampling.NEAREST)
self.display_image(self.current_image)
def vaporwave(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
r, g, b = img.split()
r = r.point(lambda i: min(255, int(i * 1.2)))
g = g.point(lambda i: min(255, int(i * 0.95)))
b = b.point(lambda i: min(255, int(i * 1.25)))
img = Image.merge('RGB', (r, g, b))
img = ImageEnhance.Color(img).enhance(1.5)
self.current_image = img
self.display_image(img)
def neon_lights(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Color(img).enhance(2.0)
img = ImageEnhance.Contrast(img).enhance(1.3)
img = ImageEnhance.Brightness(img).enhance(1.2)
self.current_image = img
self.display_image(img)
# === PRO PRESETS ===
def instagram_pro(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Contrast(img).enhance(1.15)
img = ImageEnhance.Color(img).enhance(1.2)
img = ImageEnhance.Sharpness(img).enhance(1.1)
self.current_image = img
self.display_image(img)
def gallery_print(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Contrast(img).enhance(1.1)
img = ImageEnhance.Sharpness(img).enhance(1.3)
img = ImageEnhance.Color(img).enhance(1.05)
self.current_image = img
self.display_image(img)
def professional(self):
self.apply_effect(lambda img: ImageEnhance.Contrast(img).enhance(1.1))
def artistic_bold(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
img = ImageEnhance.Color(img).enhance(1.6)
img = ImageEnhance.Contrast(img).enhance(1.4)
self.current_image = img
self.display_image(img)
def candlelight_sketch(self):
"""Pencil sketch with warm candlelight - mimics the style Dave showed"""
if not self.check_image(): return
self.save_to_history()
img = self.current_image
# Step 1: Reduce color saturation (pencil sketch base)
img = ImageEnhance.Color(img).enhance(0.3)
# Step 2: Add warm candlelight glow (orange/golden tones)
r, g, b = img.split()
# Boost reds/oranges (candlelight)
r = r.point(lambda i: min(255, int(i * 1.3)))
g = g.point(lambda i: min(255, int(i * 1.15)))
b = b.point(lambda i: int(i * 0.75)) # Reduce blue for warmth
img = Image.merge('RGB', (r, g, b))
# Step 3: High contrast (dramatic lighting)
img = ImageEnhance.Contrast(img).enhance(1.8)
# Step 4: Darken overall (dark shadows)
img = ImageEnhance.Brightness(img).enhance(0.7)
# Step 5: Add slight blur to mimic soft pencil texture
img = img.filter(ImageFilter.GaussianBlur(radius=0.5))
# Step 6: Edge enhance for sketch lines
img = img.filter(ImageFilter.EDGE_ENHANCE)
self.current_image = img
self.display_image(img)
# === ACTIONS ===
def undo_last(self):
if len(self.history) > 1:
self.history.pop()
self.current_image = self.history[-1].copy()
self.display_image(self.current_image)
else:
messagebox.showinfo("Undo", "No more undo history!")
def reset_image(self):
if self.original_image:
self.current_image = self.original_image.copy()
self.history = [self.current_image.copy()]
self.display_image(self.current_image)
def save_image(self):
if not self.check_image(): return
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG", "*.png"), ("JPEG", "*.jpg"), ("WebP", "*.webp")]
)
if file_path:
try:
self.current_image.save(file_path, quality=95)
messagebox.showinfo("Saved!", f"Saved to:\n{file_path}")
except Exception as e:
messagebox.showerror("Error", f"Save failed: {e}")
def batch_save(self):
if not self.check_image(): return
folder = filedialog.askdirectory(title="Select Output Folder")
if folder:
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"dr_magic_{timestamp}.png"
path = os.path.join(folder, filename)
self.current_image.save(path, quality=95)
messagebox.showinfo("Batch Saved!", f"Saved to:\n{path}")
except Exception as e:
messagebox.showerror("Error", str(e))
# === IMAGE TOOLS ===
def expand_canvas(self):
if not self.check_image(): return
self.save_to_history()
# Ask for expansion amount
expansion = 100 # pixels on each side
img = self.current_image
width, height = img.size
new_width = width + (expansion * 2)
new_height = height + (expansion * 2)
# Create new canvas
expanded = Image.new('RGB', (new_width, new_height), (20, 20, 20))
# Paste original in center
expanded.paste(img, (expansion, expansion))
self.current_image = expanded
self.display_image(self.current_image)
messagebox.showinfo("Expanded!", f"Canvas expanded by {expansion}px on each side")
def upscale_image(self):
if not self.check_image(): return
self.save_to_history()
img = self.current_image
new_size = (img.width * 2, img.height * 2)
# Use LANCZOS for quality upscaling
upscaled = img.resize(new_size, Image.Resampling.LANCZOS)
self.current_image = upscaled
self.display_image(self.current_image)
messagebox.showinfo("Upscaled!", f"Image doubled to {new_size[0]}x{new_size[1]}")
def style_transfer(self):
if not self.check_image(): return
style_path = filedialog.askopenfilename(
title="Select Style Reference Image",
filetypes=[("Images", "*.png *.jpg *.jpeg"), ("All", "*.*")]
)
if not style_path:
return
self.save_to_history()
try:
style_img = Image.open(style_path).convert('RGB')
# Simple style transfer using color statistics
content = self.current_image
# Get color statistics from style image
style_array = np.array(style_img)
content_array = np.array(content)
# Match mean and std of each channel
for i in range(3): # RGB channels
content_mean = content_array[:,:,i].mean()
content_std = content_array[:,:,i].std()
style_mean = style_array[:,:,i].mean()
style_std = style_array[:,:,i].std()
# Transfer statistics
content_array[:,:,i] = (content_array[:,:,i] - content_mean) / (content_std + 1e-5)
content_array[:,:,i] = content_array[:,:,i] * style_std + style_mean
# Clip to valid range
content_array = np.clip(content_array, 0, 255).astype(np.uint8)
self.current_image = Image.fromarray(content_array)
self.display_image(self.current_image)
messagebox.showinfo("Style Applied!", "Style transfer complete!")
except Exception as e:
messagebox.showerror("Error", f"Style transfer failed: {e}")
def rotate_90(self):
if not self.check_image(): return
self.save_to_history()
self.current_image = self.current_image.rotate(-90, expand=True)
self.display_image(self.current_image)
def flip_horizontal(self):
if not self.check_image(): return
self.save_to_history()
self.current_image = self.current_image.transpose(Image.FLIP_LEFT_RIGHT)
self.display_image(self.current_image)
def flip_vertical(self):
if not self.check_image(): return
self.save_to_history()
self.current_image = self.current_image.transpose(Image.FLIP_TOP_BOTTOM)
self.display_image(self.current_image)
if __name__ == "__main__":
root = tk.Tk()
app = DrImageMagicFull(root)
root.mainloop()