问题描述
我想知道是否可以动态调整图像大小(保持其宽高比)。我制作了一个图像查看器应用程序,但随后垂直较长的图像在屏幕上溢出了,所以我想知道一种调整图像大小的方法,我尝试了一种方法,下面提供了它。但是我仍然得到了溢出屏幕的相同输出。
from win32api import GetSystemMetrics
from tkinter import *
screen_width,screen_height = GetSystemMetrics(0),GetSystemMetrics(1)
root = Tk() # this is your window
root.geometry("{}x{}".format(screen_width//2,screen_height//2)) # set size of you window here is example for 1/2 screen height and width
img = Image.open("picture_name.png")
width,height = screen_width//4,screen_height//4
img.resize((width,height),Image.ANTIALIAS)
l = Label(root,image=img)
l.pack()
root.mainloop()
仍然无法获得未调整大小的图像,不知道为什么。
然后我尝试了这种方法,在其中设置了分辨率,并且该方法在我的屏幕上正常工作。但是如果我要发送给其他人,它将不会动态调整。
desired_size = 950
im = Image.open('img.png')
old_size = im.size
ratio = float(desired_size)/max(old_size)
new_size = tuple([int(x*ratio) for x in old_size])
im = im.resize(new_size,Image.ANTIALIAS)
img = ImageTk.PhotoImage(im)
l = Label(root,image=img)
l.image = img
l.pack()
我想知道一种可以动态调整图像大小并保持其长宽比的方法,因此不会发生失真,例如Windows 10中的“照片”应用程序。
整个代码:
from tkinter import *
from tkinter import messageBox
from glob import glob
from tkinter import filedialog
from PIL import Image,ImageTk
root = Tk()
root.config(bg='white')
root.title('Image Viewer App')
def forward_image(event=None):
global n
n += 1
if n > len(main_img)-2:
forward['state'] = disABLED
root.unbind('<Key-Right>')
else:
backward['state'] = norMAL
root.bind('<Key-Left>',backward_image)
im = Image.open(main_img[n])
old_size = im.size
ratio = float(desired_size)/max(old_size)
new_size = tuple([int(x*ratio) for x in old_size])
im = im.resize(new_size,Image.ANTIALIAS)
img = ImageTk.PhotoImage(im)
l.image = img
l.config(image=img)
status.config(text=f'{n+1} of {total} images')
def backward_image(event=None):
global n
n -= 1
if n <= 0:
backward['state'] = disABLED
root.unbind('<Key-Left>')
else:
forward['state'] = norMAL
root.bind('<Key-Right>',forward_image)
im = Image.open(main_img[n])
old_size = im.size
ratio = float(desired_size)/max(old_size)
new_size = tuple([int(x*ratio) for x in old_size])
im = im.resize(new_size,Image.ANTIALIAS)
img = ImageTk.PhotoImage(im)
l.image = img
l.config(image=img)
status.config(text=f'{n+1} of {total} images')
def path():
global main_img
path = filedialog.askdirectory(
initialdir='c:/',title='Select a folder with images')
img_png = glob(path+'/*.png')
img_jpg = glob(path+'/*.jpg')
main_img = img_jpg + img_png
path()
n = 0
desired_size = 950
im = Image.open(main_img[n])
old_size = im.size
ratio = float(desired_size)/max(old_size)
new_size = tuple([int(x*ratio) for x in old_size])
im = im.resize(new_size,image=img)
l.image = img
l.pack()
forward = Button(root,text='Forward',command=forward_image)
forward.pack(side=RIGHT)
backward = Button(root,text='Backward',command=backward_image)
backward.pack(side=LEFT)
backward['state'] = disABLED
total = len(main_img)
status = Label(root,text=f'{n+1} of {total} images',bg='white',font=('helvetica',10))
status.pack(side=BottOM)
root.focus_force()
root.bind('<Key-Left>',backward_image)
root.bind('<Key-Right>',forward_image)
root.bind('<Escape>',lambda event: root.state('normal'))
root.bind('<F11>',lambda event: root.state('zoomed'))
if total <= 1:
backward['state'] = disABLED
forward['state'] = disABLED
root.unbind('<Key-Right>')
root.unbind('<Key-Left>')
if total == 0:
messageBox.showerror('No image','Choose a directory with images.')
root.mainloop()
先谢谢您了:D
解决方法
不确定这是否是您想要的,但是下面我定义了一个import React from 'react';
export default function App() {
const [dropdownCount,setDropdownCount] = React.useState(0);
return (
<div>
{Array.from({ length: dropdownCount }).map((v,idx) => {
return (
<div>
<p>Dropdown {idx + 1}</p>
<MultiDropdown />
</div>
)
})}
<button onClick={() => setDropdownCount(dropdownCount + 1)}>
Increase dropdown
</button>
</div>
);
}
,该图像始终将其图像class
的大小调整为950,并将高度调整为原始的width
:
height*delta
如果稍微修改一下并根据实际窗口值传递宽度/高度,它也可以缩小或增长。
,去吧。 scale
为1.0
或更低时,图像将始终适合其主图像。该答案基于@HenryYik答案,但通过添加scale
参数以及考虑各个方向上的溢出的逻辑,使其更具动态性。另外,不是基于窗口屏幕空间,而是基于主屏幕空间,并且考虑是在resizing
中进行,而不是在__init__
中进行。
其他更改:
- 将
super()
用作__init__
的超类并不理想,因此该部分已更改为更严格的语法。 - 除非您在所有
kwargs
的确切顺序中都有一个运行列表,否则对于每个小部件,您永远都不会使用*args
,因此已被省略。
import tkinter as tk
from tkinter import messagebox,filedialog
from glob import glob
from PIL import Image,ImageTk
#configure root
root = tk.Tk()
root.title('Image Viewer App')
root.geometry('800x600')
root.config(bg='#222222',bd=0,padx=0,pady=0,highlightthickness=0)
root.bind('<Escape>',lambda event: root.state('normal'))
root.bind('<F11>',lambda event: root.state('zoomed'))
class Slide(tk.Label):
def __init__(self,master,image_path:str='',scale:float=1.0,**kwargs):
tk.Label.__init__(self,**kwargs)
self.configure(bg=master['bg'])
self.img = None if not image_path else Image.open(image_path)
self.p_img = None
self.scale = scale
self.bind("<Configure>",self.resizing)
def set_image(self,image_path:str):
self.img = Image.open(image_path)
self.resizing()
def resizing(self,event=None):
if self.img:
iw,ih = self.img.width,self.img.height
mw,mh = self.master.winfo_width(),self.master.winfo_height()
if iw>ih:
ih = ih*(mw/iw)
r = mh/ih if (ih/mh) > 1 else 1
iw,ih = mw*r,ih*r
else:
iw = iw*(mh/ih)
r = mw/iw if (iw/mw) > 1 else 1
iw,ih = iw*r,mh*r
self.p_img = ImageTk.PhotoImage(self.img.resize((int(iw*self.scale),int(ih*self.scale))))
self.config(image=self.p_img)
total = 0
slide_num = 0
def get_slides():
global total
path = filedialog.askdirectory(initialdir='c:/',title='Select a folder with images')
cache = glob(path+'/*.png') + glob(path+'/*.jpg')
total = len(cache)
if not total:
m = messagebox.askyesno('No Images','The directory you have chosen does not contain any images. Try Again?')
if m:
return get_slides()
else:
root.quit()
exit(0)
return cache
image_cache = get_slides()
def commit_slide(n,t):
slide.set_image(image_cache[n])
status.config(text=f'{n+1} of {t} images')
def next_slide(event=None):
global slide_num,total
slide_num = (slide_num+1)%len(image_cache) #wrap
commit_slide(slide_num,total)
root.bind('<Key-Right>',next_slide)
def previous_slide(event=None):
global slide_num,total
slide_num = range(len(image_cache))[slide_num-1] #wrap
commit_slide(slide_num,total)
root.bind('<Key-Left>',previous_slide)
#init display widgets
slide = Slide(root)
slide.pack()
tk.Button(root,text='prev',command=previous_slide).place(relx=.02,rely=.99,anchor='sw')
tk.Button(root,text='next',command=next_slide).place(relx=.98,anchor='se')
status = tk.Label(root,bg='white',font=('helvetica',10))
status.place(relx=.5,anchor='s')
#init first slide
commit_slide(slide_num,total)
root.focus_force()
root.mainloop()