Как отобразить очень длинное изображение в Tkinter? (как обойти холст макс лимит) - PullRequest
0 голосов
/ 10 мая 2018

Я пробовал несколько способов отображения больших изображений с помощью tkinter действительно длинного изображения Независимо от того, что я пробовал, похоже, что не работает какой-либо код. Основная проблема заключается в том, что максимальная высота Canvas составляет около 30 000 пикселей.

Есть ли способ отобразить все это изображение? увеличить или обойти лимит холста? Смотрите пример изображения ниже.

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Это довольно непривлекательный ответ, но, тем не менее, ответ. Это делит чрезвычайно длинные изображения на «плитки» длиной 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()
0 голосов
/ 10 мая 2018

Нет никакого способа обойти ограничение размера холста, если не считать изменения и перекомпиляции базового кода tk.Скорее всего, это не будет тривиальной задачей.

Предполагая, что вы пытаетесь отобразить изображение на типичном экране компьютера, все еще существуют способы его просмотра.По сути, это сводится к загрузке только той части изображения, которую пользователь может видеть одновременно.

Например, изображение мира значительно больше, чем 64К на 64К, но Google Maps позволяет вам прокручивать все, что вы хотите.Это делается путем отображения карты в виде серии плиток.При перемещении изображения изображение вне экрана выбрасывается и загружаются новые плитки.

Эту же технику можно использовать в tkinter и даже можно использовать с полосами прокрутки вместо перетаскивания.Вам просто нужно привязать полосы прокрутки к функции, а не напрямую к холсту.Затем, когда функция вызывается, она может вычислить, какую часть изображения просматривает пользователь, и загрузить ее в память.

...