Python tkinter canvas实现图片裁剪
第一版、实现:tkinter 画布上显示图片,按下鼠标左键并且移动,实现截图
# -*- encoding=utf-8 -*- import os import tkinter as tk from PIL import Image from PIL import ImageTk left_mouse_down_x = 0 left_mouse_down_y = 0 left_mouse_up_x = 0 left_mouse_up_y = 0 sole_rectangle = None def left_mouse_down(event): # print('鼠标左键按下') global left_mouse_down_x, left_mouse_down_y left_mouse_down_x = event.x left_mouse_down_y = event.y def left_mouse_up(event): # print('鼠标左键释放') global left_mouse_up_x, left_mouse_up_y left_mouse_up_x = event.x left_mouse_up_y = event.y corp_img(img_path, 'img/one_corp.png', left_mouse_down_x, left_mouse_down_y, left_mouse_up_x, left_mouse_up_y) def moving_mouse(event): # print('鼠标左键按下并移动') global sole_rectangle global left_mouse_down_x, left_mouse_down_y moving_mouse_x = event.x moving_mouse_y = event.y if sole_rectangle is not None: canvas.delete(sole_rectangle) # 删除前一个矩形 sole_rectangle = canvas.create_rectangle(left_mouse_down_x, left_mouse_down_y, moving_mouse_x, moving_mouse_y, outline='red') def right_mouse_down(event): # print('鼠标右键按下') pass def right_mouse_up(event): # print('鼠标右键释放') pass def corp_img(source_path, save_path, x_begin, y_begin, x_end, y_end): if x_begin < x_end: min_x = x_begin max_x = x_end else: min_x = x_end max_x = x_begin if y_begin < y_end: min_y = y_begin max_y = y_end else: min_y = y_end max_y = y_begin save_path = os.path.abspath(save_path) if os.path.isfile(source_path): corp_image = Image.open(source_path) region = corp_image.crop((min_x, min_y, max_x, max_y)) region.save(save_path) print('裁剪完成,保存于:{}'.format(save_path)) else: print('未找到文件:{}'.format(source_path)) if __name__ == '__main__': pass win = tk.Tk() frame = tk.Frame() frame.pack() screenwidth = win.winfo_screenwidth() screenheight = win.winfo_screenheight() img_path = 'img/one.png' # img_path = 'img/bg.jpg' # img_path = 'img/test.jpg' # img_path = 'img/pic.gif' image = Image.open(img_path) image_x, image_y = image.size if image_x > screenwidth or image_y > screenheight: print('The picture size is too big,max should in:{}x{}, your:{}x{}'.format(screenwidth, screenheight, image_x, image_y)) img = ImageTk.PhotoImage(image) canvas = tk.Canvas(frame, width=image_x, height=image_y, bg='pink') i = canvas.create_image(0, 0, anchor='nw', image=img) canvas.pack() canvas.bind('<Button-1>', left_mouse_down) # 鼠标左键按下 canvas.bind('<ButtonRelease-1>', left_mouse_up) # 鼠标左键释放 canvas.bind('<Button-3>', right_mouse_down) # 鼠标右键按下 canvas.bind('<ButtonRelease-3>', right_mouse_up) # 鼠标右键释放 canvas.bind('<B1-Motion>', moving_mouse) # 鼠标左键按下并移动 win.mainloop()
原图one.png
运行
one_corp.png
2、第二版
import datetime import os from tkinter import * from tkinter import messagebox from tkinter.filedialog import askopenfilename from tkinter.ttk import * from PIL import Image from PIL import ImageTk def now(fmt='%Y%m%d%H%M%S'): string = datetime.datetime.now().strftime(fmt) return string def create_folder(folder): folder = os.path.abspath(folder) if not os.path.exists(folder): try: os.makedirs(folder) except Exception as e: msg = 'Failed to create folder({}), exception is({})'.format(folder, e) print(msg) def middle_windows(window, width=400, height=500, reset=False): # 设置窗口居中 screenwidth = window.winfo_screenwidth() # 屏幕宽度 screenheight = window.winfo_screenheight() # 屏幕高度 x = int((screenwidth - width) / 2) # x轴坐标 y = int((screenheight - height) / 2) # y轴坐标 window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) # 放置窗口 if not reset: window.resizable(0, 0) # 不可以最大化最小化 window.update() # 更新窗口 MIN_WIDTH = 1000 TITLE = '裁剪图片' IMG = None PHOTO_ENTRY = None LEVEL_WINDOW = None sole_rectangle = None left_mouse_down_x = 0 left_mouse_down_y = 0 left_mouse_up_x = 0 left_mouse_up_y = 0 img_path = None def choose_file(): global PHOTO_ENTRY filename = askopenfilename() if filename: filename = os.path.abspath(filename) PHOTO_ENTRY.delete(0, END) PHOTO_ENTRY.insert(END, filename) create_progressbar(filename) def close_level_window(): win.attributes('-disabled', False) LEVEL_WINDOW.destroy() def left_mouse_down(event): # print('鼠标左键按下') global left_mouse_down_x, left_mouse_down_y left_mouse_down_x = event.x left_mouse_down_y = event.y def corp_img(source_path, save_path, x_begin, y_begin, x_end, y_end): if x_begin < x_end: min_x = x_begin max_x = x_end else: min_x = x_end max_x = x_begin if y_begin < y_end: min_y = y_begin max_y = y_end else: min_y = y_end max_y = y_begin save_path = os.path.abspath(save_path) if os.path.isfile(source_path): corp_image = Image.open(source_path) region = corp_image.crop((min_x, min_y, max_x, max_y)) create_folder(os.path.dirname(save_path)) region.save(save_path) msg = '裁剪完成,保存于:{}'.format(save_path) messagebox.showinfo('结果', msg) else: print('未找到文件:{}'.format(source_path)) def left_mouse_up(event): # print('鼠标左键释放') global left_mouse_up_x, left_mouse_up_y left_mouse_up_x = event.x left_mouse_up_y = event.y corp_img(img_path, 'img/{}.png'.format(now()), left_mouse_down_x, left_mouse_down_y, left_mouse_up_x, left_mouse_up_y) def moving_mouse(event): # print('鼠标左键按下并移动') global sole_rectangle global left_mouse_down_x, left_mouse_down_y moving_mouse_x = event.x moving_mouse_y = event.y canvas = event.widget if sole_rectangle is not None: canvas.delete(sole_rectangle) # 删除前一个矩形 sole_rectangle = canvas.create_rectangle(left_mouse_down_x, left_mouse_down_y, moving_mouse_x, moving_mouse_y, outline='red', width=3) def create_top_level(width, height, path): print('width:{}'.format(width)) print('height:{}'.format(height)) global LEVEL_WINDOW win.attributes('-disabled', True) LEVEL_WINDOW = Toplevel(win) LEVEL_WINDOW.title(TITLE) middle_windows(LEVEL_WINDOW, width, height, reset=True) canvas = Canvas(LEVEL_WINDOW, width=width, height=height, bg='white') canvas.pack(expand=True, fill=BOTH) canvas.bind('<B1-Motion>', moving_mouse) # 鼠标左键按下并移动 canvas.bind('<Button-1>', left_mouse_down) # 鼠标左键按下 canvas.bind('<ButtonRelease-1>', left_mouse_up) # 鼠标左键释放 open_img(canvas, path) LEVEL_WINDOW.protocol("WM_DELETE_WINDOW", close_level_window) def analysis_photo(path, frame): global img_path img = Image.open(path) if img.width > MIN_WIDTH: rate = img.width / MIN_WIDTH width = int(img.width / rate) height = int(img.height / rate) crop_img = img.resize((width, height), Image.ANTIALIAS) new_name = os.path.abspath('tmp/img_tmp.jpg') create_folder(os.path.dirname(new_name)) crop_img.save(new_name) print('宽度大于:{},自动缩放,保存于:{}'.format(MIN_WIDTH, new_name)) else: width = img.width height = img.height new_name = path frame.destroy() img_path = new_name create_top_level(width, height, new_name) def open_img(canvas, path): global IMG IMG = ImageTk.PhotoImage(Image.open(path)) canvas.create_image(0, 0, image=IMG, anchor='nw') def create_progressbar(path): frame = Frame(win) frame.pack(pady=(50, 0)) label = Button(frame, text='正在解析', width=21) label.grid(row=0, column=0) progressbar = Progressbar(frame, mode='indeterminate', # mode must be determinate or indeterminate length=155, ) progressbar.grid(row=1, column=0, padx=(0, 0), pady=(20, 0)) progressbar.start() analysis_photo(path, frame) def create_top_frame(): global PHOTO_ENTRY frame = Frame(win) PHOTO_ENTRY = Entry(frame, width=40) PHOTO_ENTRY.grid(row=0, column=0) button = Button(frame, text='选择图片', command=choose_file) button.grid(row=0, column=1) frame.pack(pady=(50, 0)) if __name__ == '__main__': win = Tk() win.title(TITLE) middle_windows(win, 431, 242, True) create_top_frame() win.mainloop()
运行