Python 如何在Tkinter中显示超长图像?(如何绕过画布最大限制)

Python 如何在Tkinter中显示超长图像?(如何绕过画布最大限制),python,image,tkinter,tkinter-canvas,Python,Image,Tkinter,Tkinter Canvas,我用tkinter尝试了多种显示大图像的方法,不管我尝试了什么,似乎都没有任何代码可以工作。主要问题是画布的最大高度限制在30000像素左右 有没有办法显示整个图像?增加或绕过画布限制?请参见下面的示例图像。除了修改和重新编译底层tk代码之外,无法绕过画布的大小限制。这可能不是一项微不足道的任务 假设您试图在典型的计算机屏幕上显示图像,仍然有查看图像的方法。基本上,它归结为只加载用户在任何时候都可以看到的部分图像 例如,一幅世界图像比64k乘以64k大得多,但谷歌地图可以让你随心所欲地滚动。它通

我用tkinter尝试了多种显示大图像的方法,不管我尝试了什么,似乎都没有任何代码可以工作。主要问题是画布的最大高度限制在30000像素左右


有没有办法显示整个图像?增加或绕过画布限制?请参见下面的示例图像。

除了修改和重新编译底层tk代码之外,无法绕过画布的大小限制。这可能不是一项微不足道的任务

假设您试图在典型的计算机屏幕上显示图像,仍然有查看图像的方法。基本上,它归结为只加载用户在任何时候都可以看到的部分图像

例如,一幅世界图像比64k乘以64k大得多,但谷歌地图可以让你随心所欲地滚动。它通过将地图显示为一系列平铺来实现这一点。当您在图像周围移动时,屏幕外的磁贴将被丢弃,并加载新的磁贴


同样的技术也可以用在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()

布莱恩,我看你是个好朋友。谢谢你的回答,我把在网上找到的一些代码拼凑在一起,得到了一些有用的东西。