36

I need to resize an image, but I want to avoid PIL, since I cannot make it work under OS X - don't ask me why...

Anyway since I am satisfied with gif/pgm/ppm, the PhotoImage class is ok for me:

photoImg = PhotoImage(file=imgfn)
images.append(photoImg)
text.image_create(INSERT, image=photoImg)

The problem is - how do I resize the image? The following works only with PIL, which is the non-PIL equivalent?

img = Image.open(imgfn)
img = img.resize((w,h), Image.ANTIALIAS)
photoImg = ImageTk.PhotoImage(img)
images.append(photoImg)
text.image_create(INSERT, image=photoImg) 

Thank you!

Abhipso Ghosh
  • 457
  • 1
  • 6
  • 21
alessandro
  • 3,838
  • 8
  • 40
  • 59

5 Answers5

27

Because both zoom() and subsample() want integer as parameters, I used both.

I had to resize 320x320 image to 250x250, I ended up with

imgpath = '/path/to/img.png'
img = PhotoImage(file=imgpath)
img = img.zoom(25) #with 250, I ended up running out of memory
img = img.subsample(32) #mechanically, here it is adjusted to 32 instead of 320
panel = Label(root, image = img)
Memes
  • 1,005
  • 2
  • 11
  • 20
21

You have to either use the subsample() or the zoom() methods of the PhotoImage class. For the first option you first have to calculate the scale factors, simply explained in the following lines:

scale_w = new_width/old_width
scale_h = new_height/old_height
photoImg.zoom(scale_w, scale_h)
Constantinius
  • 34,183
  • 8
  • 77
  • 85
  • 7
    what I need! Only problem is, zoom() wants integer arguments, which is a bit odd since I may want to rescale say from 640x480 to 320x240: in that case I would get zoom(0,0). Or zooming in of a small factor, less than 2x – alessandro Jul 05 '11 at 14:49
  • 1
    Then I guess you have to use the `subsample` method. – Constantinius Jul 05 '11 at 14:58
  • 1
    I guess it will have to do! Just found out also _It had probably been a bit more convenient to have a single resize method, but the Tk designers didn’t think of that (if you need this, use PIL)_ at http://effbot.org/zone/tkinter-photoimage-grayscale-ramp.htm – alessandro Jul 05 '11 at 15:57
  • `AttributeError: 'PhotoImage' object has no attribute 'zoom'` – markroxor Aug 17 '18 at 10:28
  • 1
    @markroxor PIL's `PhotoImage` does not implement `zoom` from Tkinter's `PhotoImage` (as well as some other methods) – mister_potato Jan 04 '19 at 19:40
  • 1
    this answer suggests the ´.zoom´ method works in place but it's not. – bb1950328 Apr 18 '20 at 09:16
10

If you don't have PIL installed --> install it

(for Python3+ users --> use 'pip install pillow' in cmd)

from tkinter import *
import tkinter
import tkinter.messagebox
from PIL import Image
from PIL import ImageTk

master = Tk()
 
def callback():
    print("click!")

width = 50
height = 50
img = Image.open("dir.png")
img = img.resize((width,height), Image.ANTIALIAS)
photoImg =  ImageTk.PhotoImage(img)
b = Button(master,image=photoImg, command=callback, width=50)
b.pack()
mainloop()
Community
  • 1
  • 1
Vyr
  • 175
  • 1
  • 3
1

I just had the same problem, and I found that @Memes' answer works rather well. Just make sure to reduce your ratio as much as possible, as subsample() takes a rather long time to run for some reason.

Basically, the image is zoomed out to the least common factor of the two sizes, and then being subsidized by the origonal size. This leaves you with the image of the desired size.

Patrick
  • 165
  • 2
  • 10
-2

I had a requirement where I wanted to open an image, resize it, keeping the aspect ratio, save it under a new name, & display it in a tkinter window (using Linux Mint). After looking through dozens of forum questions, and dealing with some weird errors (semmingly involving the PIL to Pillow fork in Python 3.x), I was able to develop some code that works, using a predefined new maximum width or new maximum height (scaling up or down as necessary), and a Canvas object, where the image is displayed centered in the frame. Note that I did not include the file dialogs, just a hardcoded Image open & save for one file:

from tkinter import *
from PIL import ImageTk, Image
import shutil,os
from tkinter import filedialog as fd

maxwidth = 600
maxheight = 600

mainwindow = Tk()
picframe = Frame(mainwindow)
picframe.pack()
canvas = Canvas(picframe, width = maxwidth, height = maxheight)  
canvas.pack()

img = Image.open("/home/user1/Pictures/abc.jpg")

width, height = img.size                # Code to scale up or down as necessary to a given max height or width but keeping aspect ratio
if width > height:
    scalingfactor = maxwidth/width
    width = maxwidth
    height = int(height*scalingfactor)
else:
    scalingfactor = maxheight/height
    height = maxheight
    width = int(width*scalingfactor)

img = img.resize((width,height), Image.ANTIALIAS)

img.save("/home/user1/Pictures/Newabc.jpg")

img = ImageTk.PhotoImage(img)     # Has to be after the resize
canvas.create_image(int(maxwidth/2)-int(width/2), int(maxheight/2)-int(height/2), anchor=NW, image=img)   # No autocentering in frame, have to manually calculate with a new x, y coordinate based on a NW anchor (upper left)