Как в tkinter вставить картинку с сайта?
Есть сайт wolframalpha.com , там есть API для, я отправляю запрос, получаю решение уравнения в виде картинки, вопрос: как эту картинку взять и поместить в tkinter?
Отслеживать
задан 6 ноя 2019 в 13:05
Максим Синельников Максим Синельников
85 1 1 серебряный знак 4 4 бронзовых знака
Подробнее напишите свой вопрос. Как получаете своё решение в виде картинки? Исходник нужен.
6 ноя 2019 в 14:21
api.wolframalpha.com/v2/… любая из картинок
6 ноя 2019 в 14:35
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Допустим, вам уже известен url изображения.
Ниже два примера (синхронный и асинхронный). В обоих случаях изображение скачивается из интернета в память, потом с помощью библиотеки Pillow (ее нужно установить с помощью pip install pillow ) изображение преобразовывается в формат, который понимает tkinter, потом изображение устанавливается в label.
Первое решение синхронное (графический интерфейс подвисает, пока идет загрузка), загрузка с помощью requests :
import tkinter as tk import requests from io import BytesIO from PIL import Image, ImageTk url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" root = tk.Tk() def load_image(): label.config(text='Loading an image. ') root.update() try: response = requests.get(url, timeout=10) except requests.exceptions.Timeout: label.config(text='Timeout error') else: if response.status_code != 200: label.config(text=f'HTTP error ') else: pil_image = Image.open(BytesIO(response.content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') # прикрепляем ссылку на изображение к объекту label, # чтобы изображение не удалил сборщик мусора label.image = image tk.Button(root, text='Load an image', command=load_image).pack() label = tk.Label(root) label.pack() root.mainloop()
Второй вариант с асинхронностью (Python 3.5 и выше), загрузка с помощью библиотеки aiohttp (нужно установить ее с помощью pip install aiohttp ):
import tkinter as tk import asyncio import aiohttp from io import BytesIO from PIL import Image, ImageTk class AsyncTk(tk.Tk): """Асинхронная обертка для класса Tk""" def __init__(self): super().__init__() self.protocol("WM_DELETE_WINDOW", self.on_close) def on_close(self): self.done = True async def updater(self): self.done = False while not self.done: self.update() await asyncio.sleep(0.05) def mainloop(self): asyncio.get_event_loop().run_until_complete(self.updater()) async def fetch_image(url): async with aiohttp.ClientSession() as session: response = await session.get(url) if response.status != 200: label.config(text=f'HTTP error ') else: content = await response.content.read() pil_image = Image.open(BytesIO(content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') label.image = image button.config(state=tk.NORMAL) url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" def load_image(): button.config(state=tk.DISABLED) label.config(text='Loading an image. ') asyncio.ensure_future(fetch_image(url)) root = AsyncTk() button = tk.Button(root, text='Load an image', command=load_image) button.pack() label = tk.Label(root) label.pack() root.mainloop()
Идеи для данной реализации взяты из этих ответов:
- Use asyncio and Tkinter
- Проблема с asyncio: RuntimeWarning: coroutine ‘message_send’ was never awaited self.tk.mainloop(n)
P.S. минутка саморекламы. Второй вариант (в немного другой реализации, без наследования от Tk ) я оформил в виде модуля, выкатил на pypi. Возможно кому-то пригодится.
- Ставится через pip install async-tkinter-loop , см. на pypi:
https://pypi.org/project/async-tkinter-loop/ - Проект и примеры использования (папка examples):
https://github.com/insolor/async-tkinter-loop
Вариант с использованием модуля async_tkinter_loop :
import tkinter as tk import aiohttp from async_tkinter_loop import async_handler, async_mainloop from io import BytesIO from PIL import Image, ImageTk async def load_image(url): button.config(state=tk.DISABLED) label.config(text='Loading an image. ') root.update() async with aiohttp.ClientSession() as session: response = await session.get(url) if response.status != 200: label.config(text=f'HTTP error ') else: content = await response.content.read() pil_image = Image.open(BytesIO(content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') label.image = image button.config(state=tk.NORMAL) url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" root = tk.Tk() # Объект окна создается как обычно button = tk.Button(root, text='Load an image', command=async_handler(load_image, url)) button.pack() label = tk.Label(root) label.pack() async_mainloop(root) # Вместо стандартного `mainloop()` используется своя реализация с поддержкой асинхронности
Встраиваем картинки в Jupyter
Рассмотрим способы вставки картинок в Jupyter ноутбук.
Синтаксис Markdown
Выглядит следующим образом:

Например, исполним Markdown ячейку со следующим содержимым:

Синтаксис HTML
Для этого в Markdown ячейке используем тег . Этот способ позволяет задавать дополнительные настройки, в частности, размеры:
Возможности Ipython
В отличие от предыдущих способов позволяет совместить код и вывод картинки в одной ячейке, так как делает это посредством использования функции Image из модуля IPython.display:
from IPython.display import Image print('Картинка с птицей') Image("data/картинки/kartinki-ryabchiki-28.jpeg", width=320, height=240)
Четыре метода загрузки изображений с веб-сайта с помощью Python
Недавно пришлось по работе написать простенький парсер на питоне, который бы скачивал с сайта изображения (по идее тот же самый парсер может качать не только изображения, но и файлы других форматов) и сохранял их на диске. Всего я нашел в интернете четыре метода. В этой статье я их решил собрать все вместе.
1-ый метод
Первый метод использует модуль urllib (или же urllib2). Пусть имеется ссылка на некое изображение img. Метод выглядит следующим образом:
import urllib resource = urllib.urlopen(img) out = open(". \img.jpg", 'wb') out.write(resource.read()) out.close()
Здесь нужно обратить внимание, что режим записи для изображений — ‘wb’ (бинарный), а не просто ‘w’.
2-ой метод
Второй метод использует тот же самый urllib. В дальнейшем будет показано, что этот метод чуть медленнее первого (отрицательный оттенок фактора скорости парсинга неоднозначен), но достоин внимания из-за своей краткости:
import urllib urllib.urlretrieve(img, ". \img.jpg")
Притом стоит заметить, что функция urlretrieve в библиотеке urllib2 по неизвестным мне причинам (может кто подскажет по каким) отсутствует.
3-ий метод
Третий метод использует модуль requests. Метод имеет одинаковый порядок скорости выгрузки картинок с первыми двумя методами:
import requests p = requests.get(img) out = open(". \img.jpg", "wb") out.write(p.content) out.close()
При этом при работе с веб в питоне рекомендуется использовать именно requests вместо семейств urllib и httplib из-за его краткости и удобства обращения с ним.
4-ый метод
Четвертый метод по скорости кардинально отличается от предыдущих методов (на целый порядок). Основан на использовании модуля httplib2. Выглядит следующим образом:
import httplib2 h = httplib2.Http('.cache') response, content = h.request(img) out = open('. \img.jpg', 'wb') out.write(content) out.close()
Здесь явно используется кэширование. Без кэширования (h = httplib2.Http()) метод работает в 6-9 раза медленнее предыдущих аналогов.
Тестирование скорости проводилось на примере скачивания картинок с расширением *.jpg c сайта новостной ленты lenta.ru. Выбор картинок, подпадающих под этот критерий и измерение времени выполнения программы производились следующим образом:
import re, time, urllib2 url = "http://lenta.ru/" content = urllib2.urlopen(url).read() imgUrls = re.findall('img .*?src="https://habr.com/ru/articles/210238/(.*?)"', сontent) start = time.time() for img in imgUrls: if img.endswith(".jpg"): """реализация метода по загрузке изображения из url""" print time.time()-start
Постоянно меняющиеся картинки на сайте не повлияли на чистоту измерений, поскольку методы отрабатывали друг за другом. Полученные результаты таковы:
| Метод 1, с | Метод 2, с | Метод 3, с | Метод 4, с (без кэширования, с) |
|---|---|---|---|
| 0.823 | 0.908 | 0.874 | 0.089 (7.625) |
Данные представлены как результат усреднения результатов семи измерений.
Просьба к тем, кто имел дело с библиотекой Grab (и с другими), написать в комментариях аналогичный метод по скачиванию изображений с помощью этой и других библиотек.
- питон и парсинг
- изображения
Python. Работа с изображениями в tkinter.
На уроке Python. Работа с изображениями мы с вами научились загружать и отображать картинки, а также всяко извращаться с ними. Это мы делали при помощи библиотеки PIL. На уроке Python. GUI мы с вами при помощи библиотеки tkinter создавали виндовый интерфейс программы: всякие кнопочки, флажки, и прочие элементы управления. Но возникает вопрос: а нельзя ли при помощи tkinter как-то выводить изображение на виндовую форму? Можно. Например вот такая программа:
import tkinter from PIL import Image, ImageTk root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() #Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2) #Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) image = Image.open("d:/3/Dscn0116.jpg") photo = ImageTk.PhotoImage(image) image = canvas.create_image(0, 0, anchor='nw',image=photo) canvas.grid(row=2,column=1) root.mainloop()
выдаст вот такое окно:

Что интересно, PIL здесь нужен, чтобы загружать изображения типа jpg, gif-ы и png можно открыть и без него:
import tkinter root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() #Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2) #Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) img = tkinter.PhotoImage(file = 'd:/3/Dscn0116.png') image = canvas.create_image(0, 0, anchor='nw',image=img) canvas.grid(row=2,column=1) root.mainloop()
А теперь попробуем при нажатии на кнопку сменить изображение:
import tkinter from PIL import Image, ImageTk root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() # Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1, column=1) image = Image.open("d://1//DSCN1128.png") photo = ImageTk.PhotoImage(image) def my_event_handler(): print("my_event_handler") image = Image.open("d://1//original.jpg") photo = ImageTk.PhotoImage(image) image = canvas.create_image(0, 0, anchor='nw', image=photo) canvas.grid(row=2, column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка", command=my_event_handler).grid(row=1, column=2) # Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) image = canvas.create_image(0, 0, anchor='nw', image=photo) canvas.grid(row=2, column=1) root.mainloop()
Но не тут то было. При нажатии на кнопку изображение не меняется. Хотя, казалось бы, все написано правильно, и наш обработчик событий работает, наше сообщение, что мы выводим командой print выводится в окно сообщений. В чем же дело? А дело в сборщике мусора (garbage collector). Как только мы вышли из my_event_handler, локальные переменные тут же уничтожаются сборщиком мусора. Именно поэтому мы видим на форме ту же самую картинку, что и до нажатия на кнопку. Как же быть? Не использовать локальные переменные. Давайте объявим класс, пусть изображение и прочие объекты хранятся в его полях:
import tkinter from PIL import Image, ImageTk class App: def __init__(self): self.root = tkinter.Tk() # создаем рабочую область self.frame = tkinter.Frame(self.root) self.frame.grid() # Добавим метку self.label = tkinter.Label(self.frame, text="Hello, World!").grid(row=1, column=1) self.image = Image.open("d://1//DSCN1128.png") self.photo = ImageTk.PhotoImage(self.image) # вставляем кнопку self.but = tkinter.Button(self.frame, text="Кнопка", command=self.my_event_handler).grid(row=1, column=2) # Добавим изображение self.canvas = tkinter.Canvas(self.root, height=600, width=700) self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo) self.canvas.grid(row=2, column=1) self.root.mainloop() def my_event_handler(self): print("my_event_handler") self.image = Image.open("d://1//original.jpg") self.photo = ImageTk.PhotoImage(self.image) self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo) self.canvas.grid(row=2, column=1) app= App()
