How can I increase Tkinter Maximum Canvas size for extremely large images?
I tried to put together a bigger image from displays of a grid of canvases. This looks like it might work, at least if you just want to display a big image. I have just tested with a small image and not paid any attention to memory or speed or anything...
from tkinter import *from scrframe import VerticalScrolledFrameroot = Tk()tiles = VerticalScrolledFrame(root) # Scrolled frametiles.grid()tw = 90 # Tile widthth = 110 # Tile heightrows = 4 # Number of tiles/rowcols = 4 # Number of tiles/columntile_list = [] # List of image tilesimg = PhotoImage(file='pilner.png')for r in range(rows): col_list = [] for c in range(cols): tile = Canvas(tiles.interior, highlightthickness=0, bg='tan1', width=tw, height=th) tile.create_image(-c*tw, -r*th, image=img, anchor ='nw') tile.grid(row=r, column=c) col_list.append(tile) tile_list.append(col_list)root.mainloop()
Now, scrolling a frame seems to raise some problems, but there also seems to be solutions. I tried to use VerticalScrolledFrame
as described in Python Tkinter scrollbar for frame and it works fine. As it only provides for a vertical scrollbar you'd have to implement horizontal scrollbar yourself. Maybe a few additional functions as scrolling with the mouse wheel, keyboard shortcuts or other would be useful.
I got the VerticalScrolledFrame
from TKinter scrollable frame and modified it for Python 3.
This is the code I've come up with from several sources - Thanks to figbeam for all the help. Also, this is not pretty!!!! The button shows up in the center of the Tkinter window. If you'd like to modify this, please do.
from tkinter import *from PIL import ImageTk as itkfrom PIL import Imageimport mathimport numpy as npImage.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) # 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.button = Button(main, text="DOWN", command=self.onDownButton) self.button.grid(row=0, 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 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()