Skip to content Skip to sidebar Skip to footer

How Do I Display An Extremly Long Image In Tkinter? (how To Get Around Canvas Max Limit)

I've tried multiple ways of displaying large images with tkinterreally long image No matter what I've tried, there doesn't seem to be any code that works. The main issue is that Ca

Solution 1:

There is no way around the size limit of the canvas, short of modifying and recompiling the underlying tk code. This would likely not be a trivial task.

Assuming you are trying to display the image on a typical computer screen, there are still ways to view the image. Basically it boils down to only loading the part of the image that the user can see at any one time.

For example, an image of the world is considerably larger than 64k by 64k, yet google maps is able to let you scroll around all you want. It does this by displaying the map as a series of tiles. As you move around the image, off-screen tiles are thrown away and new tiles are loaded.

This same technique can be used in tkinter, and can even be used with scrollbars instead of a dragging motion. You just need to hook the scrollbars up to a function rather than directly to the canvas. Then, when the function is called, it can compute which part of the image that the user is looking at, and load it into memory.

Solution 2:

This is a rather unattractive answer, but an answer non-the-less. This divides up extremely long images into "tiles" of 1000 pixel lengths. It does not divide the width. I've spliced together code from several sources until I got it all to work. If someone could make this with a scroll-bar functionality, that would be cool.

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.classMainWindow():

    #----------------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)#----------------defgetimage(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 heightreturn width, height, im # return relevent variables/objectsdefgetrowsandcols(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/columnreturn im, th, tw, rows, cols #return selected variablesdefcropimages(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 imagefor r inrange(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 = Nonereturn self.my_images
    defonUpButton(self):
        # next imageif self.my_image_number == 0:
            self.my_image_number = len(self.my_images)-1else:
            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 canvasdefonDownButton(self):
        # next image
        self.my_image_number += 1#every button pressed will# return to first imageif 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()

Post a Comment for "How Do I Display An Extremly Long Image In Tkinter? (how To Get Around Canvas Max Limit)"