Python基于tkinter canvas实现图片裁剪功能

Python基于tkinter canvas实现图片裁剪功能的攻略如下:

1. 准备工作

在使用canvas进行图片裁剪之前,我们需要导入必要的库,包括tkinterPIL(Python Imaging Library,用于处理图片的库)。在命令行中输入以下代码进行安装:

pip install tkinter
pip install pillow

之后,我们需要在Python代码中导入这两个库:

from tkinter import *
from PIL import Image, ImageTk

2. 加载图片

首先,我们需要加载待裁剪的图片。在这里,我们可以使用PIL库中的Image类来加载图片。在加载图片时,我们需要把图片的路径传给Image类,并调用open方法来读取图片。读取完成后,我们可以使用ImageTk类将图片转化为Tkinter所支持的格式。

# 加载图片
img_path = "example.jpg"
img = Image.open(img_path)

# 将图片转换为Tkinter所支持的格式
tk_img = ImageTk.PhotoImage(img)

3. 创建canvas并展示图片

接下来,我们需要创建一个Canvas对象,并在其中展示图片。我们可以利用Canvascreate_image方法在画布中插入图片。

# 创建Canvas
canvas_width = 400
canvas_height = 400
canvas = Canvas(root, width=canvas_width, height=canvas_height)
canvas.pack()

# 在Canvas中插入图片
canvas.create_image(0, 0, anchor=NW, image=tk_img)

注意到这里我们的tk_img是前文中从PIL.Image转换而来的。anchor参数是表示图片的锚点,NW意味着左上角为起点。

现在打开运行程序,您可以看到一幅图片展示在界面中。

4. 裁剪图片

具体实现图片的裁剪,这里我们需要利用鼠标来绘制矩形,选取需要裁剪的区域。当鼠标按下之后,我们需要记录下鼠标的位置,并将长方形的起点设为这个位置。当鼠标拖动的时候,我们不断地更新长方形的大小和位置。最后当鼠标释放的时候,我们得到一个完整的长方形。接下来我们需要截取长方形内的像素,并保存为新的图片。

这里以第一个示例为例。我们需要在鼠标操作过程中实时绘制矩形。同时,为方便起见,我们定义了crop_image函数,并绑定到了“裁剪”按钮的事件上。

# 鼠标按下时记录起点,同时新绘制一个长方形
def on_button_press(event):
    # 保存起点位置
    global start_x, start_y
    start_x = canvas.canvasx(event.x)
    start_y = canvas.canvasy(event.y)

    # 创建一个新的矩形
    global cur_rect
    cur_rect = canvas.create_rectangle(
        start_x, start_y, 1, 1, outline='red', width=2)

# 鼠标拖动时更新长方形大小
def on_move_press(event):
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)

    # 长方形的区域
    canvas.coords(cur_rect, start_x, start_y, cur_x, cur_y)

# 鼠标释放时结束裁剪,并保存图片
def on_button_release(event):
    global start_x, start_y

    # 计算长方形的左上角和右下角坐标
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)
    x0 = min(start_x, cur_x)
    y0 = min(start_y, cur_y)
    x1 = max(start_x, cur_x)
    y1 = max(start_y, cur_y)

    # 裁剪图片
    cropped_img = img.crop((x0, y0, x1, y1))
    cropped_tk_img = ImageTk.PhotoImage(cropped_img)

    # 在新的窗口中展示裁剪后的图片
    new_window = Toplevel(root)
    new_window.title("Crop")
    new_canvas = Canvas(new_window, width=x1-x0, height=y1-y0)
    new_canvas.pack()
    new_canvas.create_image(0, 0, anchor=NW, image=cropped_tk_img)

    # 保存裁剪后的图片
    cropped_img.save("cropped.jpg")

同时,我们还需要在程序中绑定鼠标事件,并且创建一个按钮事件来触发裁剪操作:

# 绑定鼠标事件
canvas.bind("<ButtonPress-1>", on_button_press)
canvas.bind("<B1-Motion>", on_move_press)
canvas.bind("<ButtonRelease-1>", on_button_release)

# 创建一个“裁剪”按钮事件
def crop():
    on_button_release(None)
crop_button = Button(root, text="Crop", command=crop)
crop_button.pack()

5. 完整代码

第一个示例的完整代码如下:

from tkinter import *
from PIL import Image, ImageTk

# 加载图片
img_path = "example.jpg"
img = Image.open(img_path)

# 将图片转换为Tkinter所支持的格式
tk_img = ImageTk.PhotoImage(img)

# 创建Canvas
canvas_width = 400
canvas_height = 400
canvas = Canvas(root, width=canvas_width, height=canvas_height)
canvas.pack()

# 在Canvas中插入图片
canvas.create_image(0, 0, anchor=NW, image=tk_img)

# 鼠标按下时记录起点,同时新绘制一个长方形
def on_button_press(event):
    # 保存起点位置
    global start_x, start_y
    start_x = canvas.canvasx(event.x)
    start_y = canvas.canvasy(event.y)

    # 创建一个新的矩形
    global cur_rect
    cur_rect = canvas.create_rectangle(
        start_x, start_y, 1, 1, outline='red', width=2)

# 鼠标拖动时更新长方形大小
def on_move_press(event):
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)

    # 长方形的区域
    canvas.coords(cur_rect, start_x, start_y, cur_x, cur_y)

# 鼠标释放时结束裁剪,并保存图片
def on_button_release(event):
    global start_x, start_y

    # 计算长方形的左上角和右下角坐标
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)
    x0 = min(start_x, cur_x)
    y0 = min(start_y, cur_y)
    x1 = max(start_x, cur_x)
    y1 = max(start_y, cur_y)

    # 裁剪图片
    cropped_img = img.crop((x0, y0, x1, y1))
    cropped_tk_img = ImageTk.PhotoImage(cropped_img)

    # 在新的窗口中展示裁剪后的图片
    new_window = Toplevel(root)
    new_window.title("Crop")
    new_canvas = Canvas(new_window, width=x1-x0, height=y1-y0)
    new_canvas.pack()
    new_canvas.create_image(0, 0, anchor=NW, image=cropped_tk_img)

    # 保存裁剪后的图片
    cropped_img.save("cropped.jpg")

# 绑定鼠标事件
canvas.bind("<ButtonPress-1>", on_button_press)
canvas.bind("<B1-Motion>", on_move_press)
canvas.bind("<ButtonRelease-1>", on_button_release)

# 创建一个“裁剪”按钮事件
def crop():
    on_button_release(None)
crop_button = Button(root, text="Crop", command=crop)
crop_button.pack()

root.mainloop()

6. 第二个示例:添加撤销操作

第二个示例在第一个示例的基础上,添加了撤销操作。在进行裁剪操作时,用户可以利用Ctrl+Z快捷键撤销上一次操作。我们需要利用一个栈来记录所有的裁剪历史,并在进行撤销时取出最后一次裁剪。与第一个示例相比,这里引入了两个新的全局变量:cropped_img_stackcropped_tk_img_stack,分别用于记录裁剪历史。

示例代码如下:

from tkinter import *
from PIL import Image, ImageTk
import copy

# 加载图片
img_path = "example.jpg"
img = Image.open(img_path)

# 将图片转换为Tkinter所支持的格式
tk_img = ImageTk.PhotoImage(img)

# 创建Canvas
canvas_width = 400
canvas_height = 400
canvas = Canvas(root, width=canvas_width, height=canvas_height)
canvas.pack()

# 在Canvas中插入图片
canvas.create_image(0, 0, anchor=NW, image=tk_img)

# 记录裁剪历史的栈
cropped_img_stack = []
cropped_tk_img_stack = []
MAX_HISTORY = 10  # 最多记录10次历史记录

# 鼠标按下时记录起点,同时新绘制一个长方形
def on_button_press(event):
    # 保存起点位置
    global start_x, start_y
    start_x = canvas.canvasx(event.x)
    start_y = canvas.canvasy(event.y)

    # 创建一个新的矩形
    global cur_rect
    cur_rect = canvas.create_rectangle(
        start_x, start_y, 1, 1, outline='red', width=2)

# 鼠标拖动时更新长方形大小
def on_move_press(event):
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)

    # 长方形的区域
    canvas.coords(cur_rect, start_x, start_y, cur_x, cur_y)

# 鼠标释放时结束裁剪,并保存图片
def on_button_release(event):
    global start_x, start_y

    # 计算长方形的左上角和右下角坐标
    cur_x = canvas.canvasx(event.x)
    cur_y = canvas.canvasy(event.y)
    x0 = min(start_x, cur_x)
    y0 = min(start_y, cur_y)
    x1 = max(start_x, cur_x)
    y1 = max(start_y, cur_y)

    # 裁剪图片
    cropped_img = img.crop((x0, y0, x1, y1))
    cropped_tk_img = ImageTk.PhotoImage(cropped_img)

    # 在新的窗口中展示裁剪后的图片
    new_window = Toplevel(root)
    new_window.title("Crop")
    new_canvas = Canvas(new_window, width=x1-x0, height=y1-y0)
    new_canvas.pack()
    new_canvas.create_image(0, 0, anchor=NW, image=cropped_tk_img)

    # 保存裁剪后的图片
    cropped_img.save("cropped.jpg")

    # 记录裁剪历史
    cropped_img_stack.append(copy.deepcopy(img))
    cropped_tk_img_stack.append(copy.deepcopy(tk_img))
    if len(cropped_img_stack) > MAX_HISTORY:
        cropped_img_stack.pop(0)
        cropped_tk_img_stack.pop(0)

    # 更新原始图片为裁剪后的图片
    global img, tk_img
    img = cropped_img
    tk_img = cropped_tk_img
    canvas.delete("all")
    canvas.create_image(0, 0, anchor=NW, image=tk_img)

# 撤销操作
def undo(event):
    if len(cropped_img_stack) == 0:
        return

    # 取出上一次的裁剪历史并展示
    global img, tk_img
    img = cropped_img_stack.pop()
    tk_img = cropped_tk_img_stack.pop()
    canvas.delete("all")
    canvas.create_image(0, 0, anchor=NW, image=tk_img)

# 绑定鼠标事件
canvas.bind("<ButtonPress-1>", on_button_press)
canvas.bind("<B1-Motion>", on_move_press)
canvas.bind("<ButtonRelease-1>", on_button_release)

# 绑定快捷键事件
root.bind("<Control-z>", undo)

# 创建一个“裁剪”按钮事件
def crop():
    on_button_release(None)
crop_button = Button(root, text="Crop", command=crop)
crop_button.pack()

root.mainloop()

在这个示例中,我们使用了copy库的deepcopy函数来复制图片对象。在python中,对象之间的赋值(=img)通常会产生两个指向同一位置的指针,因此当修改指针指向对应位置时,会同时影响到被指向的两个指针。这里使用deepcopy函数可以完整地复制对象本身,而不是产生新的指针。

最后,我们利用root.bind将快捷键和对应的函数绑定在一起。

7. 结语

这就是Python基于tkinter canvas实现图片裁剪功能的全部攻略。希望这个教程可以帮助你更好地掌握canvas的基本用法,并能在需要时灵活运用canvas进行图片的裁剪。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python基于tkinter canvas实现图片裁剪功能 - Python技术站

(0)
上一篇 2023年6月13日
下一篇 2023年6月13日

相关文章

  • Python之string编码问题

    Python之string编码问题攻略 在Python中,字符串(string)是一种重要的数据类型,然而在处理字符串时,字符编码问题就变得非常重要。不同的编码系统可能会对同一个字符串产生不同的字符编码,因此需要了解Python的string编码问题。这里将介绍几个经典的Python中的字符编码问题,并提供一些解决方案。 1. Unicode和ASCII码 …

    python 2023年5月20日
    00
  • python实现识别手写数字 python图像识别算法

    下面是详细讲解“Python实现识别手写数字的图像识别算法”的完整攻略,包括算法原理、Python实现和两个示例。 算法原理 手写数字识别是图像识别的一个重要应用,其基本思想是将手写数字图像转换为数字特征向量,然后使用分类算法对其进行分类。常用的手写数字识别法包括KNN、SVM、神经网络等。其中,神经网络是一种非常有效的手写数字识别算法,其基本思想是通过多层…

    python 2023年5月14日
    00
  • Pyhton中单行和多行注释的使用方法及规范

    下面是Python中单行和多行注释的使用方法及规范的完整攻略。 单行注释 单行注释是用来在代码行后面添加注释的。在Python中,使用#符号来注释一行代码。被注释的内容不会被Python解释器执行,也不会影响程序的运行。 以下是单行注释的使用示例: # 这是一条单行注释 print(‘Hello, World!’) # 这是另一条单行注释 需要注意的是,每个…

    python 2023年5月20日
    00
  • Python转换HTML到Text纯文本的方法

    Python转换HTML到Text纯文本的方法 在本文中,我们将介绍如何使用Python将HTML转换为纯文本。我们将使用BeautifulSoup库来解析HTML,并使用get_text方法将HTML转换为纯文本。以下是详细的步骤和示例。 步骤1:安装必要的库 在使用Python将HTML转换为纯文本之前,我们需要安装必要的库。以下是安装必要库的步骤: p…

    python 2023年5月15日
    00
  • python3在各种服务器环境中安装配置过程

    安装Python3在各种服务器环境中可以分为以下几个步骤: 1.检查系统环境在进行Python3安装之前,建议先检查系统是否已经安装了Python2及其版本。可以通过命令行输入“python –version”进行检查。如果系统已经安装了Python2,可以通过编写Python2程序进行验证。 2.安装Python3可以到Python官网(https://…

    python 2023年5月18日
    00
  • 利用Seaborn绘制20个精美的pairplot图

    这里给出利用Seaborn绘制20个精美的pairplot图的完整攻略。 1. 确定数据集 首先,确定需要绘制的数据集,例如seaborn提供的自带数据集iris。 import seaborn as sns iris = sns.load_dataset(‘iris’) 2. 进行数据探索 接下来,可以对数据集进行初步探索,了解数据的特征和分布情况。 ir…

    python 2023年5月18日
    00
  • python3操作redis实现List列表实例

    Python3操作Redis实现List列表实例 Redis是一种高性能的键值存储数据库,支持多种数据结构,包括字符串、哈希、列表、集合和集合等。本文将详细介绍如何使用Python3操作Redis实List列表。 安装Redis 在使用Python3操作Redis之前,我们先安装Redis。可以在Redis官网下载最新版本的Redis,也使用Linux系统的…

    python 2023年5月13日
    00
  • 详解Python中List、Set和Tuple的区别

    Python中List、Set和Tuple是常用的三种数据类型,它们都可以存储一组数据。但是它们有一些重要的区别,下面我将详细讲解这些区别。 List List是Python内置的一种数据类型,它可以存储一组元素,元素可以是任何数据类型。List使用方括号[]来表示,每个元素用逗号分隔。 # 示例1:定义一个List my_list = [1, 2, 3, …

    python-answer 2023年3月25日
    00
合作推广
合作推广
分享本页
返回顶部