Python截图轻量化工具
这是用Python做到截图工具,不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中"C:/Windows/Cursors/"中的.cur光标样式文件, 这个工具只适用于Windows环境;
如果要提升其跨平台性的话,需要考虑替换ctypes的一些专属于Windows的API以及设置不同的.cur访问方式;
该模块只使用了PIL这一个第三方库,和别的使用pygame\pyautogui等模块不同,该工具着重强调轻量化,无关或没必要使用的库尽可能不使用。
目前模块基本完成,更多功能可能会考虑未来需要时加入。
目前纯截图功能已经高度接近微信的截图,不过不包含截图后的编辑操作;因为具体编辑个人认为直接打开图片编辑器编辑更方便,没必要写一个图片编辑功能;
基础功能演示:
主要功能包括:
①基本的截图后等待,可继续调整上下左右+对角位置(类似微信);
②打开图片文件,可以直接显示在面板上;
③选择保存文件。对截取过的图片进行翻页查看不同截图;
④删除图片。对于截取过的图片进行删除;当然只是删除内存中图片引用;
窗口属性设置了topmost=True, 即无论怎么打开其他窗口,该窗口都始终置于顶部。这是为了方便我们对截图后的图片放置到一侧,方便参照图片进行操作。
代码经过重构,具备一定的可读性以及可拓展性。虽然还有很多不足,但已经相对优美了;
完整代码如下,单文件,请自行安装PIL模块,在Windows环境上运行。
import ctypes
import tkinter as tk
from tkinter import messagebox, filedialog
from PIL import Image, ImageGrab, ImageTk, UnidentifiedImageError
ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)
ctypes.windll.shcore.SetProcessDpiAwareness(1)
class FlatButton(tk.Label):
def __init__(
self, parent, command=None, enter_fg="#000000",
click_color="#25C253", *args, **kwargs
):
super().__init__(parent, *args, **kwargs)
self.__fg = fg = kwargs.get("fg", "#3B3B3B")
self.__enter_fg = enter_fg
self.__click_fg = click_color
self.command = command
self.config(cursor="hand2")
self.bind("<Enter>", lambda _: self.config(fg=enter_fg))
self.bind("<Leave>", lambda _: self.config(fg=fg))
self.bind("<Button-1>", lambda _: self.config(fg=click_color))
self.bind("<ButtonRelease-1>", self.__command)
if fg == enter_fg:
raise ValueError("enter_fg must be different from fg")
def __command(self, event):
try:
if self.cget("fg") in (self.__enter_fg, self.__click_fg):
self.command(event)
self.config(fg=self.__fg)
except tk.TclError:
pass
except TypeError:
self.config(fg=self.__fg)
class AdjustableRect(object):
"""
The judgement seq is so important that you must care about:
(right, bottom), (left, top), (right, top), (left, bottom),
(center_x, top), (center_x, bottom), (left, center_y, ), (right, center_y)
"""
ANCHOR_SIZE = 3
ANCHOR_HOVER_DISTANCE = 20
CURSOR_FILES_NAME = ["aero_nwse_l.cur", "aero_nesw_l.cur", "aero_ns_l.cur", "aero_ew_l.cur"]
CURSOR_FILES = [f"@C:/Windows/Cursors/{cursor_file}" for cursor_file in CURSOR_FILES_NAME]
CURSORS = [
CURSOR_FILES[0], CURSOR_FILES[0], CURSOR_FILES[1], CURSOR_FILES[1],
CURSOR_FILES[2], CURSOR_FILES[2], CURSOR_FILES[3], CURSOR_FILES[3],
"fleur", "arrow"
]
def __init__(self, parent, screenshot):
self.parent: tk.Canvas = parent
self.screenshot: ScreenshotUtils = screenshot
self.__rect: int = 0
self.__anchors: list[int] = []
self.anchor_id: int = 0
def rect_coords(self) -> tuple[int, int, int, int]:
try:
return self.parent.coords(self.__rect)
except tk.TclError:
return [
min(self.screenshot.start_x, self.screenshot.end_x),
min(self.screenshot.start_y, self.screenshot.end_y),
max(self.screenshot.start_x, self.screenshot.end_x),
max(self.screenshot.start_y, self.screenshot.end_y)
]
def anchor_coords(self) -> tuple[int, int, int, int]:
left, top, right, bottom = self.rect_coords()
horizontal_middle = (left + right) // 2
vertical_middle = (top + bottom) // 2
return (
(left, top), (horizontal_middle, top), (right, top), (right, vertical_middle),
(right, bottom), (horizontal_middle, bottom), (left, bottom), (left, vertical_middle)
)
def get_anchor(self, event) -> int:
cls = self.__class__
left, top, right, bottom = self.rect_coords()
center_x, center_y = (left + right) // 2, (top + bottom) // 2
def near(actual, target):
return abs(actual - target) < cls.ANCHOR_HOVER_DISTANCE
# 务必注意这个判断顺序,这与后面rect_adjust密切相关
judgement_pos = (
(right, bottom), (left, top), (right, top), (left, bottom),
(center_x, top), (center_x, bottom), (left, center_y, ), (right, center_y)
)
for index, pos in enumerate(judgement_pos):
if near(event.x, pos[0]) and near(event.y, pos[1]):
return index
if left < event.x < right and top < event.y < bottom:
return 8
return -1
def create_anchors(self):
cls = self.__class__
for coord in self.anchor_coords():
anchor = self.parent.create_rectangle(
coord[0]-cls.ANCHOR_SIZE, coord[1]-cls.ANCHOR_SIZE,
coord[0]+cls.ANCHOR_SIZE, coord[1]+cls.ANCHOR_SIZE,
fill="#1AAE1A", outline="#1AAE1A"
)
self.__anchors.append(anchor)
def move_anchors(self):
cls = self.__class__
for anchor, coord in zip(self.__anchors, self.anchor_coords()):
self.parent.coords(
anchor, coord[0]-cls.ANCHOR_SIZE, coord[1]-2,
coord[0]+cls.ANCHOR_SIZE, coord[1]+cls.ANCHOR_SIZE
)
def on_press(self, event):
self.screenshot.start_x = event.x
self.screenshot.start_y = event.y
self.__rect= self.parent.create_rectangle(self.screenshot.start_x, self.screenshot.start_y, self.screenshot.start_x, self.screenshot.start_y, outline='#1AAE1A', width=2)
self.create_anchors()
def on_release(self, _):
self.screenshot.start_x, self.screenshot.start_y,\
self.screenshot.end_x, self.screenshot.end_y = self.rect_coords()
def on_hover(self, event):
self.anchor_id = self.get_anchor(event)
cursor = self.CURSORS[self.anchor_id]
self.parent.config(cursor=cursor)
def move_rect(self, event):
offset_x = event.x - self.screenshot.move_start_x
offset_y = event.y - self.screenshot.move_start_y
self.screenshot.start_x += offset_x
self.screenshot.start_y += offset_y
self.screenshot.end_x += offset_x
self.screenshot.end_y += offset_y
self.screenshot.move_start_x = event.x
self.screenshot.move_start_y = event.y
self.parent.coords(self.__rect, self.screenshot.start_x, self.screenshot.start_y, self.screenshot.end_x, self.screenshot.end_y)
self.move_anchors()
def rect_adjust(self, event):
if self.anchor_id == 8:
return self.move_rect(event)
if self.anchor_id == 0:
self.screenshot.end_x, self.screenshot.end_y = event.x, event.y
elif self.anchor_id == 1:
self.screenshot.start_x, self.screenshot.start_y = event.x, event.y
elif self.anchor_id == 2:
self.screenshot.end_x, self.screenshot.start_y = event.x, event.y
elif self.anchor_id == 3:
self.screenshot.start_x, self.screenshot.end_y = event.x, event.y
elif self.anchor_id == 4:
self.screenshot.start_y = event.y
elif self.anchor_id == 5:
self.screenshot.end_y = event.y
elif self.anchor_id == 6:
self.screenshot.start_x = event.x
elif self.anchor_id == 7:
self.screenshot.end_x = event.x
else:
return
self.parent.coords(self.__rect, self.screenshot.start_x, self.screenshot.start_y, self.screenshot.end_x, self.screenshot.end_y)
self.move_anchors()
class ScreenshotUtils(object):
"""
截图的关键是坐标;这个类管理着图片的引用和截图坐标;
"""
def TkS(value) -> int:
return int(ScaleFactor/100*value)
ZOOM: int = 4
ZOOM_WIDTH: float = TkS(28.75)
ZOOM_SCREEN_SIZE: int = int(ZOOM_WIDTH*ZOOM)
MAGNIFIER_OFFSET: int = 36
WIDTH_HEIGHT_OFFSET = 40
POS_TAG_GAP = 10
RGB_TAG_GAP = 47
MAGNIFIER_ADJUST = 70
AJUST_BAR_WIDTH: int = TkS(100)
# 截图相关变量
def __init__(self):
self.start_x = self.start_y = self.end_x = self.end_y = 0
self.move_start_x = self.move_start_y = self.move_end_x = self.move_end_y = 0
self.current_image = None
self.pixel_reader = None
self.final_images = list()
# 这种是只移动但不改变大小和内容的控件,只需移动无需重绘
self.screenshot_move_widget = list()
# 这种是移动和改变大小的控件,需要实时重绘
self.screenshot_redraw_widget = list()
@staticmethod
def TkS(value) -> int:
return int(ScaleFactor/100*value)
@classmethod
def move_widget_coords(cls, x, y) -> list[tuple[int, int, int, int]]:
# 按照主框架,水平线,垂直线的顺序返回坐标
main_frame_coord = (x, y, x+cls.ZOOM_SCREEN_SIZE, y+cls.ZOOM_SCREEN_SIZE)
horrontal_line_coord = (x, y+cls.ZOOM_SCREEN_SIZE // 2, x+cls.ZOOM_SCREEN_SIZE, y+cls.ZOOM_SCREEN_SIZE // 2)
vertical_line_coord = (x+cls.ZOOM_SCREEN_SIZE // 2, y, x+cls.ZOOM_SCREEN_SIZE // 2, y+cls.ZOOM_SCREEN_SIZE)
return [main_frame_coord, horrontal_line_coord, vertical_line_coord]
def redraw_widget_coords(self, x, y) -> list[tuple]:
# 按照"放大镜图像"、"长 × 宽"、"POS标签"、"RGB标签"的顺序返回坐标
offset = self.__class__.MAGNIFIER_OFFSET
zoom_size = self.__class__.ZOOM_SCREEN_SIZE
if x + offset + zoom_size < SCREEN_WIDTH:
x_offset = x + offset
else:
x_offset = x - offset - zoom_size
if y + offset + zoom_size + self.__class__.MAGNIFIER_ADJUST < SCREEN_HEIGHT:
y_offset = y + offset
else:
y_offset = y - offset - zoom_size - self.__class__.MAGNIFIER_ADJUST
width_height_y = max(min(self.start_y, self.end_y) - self.__class__.WIDTH_HEIGHT_OFFSET, 0)
width_height_info = (max(min(self.start_x, self.end_x), 0), width_height_y)
magnifier_coord = (x_offset, y_offset)
pos_info = (x_offset, y_offset + zoom_size + self.__class__.POS_TAG_GAP)
rgb_info = (x_offset, y_offset + zoom_size + self.__class__.RGB_TAG_GAP)
return [magnifier_coord, width_height_info, pos_info, rgb_info]
class MainUI(tk.Tk):
def __init__(self):
super().__init__()
self.screenshot = ScreenshotUtils()
self.set_window()
self.menu_bar: tk.Frame = self.set_menubar()
self.cut_btn: FlatButton = self.set_cut_btn()
self.load_image_btn: FlatButton = self.set_load_image_btn()
self.save_btn: FlatButton = self.set_save_btn()
self.turn_left_btn: FlatButton = self.set_turn_left_btn()
self.turn_right_btn: FlatButton = self.set_turn_right_btn()
self.delete_btn: FlatButton = self.set_delete_btn()
self.show_image_canvas: tk.Canvas = self.set_show_image_canvas()
self.full_screenshot_canvas: tk.Canvas = None
self.adjust_rect: AdjustableRect = None
self.adjust_bar: tk.Frame = None
def set_window(self):
self.title("截图工具")
self.attributes("-topmost", True)
self.geometry(f"{self.screenshot.TkS(240)}x{self.screenshot.TkS(30)}")
def set_menubar(self) -> tk.Frame:
menubar = tk.Frame(self, bg="#FFFFFF", height=30)
menubar.pack(fill=tk.X)
return menubar
def set_cut_btn(self) -> FlatButton:
btn_cut = FlatButton(
self.menu_bar, text="✂",
bg="#FFFFFF", font=("Segoe UI Emoji", 18),
)
btn_cut.pack(side=tk.LEFT, padx=5)
return btn_cut
def set_load_image_btn(self) -> FlatButton:
btn_load = FlatButton(self.menu_bar, text="📄", bg="#FFFFFF", font=("Segoe UI Emoji", 18))
btn_load.pack(side=tk.LEFT, padx=5)
return btn_load
def set_save_btn(self) -> FlatButton:
btn_save = FlatButton(
self.menu_bar, text="💾", bg="#FFFFFF", font=("Segoe UI Emoji", 18),
)
btn_save.pack(side=tk.LEFT, padx=5)
return btn_save
def set_turn_left_btn(self) -> FlatButton:
turn_left_btn = FlatButton(
self.menu_bar, text="\u25C0", bg="#FFFFFF", font=("Segoe UI Emoji", 18),
)
turn_left_btn.pack(side=tk.LEFT, padx=5)
return turn_left_btn
def set_turn_right_btn(self) -> FlatButton:
turn_page_btn = FlatButton(
self.menu_bar, text="\u25B6", bg="#FFFFFF", font=("Segoe UI Emoji", 18),
)
turn_page_btn.pack(side=tk.LEFT, padx=5)
return turn_page_btn
def set_delete_btn(self) -> FlatButton:
delete_btn = FlatButton(
self.menu_bar, text="🗑︎", bg="#FFFFFF", font=("Segoe UI Emoji", 18),
)
delete_btn.pack(side=tk.LEFT, padx=5)
return delete_btn
def set_cancel_btn(self, parent) -> FlatButton:
cancel_btn = FlatButton(
parent, self.clear_capture_info, text="×", bg="#FFFFFF",
enter_fg="#DB1A21",fg="#CC181F", font=("微软雅黑", 18)
)
cancel_btn.pack(side=tk.RIGHT, padx=5)
return cancel_btn
def set_confirm_btn(self, parent) -> FlatButton:
confirm_btn = FlatButton(
parent, self.confirm_capture, fg="#23B34C", text="√",
enter_fg="#27C956", bg="#FFFFFF", font=("微软雅黑", 18)
)
return confirm_btn
def set_show_image_canvas(self) -> tk.Canvas:
canvas = tk.Canvas(self, bg="white")
return canvas
def set_adjust_bar(self) -> tk.Frame:
self.adjust_bar = tk.Frame(self.full_screenshot_canvas, bg="#FFFFFF", height=50)
cancel_btn = self.set_cancel_btn(self.adjust_bar)
confirm_btn = self.set_confirm_btn(self.adjust_bar)
cancel_btn.pack(side=tk.RIGHT, padx=5)
confirm_btn.pack(side=tk.RIGHT, padx=10)
def set_magnifier_frame(self, event) -> None:
initial_coord = (0, 0, 0, 0)
main_frame_id = self.full_screenshot_canvas.create_rectangle(*initial_coord, outline='#1AAE1A', width=1)
horrontal_line = self.full_screenshot_canvas.create_line(*initial_coord, fill="#1AAE1A", width=2)
vertical_line = self.full_screenshot_canvas.create_line(*initial_coord, fill="#1AAE1A", width=2)
self.screenshot.screenshot_move_widget = [main_frame_id, horrontal_line, vertical_line]
event.x = event.x + event.widget.winfo_rootx()
event.y = event.y + event.widget.winfo_rooty()
self.update_magnifier(event)
def set_full_screenshot_canvas(self, parent) -> tk.Canvas:
img = ImageGrab.grab()
self.screenshot.current_image = img
self.screenshot.pixel_reader = img.convert("RGB")
photo = ImageTk.PhotoImage(img)
full_screenshot_canvas = tk.Canvas(parent, bg="white")
full_screenshot_canvas.create_image(0, 0, anchor=tk.NW, image=photo)
full_screenshot_canvas.image = photo
full_screenshot_canvas.pack(fill=tk.BOTH, expand=True)
return full_screenshot_canvas
def config_pos_rgb_info(
self, parent: tk.Canvas, pos: str, rgb: str,
pos_coord: tuple[int, int], rgb_coord: tuple[int, int]
) -> tuple[int]:
style = {"anchor": tk.NW, "font": ("微软雅黑", 9), "fill": "#FFFFFF"}
pos_info = parent.create_text(*pos_coord, text=pos, **style)
rgb_info = parent.create_text(*rgb_coord, text=rgb, **style)
pos_bg = parent.create_rectangle(*parent.bbox(pos_info), outline="#000000", fill="#000000")
rgb_bg = parent.create_rectangle(*parent.bbox(rgb_info), outline="#000000", fill="#000000")
parent.tag_raise(pos_info)
parent.tag_raise(rgb_info)
return pos_info, rgb_info, pos_bg, rgb_bg
class ScreenshotTool(MainUI):
def __init__(self):
super().__init__()
self.add_command()
self.page_index = 0
def add_command(self):
self.cut_btn.command = self.start_capture
self.load_image_btn.command = self.load_image
self.save_btn.command = self.save_image
self.turn_left_btn.command = self.turn_page
self.turn_right_btn.command = self.turn_page
self.delete_btn.command = self.delete_image
def start_capture(self, event):
self.attributes('-alpha', 0)
self.update()
self.capture_win = tk.Toplevel()
self.capture_win.geometry(f"{SCREEN_WIDTH}x{SCREEN_HEIGHT}+0+0")
self.capture_win.overrideredirect(True)
self.full_screenshot_canvas = self.set_full_screenshot_canvas(self.capture_win)
self.adjust_rect = AdjustableRect(self.full_screenshot_canvas, self.screenshot)
self.set_magnifier_frame(event)
self.set_adjust_bar()
self.full_screenshot_canvas.bind("<Button-1>", self.on_press)
self.full_screenshot_canvas.bind("<Motion>", self.update_magnifier)
self.full_screenshot_canvas.bind("<ButtonRelease-1>", self.on_release)
def on_press(self, event) -> None:
self.adjust_rect.on_press(event)
self.full_screenshot_canvas.unbind("<Motion>")
self.full_screenshot_canvas.bind("<Motion>", self.on_drag)
def on_drag(self, event) -> None:
self.adjust_rect.rect_adjust(event)
self.update_magnifier(event)
def on_release(self, event, resize=True) -> None:
self.unbind_all()
self.adjust_rect.on_release(event)
self.full_screenshot_canvas.bind("<Button-1>", self.start_move)
self.full_screenshot_canvas.bind("<Motion>", self.adjust_rect.on_hover)
self.adjust_bar.place(
x=min(self.screenshot.end_x - 300, SCREEN_WIDTH - 300), width=300,
y=max(min(self.screenshot.end_y + 10, SCREEN_HEIGHT - ScreenshotUtils.TkS(40)), 0),
)
if resize:
self.screenshot.end_x, self.screenshot.end_y = event.x, event.y
self.update_width_height_info(event)
def rect_adjust(self, event) -> None:
self.adjust_rect.rect_adjust(event)
if self.adjust_rect.anchor_id != 8 or self.adjust_rect.anchor_id == -1:
self.update_magnifier(event)
def unbind_all(self):
events = ("<Button-1>", "<Motion>", "<ButtonRelease-1>")
for event in events:
self.full_screenshot_canvas.unbind(event)
def clear_redraw_widget(self, redraw_widgets: list[int]):
for redraw_widget in redraw_widgets:
self.full_screenshot_canvas.delete(redraw_widget)
self.screenshot.screenshot_redraw_widget.clear()
def update_width_height_info(self, event) -> None:
if self.rect_adjust.anchor_id == 8:
self.clear_redraw_widget(self.screenshot.screenshot_redraw_widget)
else:
self.clear_redraw_widget(self.screenshot.screenshot_redraw_widget[1:])
w, h = abs(self.screenshot.end_x - self.screenshot.start_x), abs(self.screenshot.end_y - self.screenshot.start_y)
coord = self.screenshot.redraw_widget_coords(event.x, event.y)[1]
wh_info_widget = self.full_screenshot_canvas.create_text(*coord, anchor=tk.NW, fill="white", text=f"{w:.0f} × {h:.0f}")
self.screenshot.screenshot_redraw_widget = [wh_info_widget]
def update_magnifier(self, event, ) -> None:
x, y = event.x, event.y
size = ScreenshotUtils.ZOOM_WIDTH
img = self.screenshot.current_image.crop((x - size//2, y - size//2, x + size//2, y + size//2))
img = img.resize((ScreenshotUtils.ZOOM_SCREEN_SIZE, ScreenshotUtils.ZOOM_SCREEN_SIZE))
photo = ImageTk.PhotoImage(img)
self.full_screenshot_canvas.image2 = photo
w, h = abs(self.screenshot.end_x - self.screenshot.start_x), abs(self.screenshot.end_y - self.screenshot.start_y)
self.clear_redraw_widget(self.screenshot.screenshot_redraw_widget)
redraw_widget_coords = self.screenshot.redraw_widget_coords(x, y)
magnifier_coord, width_height_info, pos_coord, rgb_coord = redraw_widget_coords
zoom_img = self.full_screenshot_canvas.create_image(*magnifier_coord, anchor=tk.NW, image=photo)
wh_info_widget = self.full_screenshot_canvas.create_text(
*width_height_info, anchor=tk.NW, fill="white", text=f"{w:.0f} × {h:.0f}"
)
pos_rgb_info = self.config_pos_rgb_info(
self.full_screenshot_canvas, f"POS: ({x}, {y})",
f"RGB: {self.screenshot.pixel_reader.getpixel((x, y))}", pos_coord, rgb_coord
)
self.screenshot.screenshot_redraw_widget = [zoom_img, wh_info_widget, *pos_rgb_info]
self.update_magnifier_frame(*self.full_screenshot_canvas.coords(zoom_img))
def update_magnifier_frame(self, x, y) -> None:
coords = self.screenshot.move_widget_coords(x, y)
for widget, coord in zip(self.screenshot.screenshot_move_widget, coords):
self.full_screenshot_canvas.coords(widget, *coord)
self.full_screenshot_canvas.tag_raise(widget)
def start_move(self, event) -> None:
self.screenshot.move_start_x = event.x
self.screenshot.move_start_y = event.y
self.adjust_bar.place_forget()
for widget in self.screenshot.screenshot_redraw_widget:
self.full_screenshot_canvas.delete(widget)
for widget in self.screenshot.screenshot_move_widget:
self.full_screenshot_canvas.tag_lower(widget)
self.full_screenshot_canvas.bind("<B1-Motion>", self.rect_adjust)
self.full_screenshot_canvas.bind("<ButtonRelease-1>", lambda e: self.on_release(e, False))
def clear_capture_info(self, _) -> None:
self.capture_win.destroy()
self.full_screenshot_canvas.destroy()
self.attributes('-alpha', 1)
self.screenshot.screenshot_move_widget.clear()
def confirm_capture(self, event) -> None:
self.clear_capture_info(event)
x1, y1, x2, y2 = self.adjust_rect.rect_coords()
image = self.screenshot.current_image.crop((x1, y1, x2, y2))
result = self.show_image(image)
self.screenshot.final_images.append(result)
self.page_index = len(self.screenshot.final_images) - 1
self.attributes('-topmost', 1)
def show_image(self, image: Image.Image) -> None:
self.geometry(f"{max(image.width, ScreenshotUtils.TkS(240))}x{image.height+self.menu_bar.winfo_height()}")
photo = ImageTk.PhotoImage(image)
self.show_image_canvas.config(width=image.width, height=image.height)
self.show_image_canvas.delete("all")
self.show_image_canvas.create_image(0, 0, anchor=tk.NW, image=photo)
self.show_image_canvas.image = photo
self.show_image_canvas.pack()
return image
def load_image(self, _) -> None:
file_types = (("Image files", "*.jpg *.png *.jpeg"),)
img_path = filedialog.askopenfilename(filetypes=file_types)
if not img_path:
return
try:
image = Image.open(img_path)
except UnidentifiedImageError:
return messagebox.showerror("错误", "无法识别该图片文件!")
self.show_image(image)
self.screenshot.final_images.append(image)
self.page_index = len(self.screenshot.final_images) - 1
def save_image(self, _) -> None:
try:
image = self.screenshot.final_images[self.page_index]
filename = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg")],
initialfile=f"{image.width}x{image.height}.png"
)
if not filename:
return
image.save(filename)
except IndexError:
messagebox.showerror("保存失败", "未检测到截取图像")
def turn_page(self, event) -> None:
if len(self.screenshot.final_images) == 0:
return messagebox.showinfo("提示", "暂无图片可切换!")
if event.widget == self.turn_left_btn:
if self.page_index == 0:
return messagebox.showinfo("提示", "已经是第一张图片!")
self.page_index -= 1
else:
if self.page_index == len(self.screenshot.final_images) - 1:
return messagebox.showinfo("提示", "已经是最后一张图片!")
self.page_index += 1
self.show_image(self.screenshot.final_images[self.page_index])
def delete_image(self, _) -> None:
if len(self.screenshot.final_images) == 0:
return messagebox.showinfo("提示", "暂无图片可删除!")
if not messagebox.askokcancel("提示", "确认删除当前图片?"):
return
self.screenshot.final_images.pop(self.page_index)
if len(self.screenshot.final_images) == 0:
self.show_image_canvas.delete("all")
self.geometry(f"{self.screenshot.TkS(240)}x{self.screenshot.TkS(30)}")
else:
self.show_image(self.screenshot.final_images[self.page_index])
if __name__ == "__main__":
app = ScreenshotTool()
SCREEN_WIDTH = app.winfo_screenwidth()
SCREEN_HEIGHT = app.winfo_screenheight()
app.mainloop()