Python基于tkinter canvas实现图片裁剪功能的攻略如下:
1. 准备工作
在使用canvas进行图片裁剪之前,我们需要导入必要的库,包括tkinter
、PIL
(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
对象,并在其中展示图片。我们可以利用Canvas
的create_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_stack
和cropped_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技术站