据我所知,内置的Tkinter画布类比例将不会自动缩放图像。如果无法使用自定义小部件,则可以在调用scale函数时缩放原始图像并将其替换到画布上。
下面的代码片段可以合并到原始类中。它执行以下操作:缓存Image.open()的结果。
添加一个redraw()函数来计算缩放的图像并将其添加到画布中,还删除以前绘制的图像(如果有的话)。
使用鼠标坐标作为图像放置的一部分。我只需将x and y传递给create_image函数,以显示当鼠标移动时图像位置如何移动。您可以用自己的中心/偏移计算来替换。
这使用了LinuxMouseWheels按钮4和5(您需要将其推广到Windows等)。
(已更新)代码:class GUI:
def __init__(self, root):
# ... omitted rest of initialization code
self.canvas.config(scrollregion=self.canvas.bbox(ALL))
self.scale = 1.0
self.orig_img = Image.open(File)
self.img = None
self.img_id = None
# draw the initial image at 1x scale
self.redraw()
# ... rest of init, bind buttons, pack frame
def zoom(self,event):
if event.num == 4:
self.scale *= 2
elif event.num == 5:
self.scale *= 0.5
self.redraw(event.x, event.y)
def redraw(self, x=0, y=0):
if self.img_id:
self.canvas.delete(self.img_id)
iw, ih = self.orig_img.size
size = int(iw * self.scale), int(ih * self.scale)
self.img = ImageTk.PhotoImage(self.orig_img.resize(size))
self.img_id = self.canvas.create_image(x, y, image=self.img)
# tell the canvas to scale up/down the vector objects as well
self.canvas.scale(ALL, x, y, self.scale, self.scale)
更新我做了一些不同规模的测试,发现resize/create_image使用了相当多的内存。我在一个32GB内存的MacPro上用540x375JPEG进行了测试。以下是用于不同比例因子的内存:1x (500, 375) 14 M
2x (1000, 750) 19 M
4x (2000, 1500) 42 M
8x (4000, 3000) 181 M
16x (8000, 6000) 640 M
32x (16000, 12000) 1606 M
64x (32000, 24000) ...
reached around ~7400 M and ran out of memory, EXC_BAD_ACCESS in _memcpy
鉴于上述情况,一个更有效的解决方案可能是确定显示图像的视窗大小,计算鼠标坐标中心周围的裁剪矩形,使用矩形裁剪图像,然后仅缩放裁剪部分。这应该使用常量内存来存储临时映像。否则,您可能需要使用第三方Tkinter控件来执行此裁剪/窗口缩放。
更新2工作但过于简单的裁剪逻辑,只是让您开始:def redraw(self, x=0, y=0):
if self.img_id: self.canvas.delete(self.img_id)
iw, ih = self.orig_img.size
# calculate crop rect
cw, ch = iw / self.scale, ih / self.scale
if cw > iw or ch > ih:
cw = iw
ch = ih
# crop it
_x = int(iw/2 - cw/2)
_y = int(ih/2 - ch/2)
tmp = self.orig_img.crop((_x, _y, _x + int(cw), _y + int(ch)))
size = int(cw * self.scale), int(ch * self.scale)
# draw
self.img = ImageTk.PhotoImage(tmp.resize(size))
self.img_id = self.canvas.create_image(x, y, image=self.img)
gc.collect()