学习软件开发的网站,wordpress作品集,简述网站建设优坏的评价标准,哪个网站专门做二手电脑手机的一、兼容局限性
这是用Python做的截图工具#xff0c;不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中C:/Windows/Cursors/中的.cur光标样式文件, 这个工具只适用于Windows环境#xff1b;
如果要提升其跨平台性的话#xff0c;需要考虑替换cty… 一、兼容局限性
这是用Python做的截图工具不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中C:/Windows/Cursors/中的.cur光标样式文件, 这个工具只适用于Windows环境
如果要提升其跨平台性的话需要考虑替换ctypes的一些专属于Windows的API以及设置不同的.cur访问方式 二、轻量化
该模块只使用了PIL这一个第三方库和别的使用pygame\pyautogui等模块不同该工具着重强调轻量化无关或没必要使用的库尽可能不使用。
目前截图功能已经高度接近微信截图不过没有编辑功能建议保存后再编辑里面包含了一些必备的快捷功能不过还没有绑定快捷键有需要者自行为代码中加入功能。 三、基础功能演示 功能演示 四、功能阐述
①基本的截图后等待可继续移动边框拖动调整上下左右对角位置类似微信
②打开图片文件可以直接显示在面板上
③复制图片文件到剪切板上
④保存当前视图上的图片。
⑤对截取过的图片进行翻页快速查看不同截图
⑥删除视图中的图片不影响磁盘文件只是删除内存中的图片引用
⑦通过调节窗口可动态调整图片在视图中的大小不改变根引用图片
⑧窗口置顶即无论怎么打开其他窗口该窗口都始终置于顶部不会被遮挡方便我们对截图后的图片放置到一侧参照图片进行操作。 五、完整代码
代码如下单文件请自行安装PIL模块确保在Windows环境上运行。
import os
import ctypes
import subprocess as sp
import tkinter as tk
from threading import Thread
from tkinter import messagebox, filedialog
from PIL import Image, ImageGrab, ImageTk, UnidentifiedImageErrorScaleFactor ctypes.windll.shcore.GetScaleFactorForDevice(0)
ctypes.windll.shcore.SetProcessDpiAwareness(1)
TEMP_FILE_PATH os.path.join(os.getenv(TEMP), tempScreenshot)
os.makedirs(TEMP_FILE_PATH, exist_okTrue)class FlatButton(tk.Label):def __init__(self, parent, commandNone, enter_fg#000000, click_color#25C253, *args, **kwargs):super().__init__(parent, *args, **kwargs)self.__fg fg kwargs.get(fg, #3B3B3B)self.__enter_fg enter_fgself.__click_fg click_colorself.command commandself.config(cursorhand2, fgfg)self.enable()if fg enter_fg:raise ValueError(enter_fg must be different from fg)def enable(self):self.bind(Enter, lambda _: self.config(fgself.__enter_fg))self.bind(Leave, lambda _: self.config(fgself.__fg))self.bind(Button-1, lambda _: self.config(fgself.__click_fg))self.bind(ButtonRelease-1, self.__command)def disable(self):for event in (Enter, Leave, Button-1, ButtonRelease-1):self.unbind(event)def __command(self, event):try:if self.cget(fg) in (self.__enter_fg, self.__click_fg):self.command(event)self.config(fgself.__fg)except tk.TclError:passexcept TypeError:self.config(fgself.__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 3ANCHOR_HOVER_DISTANCE 20CURSOR_FILES_NAME [aero_nwse_l.cur, aero_nesw_l.cur, aero_ns_l.cur, aero_ew_l.cur]CURSOR_FILES [fC:/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 parentself.screenshot: ScreenshotUtils screenshotself.__rect: int 0self.__anchors: list[int] []self.anchor_id: int 0def rect_coords(self) - tuple[int, int, int, int]:return self.parent.coords(self.__rect)def anchor_coords(self) - tuple[int, int, int, int]:left, top, right, bottom self.rect_coords()horizontal_middle (left right) // 2vertical_middle (top bottom) // 2return ((left, top), (horizontal_middle, top), (right, top), (right, vertical_middle),(right, bottom), (horizontal_middle, bottom), (left, bottom), (left, vertical_middle))def rect_width_height(self) - tuple[int, int]:left, top, right, bottom self.rect_coords()return int(right - left), int(bottom - top)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) // 2def 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 indexif left event.x right and top event.y bottom:return 8return -1def 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 create_rect(self) - None:self.__rect self.parent.create_rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, outline#1AAE1A, width2)self.create_anchors()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.xself.screenshot.start_y event.ydef 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(cursorcursor)def move_rect(self, event):offset_x event.x - self.screenshot.move_start_xoffset_y event.y - self.screenshot.move_start_yif self.screenshot.start_x offset_x 0 and self.screenshot.end_x offset_x SCREEN_WIDTH:self.screenshot.start_x offset_xself.screenshot.end_x offset_xif self.screenshot.start_y offset_y 0 and self.screenshot.end_y offset_y SCREEN_HEIGHT:self.screenshot.start_y offset_yself.screenshot.end_y offset_yself.screenshot.move_start_x event.xself.screenshot.move_start_y event.yself.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.yelif self.anchor_id 1:self.screenshot.start_x, self.screenshot.start_y event.x, event.yelif self.anchor_id 2:self.screenshot.end_x, self.screenshot.start_y event.x, event.yelif self.anchor_id 3:self.screenshot.start_x, self.screenshot.end_y event.x, event.yelif self.anchor_id 4:self.screenshot.start_y event.yelif self.anchor_id 5:self.screenshot.end_y event.yelif self.anchor_id 6:self.screenshot.start_x event.xelif self.anchor_id 7:self.screenshot.end_x event.xelse:returnself.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 4ZOOM_WIDTH: float TkS(28.75)ZOOM_SCREEN_SIZE: int int(ZOOM_WIDTH*ZOOM)MAGNIFIER_OFFSET: int 36WIDTH_HEIGHT_OFFSET 40POS_TAG_GAP 10RGB_TAG_GAP 47MAGNIFIER_ADJUST 70AJUST_BAR_WIDTH: int TkS(100)def __init__(self):self.start_x self.start_y self.end_x self.end_y 0self.move_start_x self.move_start_y self.move_end_x self.move_end_y 0self.page_index: int 0self.current_image: Image.Image Noneself.pixel_reader Noneself.final_images: list[Image.Image] list()# 这种是只移动但不改变大小和内容的控件只需移动无需重绘self.screenshot_move_widget list()# 这种是移动和改变大小的控件需要实时重绘self.screenshot_redraw_widget list()staticmethoddef TkS(value) - int:return int(ScaleFactor/100*value)classmethoddef move_widget_coords(cls, x, y) - list[tuple[int, int, int, int]]:# 按照主框架水平线垂直线的顺序返回坐标main_frame_coord (x, y, xcls.ZOOM_SCREEN_SIZE, ycls.ZOOM_SCREEN_SIZE)horrontal_line_coord (x, ycls.ZOOM_SCREEN_SIZE // 2, xcls.ZOOM_SCREEN_SIZE, ycls.ZOOM_SCREEN_SIZE // 2)vertical_line_coord (xcls.ZOOM_SCREEN_SIZE // 2, y, xcls.ZOOM_SCREEN_SIZE // 2, ycls.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_OFFSETzoom_size self.__class__.ZOOM_SCREEN_SIZEif x offset zoom_size SCREEN_WIDTH:x_offset x offsetelse:x_offset x - offset - zoom_sizeif y offset zoom_size self.__class__.MAGNIFIER_ADJUST SCREEN_HEIGHT:y_offset y offsetelse:y_offset y - offset - zoom_size - self.__class__.MAGNIFIER_ADJUSTwidth_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.copy_btn: FlatButton self.set_copy_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.capture_win: tk.Toplevel Noneself.full_screenshot_canvas: tk.Canvas Noneself.adjust_rect: AdjustableRect Noneself.adjust_bar: tk.Frame Nonedef set_window(self):self.title(截图工具)width, height self.screenshot.TkS(255), self.screenshot.TkS(30)self.minsize(widthwidth, heightheight) # 这里可以根据需要调整最小宽高self.attributes(-topmost, True)self.geometry(f{width}x{height})def set_menubar(self) - tk.Frame:menubar tk.Frame(self, bg#FFFFFF, heightScreenshotUtils.TkS(30))menubar.pack(filltk.X)menubar.pack_propagate(False) # 阻止内部组件改变框架大小return menubardef set_cut_btn(self) - FlatButton:btn_cut FlatButton(self.menu_bar, text✂, bg#FFFFFF, font(Segoe UI Emoji, 18),)btn_cut.pack(sidetk.LEFT, ipadx0.1)return btn_cutdef set_load_image_btn(self) - FlatButton:btn_load FlatButton(self.menu_bar, text, bg#FFFFFF,font(Segoe UI Emoji, 18, bold))btn_load.pack(sidetk.LEFT, ipadx0.1)return btn_loaddef set_copy_btn(self) - FlatButton:btn_copy FlatButton(self.menu_bar, text⎘, bg#FFFFFF, font(Segoe UI Symbol, 26),)btn_copy.pack(sidetk.LEFT, ipadx0.1)return btn_copydef set_save_btn(self) - FlatButton:btn_save FlatButton(self.menu_bar, text, bg#FFFFFF, font(Segoe UI Emoji, 18),)btn_save.pack(sidetk.LEFT, ipadx0.1)return btn_savedef 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(sidetk.LEFT, ipadx0.1)return turn_left_btndef 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(sidetk.LEFT, ipadx0.1)return turn_page_btndef set_delete_btn(self) - FlatButton:delete_btn FlatButton(self.menu_bar, text, bg#FFFFFF, font(Segoe UI Symbol, 26, bold),)delete_btn.pack(sidetk.LEFT, ipadx0.1)return delete_btndef set_cancel_btn(self, parent) - FlatButton:cancel_btn FlatButton(parent, self.clear_capture_info, text×, bg#FFFFFF,enter_fg#DB1A21,fg#CC181F, font(微软雅黑, 20))cancel_btn.pack(sidetk.RIGHT, padx5)return cancel_btndef set_confirm_btn(self, parent) - FlatButton:confirm_btn FlatButton(parent, self.confirm_capture, fg#23B34C, text√,enter_fg#27C956, bg#FFFFFF, font(微软雅黑, 20))confirm_btn.pack(sidetk.RIGHT, padx10)return confirm_btndef set_show_image_canvas(self) - tk.Canvas:canvas tk.Canvas(self, bgwhite)return canvasdef set_adjust_bar(self) - tk.Frame:self.adjust_bar tk.Frame(self.full_screenshot_canvas, bg#FFFFFF, height50)cancel_btn self.set_cancel_btn(self.adjust_bar)confirm_btn self.set_confirm_btn(self.adjust_bar)cancel_btn.pack(sidetk.RIGHT, padx5)confirm_btn.pack(sidetk.RIGHT, padx10)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, width1)horrontal_line self.full_screenshot_canvas.create_line(*initial_coord, fill#1AAE1A, width2)vertical_line self.full_screenshot_canvas.create_line(*initial_coord, fill#1AAE1A, width2)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()def set_full_screenshot_canvas(self, parent) - tk.Canvas:img ImageGrab.grab()self.screenshot.current_image imgself.screenshot.pixel_reader img.convert(RGB)photo ImageTk.PhotoImage(img)full_screenshot_canvas tk.Canvas(parent, bgwhite, highlightthickness0)full_screenshot_canvas.create_image(0, 0, anchortk.NW, imagephoto)full_screenshot_canvas.image photofull_screenshot_canvas.pack(filltk.BOTH, expandTrue)return full_screenshot_canvasdef 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, textpos, **style)rgb_info parent.create_text(*rgb_coord, textrgb, **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_bgclass ScreenshotTool(MainUI):def __init__(self):super().__init__()self.add_command()def add_command(self):self.protocol(WM_DELETE_WINDOW, self.on_close)self.show_image_canvas.bind(Configure, self.auto_adjust_image_size)self.cut_btn.command self.start_captureself.load_image_btn.command self.load_imageself.copy_btn.command self.copy_imageself.save_btn.command self.save_imageself.turn_left_btn.command self.turn_pageself.turn_right_btn.command self.turn_pageself.delete_btn.command self.delete_imagedef initialize_screenshot_coords(self):self.is_drag Falseself.screenshot.start_x self.screenshot.start_y 0self.screenshot.end_x SCREEN_WIDTHself.screenshot.end_y SCREEN_HEIGHTdef 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}00)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.initialize_screenshot_coords()self.adjust_rect.create_rect()self.set_magnifier_frame(event)self.update_magnifier(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, resizeTrue) - None:self.unbind_all()self.adjust_rect.on_release(event)self.full_screenshot_canvas.bind(Button-1, self.enter_adjust_mode)self.full_screenshot_canvas.bind(Motion, self.adjust_rect.on_hover)self.adjust_bar.place(xmin(self.screenshot.end_x - 300, SCREEN_WIDTH - 300), width300,ymax(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.yself.conceal_move_widget()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) - None:for redraw_widget in self.screenshot.screenshot_redraw_widget:self.full_screenshot_canvas.delete(redraw_widget)self.screenshot.screenshot_redraw_widget.clear()def conceal_move_widget(self):for widget in self.screenshot.screenshot_move_widget:self.full_screenshot_canvas.tag_lower(widget)def update_width_height_info(self, event) - None:self.clear_redraw_widget()w, h self.adjust_rect.rect_width_height()coord self.screenshot.redraw_widget_coords(event.x, event.y)[1]wh_info_widget self.full_screenshot_canvas.create_text(*coord, anchortk.NW, fillwhite, textf{w} × {h})self.screenshot.screenshot_redraw_widget [wh_info_widget]def update_magnifier(self, event, ) - None:x, y event.x, event.ysize ScreenshotUtils.ZOOM_WIDTHimg 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 photow, h self.adjust_rect.rect_width_height()self.clear_redraw_widget()redraw_widget_coords self.screenshot.redraw_widget_coords(x, y)magnifier_coord, width_height_info, pos_coord, rgb_coord redraw_widget_coordszoom_img self.full_screenshot_canvas.create_image(*magnifier_coord, anchortk.NW, imagephoto)wh_info_widget self.full_screenshot_canvas.create_text(*width_height_info, anchortk.NW, fillwhite, textf{w} × {h})pos_rgb_info self.config_pos_rgb_info(self.full_screenshot_canvas, fPOS: ({x}, {y}), fRGB: {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 enter_adjust_mode(self, event) - None:self.screenshot.move_start_x event.xself.screenshot.move_start_y event.yself.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 check_capture_screenshot(self) - None:if self.screenshot.start_x self.screenshot.end_x or \self.screenshot.start_y self.screenshot.end_y:self.initialize_screenshot_coords()def confirm_capture(self, event) - None:x1, y1, x2, y2 self.adjust_rect.rect_coords()self.clear_capture_info(event)image self.screenshot.current_image.crop((x1, y1, x2, y2))result self.show_image(image)self.screenshot.final_images.append(result)self.screenshot.page_index len(self.screenshot.final_images) - 1self.attributes(-topmost, 1)def show_image(self, image: Image.Image, window_resizeTrue) - None:if window_resize:self.geometry(f{image.width}x{image.heightself.menu_bar.winfo_height()})photo ImageTk.PhotoImage(image)self.show_image_canvas.delete(all)self.show_image_canvas.create_image(0, 0, anchortk.NW, imagephoto)self.show_image_canvas.image photoself.show_image_canvas.pack(filltk.BOTH, expandTrue)return imagedef current_limiting(self, canvas_w, canvas_h) - bool:if not self.screenshot.final_images:return Truetry:coords self.show_image_canvas.bbox(all)img_view_w, img_view_h coords[2], coords[3]except TypeError:return Trueif (img_view_w canvas_w and img_view_h canvas_h) or \(img_view_h canvas_h and img_view_w canvas_w):return Truereturn Falsedef auto_adjust_image_size(self, _) - None:canvas_w self.show_image_canvas.winfo_width()canvas_h self.show_image_canvas.winfo_height()if self.current_limiting(canvas_w, canvas_h):returnimage self.screenshot.final_images[self.screenshot.page_index]width_ratio canvas_w / image.widthheight_ratio canvas_h / image.heightratio min(width_ratio, height_ratio)new_width int(image.width * ratio)new_height int(image.height * ratio)resized_image image.resize((new_width, new_height), Image.LANCZOS)self.show_image(resized_image, False)def load_image(self, _) - None:file_types ((Image files, *.jpg *.png *.jpeg),)img_path filedialog.askopenfilename(filetypesfile_types)if not img_path:returntry:image Image.open(img_path)except UnidentifiedImageError:return messagebox.showerror(错误, 无法识别该图片文件!)self.show_image(image)self.screenshot.final_images.append(image)self.screenshot.page_index len(self.screenshot.final_images) - 1def copy_image(self, _) - None:def __copy_image():self.copy_btn.disable()self.copy_btn.config(fg#25C253)image self.screenshot.final_images[self.screenshot.page_index]temp_name f{int.from_bytes(os.urandom(4), byteorderbig)}.pngtemp_file os.path.join(TEMP_FILE_PATH, temp_name)image.save(temp_file)startupinfo sp.STARTUPINFO()startupinfo.dwFlags | sp.STARTF_USESHOWWINDOWargs [powershell, fGet-Item {temp_file} | Set-Clipboard]process sp.Popen(argsargs, startupinfostartupinfo)process.wait()self.title(截图工具)self.copy_btn.enable()self.copy_btn.config(fg#3B3B3B)if len(self.screenshot.final_images) 0:return messagebox.showerror(复制失败, 未检测到截取图像)self.title(复制成功!)Thread(target__copy_image, daemonTrue).start()def save_image(self, _) - None:try:image self.screenshot.final_images[self.screenshot.page_index]filename filedialog.asksaveasfilename(defaultextension.png,filetypes[(PNG files, *.png), (JPEG files, *.jpg)],initialfilef{image.width}x{image.height}.png)if not filename:returnimage.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.screenshot.page_index 0:return messagebox.showinfo(提示, 已经是第一张图片!)self.screenshot.page_index - 1else:if self.screenshot.page_index len(self.screenshot.final_images) - 1:return messagebox.showinfo(提示, 已经是最后一张图片!)self.screenshot.page_index 1self.show_image(self.screenshot.final_images[self.screenshot.page_index])def delete_image(self, _) - None:if len(self.screenshot.final_images) 0:return messagebox.showinfo(提示, 暂无图片可删除!)if not messagebox.askokcancel(提示, 确认删除当前图片?):returnself.screenshot.final_images.pop(self.screenshot.page_index)if self.screenshot.page_index len(self.screenshot.final_images):self.screenshot.page_index - 1if len(self.screenshot.final_images) 0:self.show_image_canvas.delete(all)self.geometry(f{self.screenshot.TkS(255)}x{self.screenshot.TkS(30)})else:self.show_image(self.screenshot.final_images[self.screenshot.page_index])def on_close(self):def delete_tmp_files():for file in os.scandir(TEMP_FILE_PATH):os.remove(file)self.destroy()Thread(targetdelete_tmp_files).start()if __name__ __main__:app ScreenshotTool()SCREEN_WIDTH app.winfo_screenwidth()SCREEN_HEIGHT app.winfo_screenheight()app.mainloop() 六、打包程序
如无Python环境可以通过以下链接下载 链接https://pan.quark.cn/s/f87bf5f9e825 提取码nMGP