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

yizhihongxing

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实现随机加减法生成器

    下面是Python实现随机加减法生成器的攻略: 1. 准备 首先,我们需要使用Python进行编程,并安装random模块。打开命令行界面,输入以下命令进行安装: pip install random 2. 设计 其次,我们需要设计一个算法来生成随机加减法。我的想法是通过随机数生成两个加数或两个减数,然后再随机生成一个数,用于判断是进行加法还是减法。 代码示…

    python 2023年5月19日
    00
  • python实现冒泡排序算法的两种方法

    冒泡排序是一种简单的排序算法,它的基本思想是重复地遍历要排序的列表,比较相邻的两个元素,并按照大小交换它们的位置,直到整个列表都是有序的。在Python中,我们可以使用两种方法来实现冒泡排序算法。 方法一:使用两个循环实现冒泡排序 以下是使用两个循环实现冒泡排序的Python代码示例: def bubble_sort(arr): n = len(arr) f…

    python 2023年5月13日
    00
  • Python实现平行坐标图的两种方法小结

    Python实现平行坐标图的两种方法小结 简介 平行坐标图(Parallel Coordinates)是数据可视化的一种常用方法,它可以有效地展示高维数据的特征和关系。本文将介绍Python中实现平行坐标图的两种方法,并且提供两个示例说明这两种方法的使用。 方法一:使用plotly库 安装plotly库 要使用plotly库,首先需要安装它。可以使用pip进…

    python 2023年5月18日
    00
  • python3实现高效的端口扫描

    让我来详细讲解“Python3实现高效的端口扫描”的完整攻略。主要包括以下几个步骤: 步骤一:导入必要的模块和库 在Python中实现端口扫描需要用到socket、argparse和concurrent.futures这三个模块。其中socket是Python提供的网络编程模块;argparse是Python提供的命令行参数解析模块;concurrent.f…

    python 2023年6月3日
    00
  • Python tuple方法和string常量介绍

    Python Tuple方法介绍 Tuple是什么 Tuple是一种Python中的内置数据类型,常用于存储具有序的、不可更改(Immutable)的集合。 Tuple的基本操作 创建Tuple 在Python中,Tuple使用小括号()括起来,每个元素之间用逗号隔开。 示例代码: tup1 = (‘apple’, ‘orange’, ‘banana’) t…

    python 2023年6月5日
    00
  • Python Pandas读取Excel日期数据的异常处理方法

    在Python Pandas中,读取Excel日期数据时,可能会遇到一些异常情况,例如日期格式不一致、日期数据缺失等。本文将为您提供详的Python Pandas读取Excel日期数据的处理方法,包括如何处理日期格式不一致如何处理日期缺失等。 处理格式不一致 在读取Excel日期数据时可能会遇到日期格式不一致的情况。例如,有些单元格中的日期格式为“yyyy-…

    python 2023年5月14日
    00
  • Python 使用列表、字典和set

    Python 是一种广泛应用的编程语言,它提供了丰富的数据结构,包括列表、字典和集合。本篇攻略将详细介绍如何使用这三种数据结构。 列表 列表是 Python 中最常用的一种数据结构,通常用于存储一组有序的数据,可以包含任意类型的元素。列表可通过方括号 [] 来创建。 创建列表 例如,要创建包含整数 1、2、3、4、5 的列表,可以使用如下代码: number…

    python-answer 2023年3月25日
    00
  • python通过Windows下远程控制Linux系统

    下面是python通过Windows下远程控制Linux系统的完整攻略,包括两条示例说明。 背景 假设我们拥有一台运行Linux操作系统的远程服务器,我们需要通过Windows下的机器远程管理该服务器。如果我们使用SSH命令行工具来进行远程管理,可能会遇到以下一些限制: 手动输入SSH命令比较繁琐,且需要记忆一些命令,并且进行一些常规操作比如复制/粘贴文件等…

    python 2023年5月30日
    00
合作推广
合作推广
分享本页
返回顶部