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()

运行

posted @ 2020-10-29 17:54  南风丶轻语  阅读(1586)  评论(0编辑  收藏  举报