Initial Tkinter GUI
This commit is contained in:
parent
a6b0298253
commit
725b3c351e
|
|
@ -9,17 +9,22 @@ Tkinter-based GUI for WImageEdit, using wimage_core for:
|
|||
- Simple per-file save/load of settings (imgedit_proc.json).
|
||||
- Directory defaults.
|
||||
|
||||
Layout:
|
||||
- Left panel: directory selection, file list, navigation, info.
|
||||
- Right panel: top canvas = Original, bottom canvas = Preview, controls on the right.
|
||||
|
||||
This version:
|
||||
- Shows TWO views:
|
||||
Left = original (with rotation applied, no processing except resize)
|
||||
Right = preview with current options applied (Pillow approximation).
|
||||
- Shows TWO views stacked vertically:
|
||||
Top = original (rotated, no processing except resize)
|
||||
Bottom = preview with current options applied (Pillow approximation).
|
||||
- Includes parametric controls for:
|
||||
- Sigmoidal contrast (contrast, midpoint)
|
||||
- Sharpen (radius, amount, threshold)
|
||||
- Includes rotation controls:
|
||||
- None / 90 / 180 / 270 / Custom
|
||||
- Displays a live ImageMagick command string based on current options.
|
||||
"""
|
||||
|
||||
import sys, os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass, field
|
||||
|
|
@ -49,6 +54,8 @@ from wimage_core import (
|
|||
save_directory_defaults,
|
||||
)
|
||||
|
||||
import tempfile
|
||||
|
||||
|
||||
# ---------------------- helpers / file listing / EXIF ----------------------
|
||||
|
||||
|
|
@ -111,8 +118,11 @@ class WImageEditTk(tk.Tk):
|
|||
|
||||
self.state = AppState()
|
||||
|
||||
# IM command string (for display/copy)
|
||||
self.current_cmd_str: str = ""
|
||||
|
||||
# UI variables
|
||||
self.dir_var = tk.StringVar()
|
||||
self.dir_var = tk.StringVar(value="~/Downloads")
|
||||
|
||||
self.color_var = tk.BooleanVar(value=True)
|
||||
self.sigmoidal_var = tk.BooleanVar(value=True)
|
||||
|
|
@ -145,19 +155,23 @@ class WImageEditTk(tk.Tk):
|
|||
# --------------------------- UI building ---------------------------------
|
||||
|
||||
def _build_ui(self):
|
||||
top = ttk.Frame(self, padding=5)
|
||||
top.pack(side=tk.TOP, fill=tk.X)
|
||||
|
||||
# Left: file list + nav
|
||||
left = ttk.Frame(self, padding=5)
|
||||
ttk.Label(left, text="Dir:").pack(side=tk.LEFT)
|
||||
ttk.Entry(left, textvariable=self.dir_var, width=30).pack(side=tk.LEFT, padx=4)
|
||||
ttk.Button(left, text="Browse...", command=self.select_directory).pack(side=tk.LEFT)
|
||||
# Main frame splits left (files) and right (images + controls)
|
||||
main = ttk.Frame(self, padding=5)
|
||||
main.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# LEFT PANEL: directory picker + file list + nav + info
|
||||
left = ttk.Frame(main, padding=5)
|
||||
left.pack(side=tk.LEFT, fill=tk.Y)
|
||||
|
||||
# Directory picker at top *within* left panel
|
||||
dir_frame = ttk.Frame(left)
|
||||
dir_frame.pack(fill=tk.X, pady=(0, 5))
|
||||
ttk.Label(dir_frame, text="Directory:").pack(side=tk.LEFT)
|
||||
ttk.Entry(dir_frame, textvariable=self.dir_var, width=30).pack(side=tk.LEFT, padx=4)
|
||||
ttk.Button(dir_frame, text="...", width=3, command=self.select_directory).pack(side=tk.LEFT)
|
||||
|
||||
ttk.Label(left, text="Files:").pack(anchor=tk.W)
|
||||
self.file_listbox = tk.Listbox(left, width=40, height=25)
|
||||
self.file_listbox = tk.Listbox(left, width=35, height=24)
|
||||
self.file_listbox.pack(fill=tk.BOTH, expand=True)
|
||||
self.file_listbox.bind("<<ListboxSelect>>", self.on_file_select)
|
||||
|
||||
|
|
@ -166,39 +180,38 @@ class WImageEditTk(tk.Tk):
|
|||
ttk.Button(nav_frame, text="Prev", command=self.prev_image).pack(side=tk.LEFT, expand=True, fill=tk.X)
|
||||
ttk.Button(nav_frame, text="Next", command=self.next_image).pack(side=tk.LEFT, expand=True, fill=tk.X)
|
||||
|
||||
# Center: two canvases (Original + Preview)
|
||||
center = ttk.Frame(self, padding=5)
|
||||
center.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
ttk.Label(left, textvariable=self.info_var, wraplength=260, justify=tk.LEFT).pack(fill=tk.X, pady=5)
|
||||
|
||||
canvas_labels = ttk.Frame(center)
|
||||
canvas_labels.pack(fill=tk.X)
|
||||
#ttk.Label(canvas_labels, text="Original").pack(side=tk.LEFT, expand=True)
|
||||
ttk.Label(canvas_labels, text="Original").pack(side=tk.TOP, expand=True)
|
||||
#ttk.Label(canvas_labels, text="Preview").pack(side=tk.RIGHT, expand=True)
|
||||
ttk.Label(canvas_labels, text="Preview").pack(side=tk.BOTTOM, expand=True)
|
||||
# RIGHT PANEL: top canvas (original), bottom canvas (preview), controls on the right
|
||||
right = ttk.Frame(main, padding=5)
|
||||
right.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
|
||||
canvases = ttk.Frame(center)
|
||||
canvases.pack(fill=tk.BOTH, expand=True)
|
||||
# Right is split: left area = canvases (stacked), right area = controls
|
||||
right_canvases = ttk.Frame(right)
|
||||
right_canvases.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
|
||||
self.canvas_orig = tk.Canvas(canvases, bg="gray", width=600, height=400)
|
||||
#self.canvas_orig.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 2))
|
||||
self.canvas_orig.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=(0, 2))
|
||||
right_controls = ttk.Frame(right, padding=(5, 0))
|
||||
right_controls.pack(side=tk.LEFT, fill=tk.Y)
|
||||
|
||||
self.canvas_prev = tk.Canvas(canvases, bg="gray", width=600, height=400)
|
||||
#self.canvas_prev.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(2, 0))
|
||||
self.canvas_prev.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True, padx=(2, 0))
|
||||
# Canvases stacked: Original (top) and Preview (bottom)
|
||||
orig_label = ttk.Label(right_canvases, text="Original")
|
||||
orig_label.pack(anchor=tk.W)
|
||||
self.canvas_orig = tk.Canvas(right_canvases, bg="gray", width=600, height=300)
|
||||
self.canvas_orig.pack(fill=tk.BOTH, expand=True, pady=(0, 4))
|
||||
|
||||
prev_label = ttk.Label(right_canvases, text="Preview")
|
||||
prev_label.pack(anchor=tk.W)
|
||||
self.canvas_prev = tk.Canvas(right_canvases, bg="gray", width=600, height=300)
|
||||
self.canvas_prev.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Crop is defined by dragging on the ORIGINAL canvas
|
||||
self.canvas_orig.bind("<ButtonPress-1>", self.on_canvas_press)
|
||||
self.canvas_orig.bind("<B1-Motion>", self.on_canvas_drag)
|
||||
self.canvas_orig.bind("<ButtonRelease-1>", self.on_canvas_release)
|
||||
|
||||
# Right: controls
|
||||
right = ttk.Frame(self, padding=5)
|
||||
right.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
|
||||
# Controls on the right
|
||||
# Actions frame
|
||||
actions_frame = ttk.LabelFrame(right, text="Actions", padding=5)
|
||||
actions_frame = ttk.LabelFrame(right_controls, text="Actions", padding=5)
|
||||
actions_frame.pack(fill=tk.X)
|
||||
|
||||
ttk.Button(actions_frame, text="Color Pos",
|
||||
|
|
@ -211,7 +224,7 @@ class WImageEditTk(tk.Tk):
|
|||
command=lambda: self.apply_action("BW Neg")).pack(fill=tk.X, pady=1)
|
||||
|
||||
# Processing options
|
||||
opts_frame = ttk.LabelFrame(right, text="Processing", padding=5)
|
||||
opts_frame = ttk.LabelFrame(right_controls, text="Processing", padding=5)
|
||||
opts_frame.pack(fill=tk.X, pady=(5, 0))
|
||||
|
||||
ttk.Checkbutton(
|
||||
|
|
@ -296,7 +309,7 @@ class WImageEditTk(tk.Tk):
|
|||
ttk.Label(scale_row, text="(1.1 ≈ 10% border)").pack(side=tk.LEFT)
|
||||
|
||||
# Rotation controls
|
||||
rot_frame = ttk.LabelFrame(right, text="Rotation", padding=5)
|
||||
rot_frame = ttk.LabelFrame(right_controls, text="Rotation", padding=5)
|
||||
rot_frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
def rot_rb(text, value):
|
||||
|
|
@ -323,11 +336,11 @@ class WImageEditTk(tk.Tk):
|
|||
).pack(side=tk.LEFT, padx=4)
|
||||
|
||||
# Annotation
|
||||
annot_frame = ttk.LabelFrame(right, text="Text annotation", padding=5)
|
||||
annot_frame = ttk.LabelFrame(right_controls, text="Text annotation", padding=5)
|
||||
annot_frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
ttk.Label(annot_frame, text="Text:").pack(anchor=tk.W)
|
||||
self.annot_text = tk.Text(annot_frame, width=30, height=4)
|
||||
self.annot_text = tk.Text(annot_frame, width=30, height=3)
|
||||
self.annot_text.pack(fill=tk.X)
|
||||
self.annot_text.bind("<<Modified>>", self.on_annot_modified)
|
||||
|
||||
|
|
@ -356,24 +369,47 @@ class WImageEditTk(tk.Tk):
|
|||
).pack(anchor=tk.W)
|
||||
|
||||
# Directory defaults
|
||||
defaults_frame = ttk.LabelFrame(right, text="Directory defaults", padding=5)
|
||||
defaults_frame = ttk.LabelFrame(right_controls, text="Directory defaults", padding=5)
|
||||
defaults_frame.pack(fill=tk.X, pady=5)
|
||||
ttk.Button(
|
||||
defaults_frame, text="Set from current image",
|
||||
command=self.set_directory_defaults_from_current
|
||||
).pack(fill=tk.X)
|
||||
|
||||
# Actions buttons
|
||||
action_frame = ttk.Frame(right)
|
||||
# IM command display
|
||||
cmd_frame = ttk.LabelFrame(right_controls, text="Current IM command", padding=5)
|
||||
cmd_frame.pack(fill=tk.BOTH, expand=True, pady=5)
|
||||
|
||||
self.cmd_text = tk.Text(cmd_frame, width=40, height=6, wrap="word")
|
||||
self.cmd_text.pack(fill=tk.BOTH, expand=True)
|
||||
self.cmd_text.configure(state="disabled")
|
||||
|
||||
btn_row = ttk.Frame(cmd_frame)
|
||||
btn_row.pack(fill=tk.X, pady=(4, 0))
|
||||
ttk.Button(btn_row, text="Copy IM Cmd", command=self.copy_cmd_to_clipboard).pack(side=tk.LEFT, expand=True, fill=tk.X)
|
||||
ttk.Button(btn_row, text="IM Preview", command=self.run_im_preview).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(4, 0))
|
||||
|
||||
ttk.Label(
|
||||
cmd_frame,
|
||||
text="Note: if 'Granite background' is checked, two IM\n"
|
||||
"commands are used (subject + background).",
|
||||
justify=tk.LEFT,
|
||||
wraplength=260,
|
||||
).pack(fill=tk.X, pady=(4, 0))
|
||||
|
||||
|
||||
# Actions buttons (bottom)
|
||||
action_frame = ttk.Frame(right_controls)
|
||||
action_frame.pack(fill=tk.X, pady=10)
|
||||
ttk.Button(action_frame, text="Process", command=self.process_current).pack(fill=tk.X)
|
||||
ttk.Button(action_frame, text="Quit", command=self.destroy).pack(fill=tk.X, pady=(5, 0))
|
||||
|
||||
ttk.Label(
|
||||
right, textvariable=self.info_var,
|
||||
wraplength=220, justify=tk.LEFT
|
||||
).pack(fill=tk.X, pady=5)
|
||||
|
||||
# Initial action
|
||||
# print(dir(self.dir_var))
|
||||
if os.path.exists(self.dir_var.get()):
|
||||
self.state.directory = Path(self.dir_var.get())
|
||||
self.load_files()
|
||||
|
||||
# ------------------------------ directory & files ------------------------
|
||||
|
||||
def select_directory(self):
|
||||
|
|
@ -400,6 +436,7 @@ class WImageEditTk(tk.Tk):
|
|||
self.canvas_orig.delete("all")
|
||||
self.canvas_prev.delete("all")
|
||||
self.info_var.set("No image files found in directory.")
|
||||
self.update_cmd_display(clear=True)
|
||||
|
||||
def on_file_select(self, event=None):
|
||||
sel = self.file_listbox.curselection()
|
||||
|
|
@ -439,8 +476,8 @@ class WImageEditTk(tk.Tk):
|
|||
|
||||
def display_on_canvas(self, canvas: tk.Canvas, img: Image.Image, is_original: bool):
|
||||
"""Scale and display img on the given canvas, center it."""
|
||||
canvas_w = canvas.winfo_width() or 400
|
||||
canvas_h = canvas.winfo_height() or 600
|
||||
canvas_w = canvas.winfo_width() or 600
|
||||
canvas_h = canvas.winfo_height() or 300
|
||||
scale = min(canvas_w / img.size[0], canvas_h / img.size[1])
|
||||
new_size = (max(1, int(img.size[0] * scale)), max(1, int(img.size[1] * scale)))
|
||||
disp_img = img.resize(new_size, Image.LANCZOS)
|
||||
|
|
@ -693,6 +730,7 @@ class WImageEditTk(tk.Tk):
|
|||
Rebuild the rotated original and the preview from base_image + options.
|
||||
"""
|
||||
if self.state.base_image is None:
|
||||
self.update_cmd_display(clear=True)
|
||||
return
|
||||
opts = self.gather_options_from_ui(include_crop=False)
|
||||
# Rotate base image according to opts
|
||||
|
|
@ -806,13 +844,16 @@ class WImageEditTk(tk.Tk):
|
|||
|
||||
def update_preview(self):
|
||||
"""
|
||||
Recompute and display the preview image (processed) on the right canvas.
|
||||
Recompute and display the preview image (processed) on the bottom canvas.
|
||||
Also updates the IM command text.
|
||||
"""
|
||||
if not self.state.current_image:
|
||||
self.update_cmd_display(clear=True)
|
||||
return
|
||||
opts = self.gather_options_from_ui(include_crop=True)
|
||||
preview_img = self.apply_preview_effects(self.state.current_image.copy(), opts)
|
||||
self.display_on_canvas(self.canvas_prev, preview_img, is_original=False)
|
||||
self.update_cmd_display(clear=False)
|
||||
|
||||
def options_changed(self):
|
||||
"""Callback used by various controls to trigger preview update."""
|
||||
|
|
@ -823,6 +864,186 @@ class WImageEditTk(tk.Tk):
|
|||
self.annot_text.edit_modified(False)
|
||||
self.update_preview()
|
||||
|
||||
# ----------------------- IM command display / copy -----------------------
|
||||
|
||||
def update_cmd_display(self, clear: bool = False):
|
||||
"""
|
||||
Build and show the current main ImageMagick command.
|
||||
|
||||
For directories with no image selected, or clear=True, the display is emptied.
|
||||
|
||||
If 'Granite background' is checked, note that a second command
|
||||
will be run on Process, but we don't synthesize that here.
|
||||
"""
|
||||
if clear or not self.state.files:
|
||||
self.current_cmd_str = ""
|
||||
self.cmd_text.configure(state="normal")
|
||||
self.cmd_text.delete("1.0", tk.END)
|
||||
self.cmd_text.configure(state="disabled")
|
||||
return
|
||||
|
||||
path = self.state.files[self.state.current_index]
|
||||
opts = self.gather_options_from_ui(include_crop=True)
|
||||
|
||||
# Destination name (same as Process)
|
||||
dest = path.with_name(path.stem + "_edit.jpg")
|
||||
|
||||
# For background, we still show the main command (first pass).
|
||||
if opts.use_background:
|
||||
tmp_subject = path.with_name(path.stem + "_tmp_subject.jpg")
|
||||
opts_main = EditOptions(
|
||||
crop_box=opts.crop_box,
|
||||
rotation_degrees=opts.rotation_degrees,
|
||||
color_correction=opts.color_correction,
|
||||
sigmoidal=opts.sigmoidal,
|
||||
sigmoidal_contrast=opts.sigmoidal_contrast,
|
||||
sigmoidal_midpoint=opts.sigmoidal_midpoint,
|
||||
sharpen=opts.sharpen,
|
||||
sharpen_radius=opts.sharpen_radius,
|
||||
sharpen_amount=opts.sharpen_amount,
|
||||
sharpen_threshold=opts.sharpen_threshold,
|
||||
grayscale=opts.grayscale,
|
||||
invert=opts.invert,
|
||||
use_background=False,
|
||||
background_scale=opts.background_scale,
|
||||
annotation_text=opts.annotation_text,
|
||||
annotation_pos=opts.annotation_pos,
|
||||
annotation_size=opts.annotation_size,
|
||||
extra_args=opts.extra_args,
|
||||
)
|
||||
cmd = build_imagemagick_cmd(path, tmp_subject, opts_main)
|
||||
cmd_str = " ".join(cmd)
|
||||
cmd_str += "\n# Note: Granite background compositing is run as a second IM command on Process."
|
||||
else:
|
||||
cmd = build_imagemagick_cmd(path, dest, opts)
|
||||
cmd_str = " ".join(cmd)
|
||||
|
||||
self.current_cmd_str = cmd_str
|
||||
self.cmd_text.configure(state="normal")
|
||||
self.cmd_text.delete("1.0", tk.END)
|
||||
self.cmd_text.insert("1.0", cmd_str)
|
||||
self.cmd_text.configure(state="disabled")
|
||||
|
||||
def run_im_preview(self):
|
||||
"""
|
||||
Generate a preview using the *actual* ImageMagick pipeline,
|
||||
but resized down to roughly the preview canvas size for speed.
|
||||
|
||||
It uses the same options as Process (including crop, rotation, etc.),
|
||||
writes to a temporary JPEG, and displays that in the Preview canvas.
|
||||
"""
|
||||
if not self.state.files or self.state.base_image is None:
|
||||
return
|
||||
if not self.state.directory:
|
||||
messagebox.showerror("Error", "No directory selected.")
|
||||
return
|
||||
|
||||
path = self.state.files[self.state.current_index]
|
||||
opts = self.gather_options_from_ui(include_crop=True)
|
||||
|
||||
# Determine preview size from preview canvas
|
||||
canvas_w = self.canvas_prev.winfo_width() or 800
|
||||
canvas_h = self.canvas_prev.winfo_height() or 450
|
||||
resize_arg = f"{canvas_w}x{canvas_h}"
|
||||
|
||||
# We'll add a "-resize WxH" at the end of the main subject command.
|
||||
# That way, all IM operations are done at preview resolution.
|
||||
opts_preview = EditOptions(
|
||||
crop_box=opts.crop_box,
|
||||
rotation_degrees=opts.rotation_degrees,
|
||||
color_correction=opts.color_correction,
|
||||
sigmoidal=opts.sigmoidal,
|
||||
sigmoidal_contrast=opts.sigmoidal_contrast,
|
||||
sigmoidal_midpoint=opts.sigmoidal_midpoint,
|
||||
sharpen=opts.sharpen,
|
||||
sharpen_radius=opts.sharpen_radius,
|
||||
sharpen_amount=opts.sharpen_amount,
|
||||
sharpen_threshold=opts.sharpen_threshold,
|
||||
grayscale=opts.grayscale,
|
||||
invert=opts.invert,
|
||||
use_background=False, # background handled separately below
|
||||
background_scale=opts.background_scale,
|
||||
annotation_text=opts.annotation_text,
|
||||
annotation_pos=opts.annotation_pos,
|
||||
annotation_size=opts.annotation_size,
|
||||
extra_args=["-resize", resize_arg],
|
||||
)
|
||||
|
||||
# Temporary files for subject and final preview
|
||||
tmp_subject = None
|
||||
tmp_preview = None
|
||||
try:
|
||||
if not opts.use_background:
|
||||
# Single-command preview
|
||||
with tempfile.NamedTemporaryFile(suffix="_impreview.jpg", delete=False) as tf:
|
||||
tmp_preview = Path(tf.name)
|
||||
cmd = build_imagemagick_cmd(path, tmp_preview, opts_preview)
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
messagebox.showerror("IM Preview error", f"IM preview failed:\n{e}")
|
||||
return
|
||||
|
||||
else:
|
||||
# Two-step: subject + granite background
|
||||
with tempfile.NamedTemporaryFile(suffix="_subject_impreview.jpg", delete=False) as tf1:
|
||||
tmp_subject = Path(tf1.name)
|
||||
with tempfile.NamedTemporaryFile(suffix="_impreview.jpg", delete=False) as tf2:
|
||||
tmp_preview = Path(tf2.name)
|
||||
|
||||
# 1) Subject at preview resolution
|
||||
cmd1 = build_imagemagick_cmd(path, tmp_subject, opts_preview)
|
||||
try:
|
||||
subprocess.run(cmd1, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
messagebox.showerror("IM Preview error", f"IM subject preview failed:\n{e}")
|
||||
return
|
||||
|
||||
# 2) Background + subject composite
|
||||
try:
|
||||
with Image.open(tmp_subject) as s_img:
|
||||
subject_size = s_img.size
|
||||
except Exception as e:
|
||||
messagebox.showerror("IM Preview error", f"Failed to open subject preview:\n{e}")
|
||||
return
|
||||
|
||||
cmd2 = build_granite_background_cmd(tmp_subject, tmp_preview, opts, subject_size)
|
||||
try:
|
||||
subprocess.run(cmd2, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
messagebox.showerror("IM Preview error", f"IM background preview failed:\n{e}")
|
||||
return
|
||||
|
||||
# Load and display the resulting preview JPEG
|
||||
if tmp_preview and tmp_preview.exists():
|
||||
try:
|
||||
with Image.open(tmp_preview) as im_prev:
|
||||
im_prev = im_prev.convert("RGB")
|
||||
self.display_on_canvas(self.canvas_prev, im_prev, is_original=False)
|
||||
except Exception as e:
|
||||
messagebox.showerror("IM Preview error", f"Failed to load preview image:\n{e}")
|
||||
|
||||
finally:
|
||||
# Clean up temp files
|
||||
try:
|
||||
if tmp_subject and tmp_subject.exists():
|
||||
tmp_subject.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if tmp_preview and tmp_preview.exists():
|
||||
tmp_preview.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def copy_cmd_to_clipboard(self):
|
||||
if not self.current_cmd_str:
|
||||
return
|
||||
self.clipboard_clear()
|
||||
self.clipboard_append(self.current_cmd_str)
|
||||
self.update() # make sure clipboard is updated
|
||||
|
||||
# -------------------------- processing (IM) ------------------------------
|
||||
|
||||
def process_current(self):
|
||||
|
|
@ -867,7 +1088,6 @@ class WImageEditTk(tk.Tk):
|
|||
)
|
||||
|
||||
cmd1 = build_imagemagick_cmd(path, tmp_subject, opts_main)
|
||||
print(cmd1)
|
||||
if not self.confirm_and_run(cmd1):
|
||||
return
|
||||
|
||||
|
|
@ -880,7 +1100,6 @@ class WImageEditTk(tk.Tk):
|
|||
return
|
||||
|
||||
cmd2 = build_granite_background_cmd(tmp_subject, dest, opts, subject_size)
|
||||
print(cmd2)
|
||||
if not self.confirm_and_run(cmd2):
|
||||
return
|
||||
|
||||
|
|
@ -916,11 +1135,10 @@ class WImageEditTk(tk.Tk):
|
|||
|
||||
|
||||
def main():
|
||||
print("start ...")
|
||||
app = WImageEditTk()
|
||||
app.mainloop()
|
||||
print("done.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ def build_imagemagick_cmd(
|
|||
|
||||
# Tone & color operations
|
||||
if opts.color_correction:
|
||||
cmd.extend(["-channel", "RGB", "-auto-level", "-auto-gamma"])
|
||||
# cmd.extend(["-channel", "RGB", "-auto-level", "-auto-gamma"])
|
||||
cmd.extend(["-channel", "RGB", "-auto-level", "-contrast-stretch"])
|
||||
|
||||
if opts.sigmoidal:
|
||||
# Clamp / format midpoint to something IM likes: 0–1
|
||||
|
|
|
|||
Loading…
Reference in New Issue