我正在为我的图像处理程序创建一个图像预览。因此,我使用tkinter canvas来显示、缩放和移动图像。为了节省内存,我想使用枕头裁剪图像并调整其大小,以便只显示可见部分。你知道吗
红色条纹的部分应该裁剪掉
为了移动图像,我使用了来自this question的技术,为了裁剪图像,我试图修改来自this question的代码
所以我最终得到了这段代码(尽量简化)
裁剪部分在重画功能中:
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
class ImagePreview(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.master.geometry('800x500+10+10')
self.master.columnconfigure(0, weight=1)
self.master.rowconfigure(0, weight=1)
self.grid(column=0, row=0, sticky=tk.N+tk.E+tk.S+tk.W)
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.master.update()
self.canvasScale = 1.0 # Multiplier to scale the image
self.sourceImage = Image.open('./test.jpg') # Must be taller than wide, for now
self.previewImage = ImageTk.PhotoImage(self.sourceImage) # Cropped Image
self.previewImage_ID = None # Canvas item ID of the cropped Image
self.init_widgets()
self.master.update_idletasks()
self.set_binds()
self.adjust_canvas_size()
def init_widgets(self):
self.previewCanvas = tk.Canvas(self)
self.previewCanvas.config(background='yellow', highlightthickness=0, width=self.winfo_width(), height=self.winfo_height())
self.previewCanvas.grid(column=0, row=0)
def set_binds(self):
self.bind('<Configure>', self.adjust_canvas_size) # Makes the canvas always the same size as the main frame
self.previewCanvas.bind("<ButtonPress-1>", self.shift_start)
self.previewCanvas.bind("<B1-Motion>", self.shift_move)
self.previewCanvas.bind('<MouseWheel>', self.zoom)
def adjust_canvas_size(self, event=None):
self.previewCanvas.config(width=self.winfo_width()-5, height=self.winfo_height()-5)
self.canvasScale = self.previewCanvas.winfo_height() / self.sourceImage.height
self.redraw()
def shift_start(self, event):
self.previewCanvas.scan_mark(event.x, event.y)
def shift_move(self, event):
self.previewCanvas.scan_dragto(event.x, event.y, gain=1)
self.redraw()
def zoom(self, event):
if event.delta >= 0 and self.canvasScale < 5:
self.canvasScale *= 1.2
if event.delta < 0 and self.canvasScale > 0.1:
self.canvasScale *= 1/1.2
self.redraw()
def redraw(self):
if self.previewImage_ID:
self.previewCanvas.delete(self.previewImage_ID)
self.previewCanvas.delete(self.orientationLine)
imageWidth, imageHeight = self.sourceImage.size
# Crop size to make image and canvas scale 1:1
cropWidth, cropHeight = int(imageWidth*self.canvasScale), int(imageHeight*self.canvasScale)
size = cropWidth, cropHeight
tempImage = self.sourceImage.resize(size, resample=Image.LANCZOS)
if self.sourceImage.height > self.sourceImage.width: # Didn't came up with an idea yet to crop wide and tall pictures with the same algorithm
# The distance between left (or right) edge of the canvas
# and the left (or right) edge of the original image position
z = int((self.previewCanvas.winfo_width()-cropWidth)/2)+1
# To simplify it, I'm just cutting the left edge,
# when the image hits the left edge of the canvas
if self.previewCanvas.canvasx(0) > z:
leftEdge = self.previewCanvas.canvasx(0) - z
print('Cut:',leftEdge)
else:
leftEdge = 0
rightEdge = tempImage.width
topEdge = 0
bottomEdge = tempImage.height
#crop
tempImage = tempImage.crop((leftEdge, topEdge, rightEdge, bottomEdge))
# To check that there is no overhang, on the not visible part of the canvas,
# what is sadly the problem
tempImage.save('./croppedImage.jpg')
# draw
x = self.previewCanvas.winfo_width() / 2
y = self.previewCanvas.winfo_height() / 2
self.previewImage = ImageTk.PhotoImage(tempImage)
self.previewImage_ID = self.previewCanvas.create_image(x, y, image=self.previewImage)
self.previewCanvas.scale(tk.ALL, x, y,self.canvasScale, self.canvasScale)
self.orientationLine = self.previewCanvas.create_line(0,0,self.previewCanvas.winfo_width(),self.previewCanvas.winfo_height())
def main():
root = tk.Tk()
application = ImagePreview(root)
application.mainloop()
if __name__ == '__main__':
main()
问题是,从理论上讲,图像的裁剪是正确的(调整大小的图像和重叠的、不可见的部分之间的差别是正确的)。但是如果我保存裁剪后的图像,我可以清楚地看到边界之外还有一部分没有被裁剪。 最糟糕的一点是,重叠越大,图像移出边界的次数越多。你知道吗
我很确定我在缩放方面遗漏了一些东西,但是在过去的几天里我没有发现错误。你知道吗
目前没有回答
相关问题 更多 >
编程相关推荐