【发布时间】:2026-01-03 08:30:01
【问题描述】:
我尝试了多种使用 tkinterreally long image 显示大图像的方法无论我尝试了什么,似乎都没有任何代码可以工作。主要问题是 Canvas 的最大高度限制约为 30,000 像素。
有没有办法显示整个图像?增加,还是绕过画布限制?请参阅下面的示例图片。
【问题讨论】:
标签: python image tkinter tkinter-canvas
我尝试了多种使用 tkinterreally long image 显示大图像的方法无论我尝试了什么,似乎都没有任何代码可以工作。主要问题是 Canvas 的最大高度限制约为 30,000 像素。
有没有办法显示整个图像?增加,还是绕过画布限制?请参阅下面的示例图片。
【问题讨论】:
标签: python image tkinter tkinter-canvas
没有办法绕过画布的大小限制,除非修改和重新编译底层 tk 代码。这可能不是一项简单的任务。
假设您尝试在典型的计算机屏幕上显示图像,仍然有一些方法可以查看图像。基本上它归结为只加载用户在任何时候都可以看到的图像部分。
例如,世界图像比 64k x 64k 大得多,但 google 地图可以让您随心所欲地滚动。它通过将地图显示为一系列瓷砖来做到这一点。当您在图像周围移动时,屏幕外的图块会被丢弃并加载新的图块。
同样的技术可以在 tkinter 中使用,甚至可以用于滚动条而不是拖动动作。您只需要将滚动条连接到一个函数而不是直接连接到画布。然后,当调用该函数时,它可以计算出用户正在查看图像的哪一部分,并将其加载到内存中。
【讨论】:
这是一个相当不吸引人的答案,但答案却很不一样。这将极长的图像划分为 1000 像素长度的“图块”。它不划分宽度。我已经将来自多个来源的代码拼接在一起,直到我完成所有工作。如果有人可以使用滚动条功能来实现这一点,那就太棒了。
from tkinter import *
from PIL import ImageTk as itk
from PIL import Image
import math
import numpy as np
Image.MAX_IMAGE_PIXELS = None #prevents the "photo bomb" warning from popping up. Have to have this for really large images.
#----------------------------------------------------------------------
# makes a simple window with a button right in the middle that let's you go "down" an image.
class MainWindow():
#----------------
def __init__(self, main):
# canvas for image
_, th, tw, rows, cols = self.getrowsandcols()
self.canvas = Canvas(main, width=tw, height=th)
#self.canvas.grid(row=0, column=0)
self.canvas.pack()
# images
self.my_images = self.cropimages() # crop the really large image down into several smaller images and append to this list
self.my_image_number = 0 #
# set first image on canvas
self.image_on_canvas = self.canvas.create_image(0, 0, anchor = NW, image = self.my_images[self.my_image_number])
# button to change image
self.upbutton = Button(main, text="UP", command=self.onUpButton)
self.downbutton = Button(main, text="DOWN", command=self.onDownButton)
self.upbutton.pack()
self.downbutton.pack()
#self.downbutton.grid(row=1, column=0)
#self.upbutton.grid(row=1, column=0)
#----------------
def getimage(self):
im = Image.open("Test_3.png") # import the image
im = im.convert("RGBA") # convert the image to color including the alpha channel (which is the transparency best I understand)
width, height = im.size # get the width and height
return width, height, im # return relevent variables/objects
def getrowsandcols(self):
width, height, im = self.getimage()
im = np.asarray(im) # Convert image to Numpy Array
tw = width # Tile width will equal the width of the image
th = int(math.ceil(height / 100)) # Tile height
rows = int(math.ceil(height / th)) # Number of tiles/row
cols = int(math.ceil(width / tw)) # Number of tiles/column
return im, th, tw, rows, cols #return selected variables
def cropimages(self):
self.my_images = [] # initialize list to hold Tkinter "PhotoImage objects"
im, th, tw, rows, cols = self.getrowsandcols() # pull in needed variables to crop the really long image
for r in range(rows): # loop row by row to crop all of the image
crop_im =im[r * th:((r * th) + th), 0:tw] # crop the image for the current row (r). (th) stands for tile height.
crop_im = Image.fromarray(crop_im) # convert the image from an Numpy Array to a PIL image.
crop_im = itk.PhotoImage(crop_im) # convert the PIL image to a Tkinter Photo Object (whatever that is)
self.my_images.append(crop_im) # Append the photo object to the list
crop_im = None
return self.my_images
def onUpButton(self):
# next image
if self.my_image_number == 0:
self.my_image_number = len(self.my_images)-1
else:
self.my_image_number -= 1 # every button pressed will
# change image
self.canvas.itemconfig(self.image_on_canvas, image=self.my_images[self.my_image_number]) # attaches the image from the image list to the canvas
def onDownButton(self):
# next image
self.my_image_number += 1 #every button pressed will
# return to first image
if self.my_image_number == len(self.my_images):
self.my_image_number = 0
# change image
self.canvas.itemconfig(self.image_on_canvas, image = self.my_images[self.my_image_number]) #attaches the image from the image list to the canvas
#----------------------------------------------------------------------
root = Tk()
MainWindow(root)
root.mainloop()
【讨论】: