Jak zobrazit fotku JPG v Tkinteru? Jak změnit její velikost, aby se vešla do okna? Jak zajistit, aby můj program dokázal zjistit, na který obrázek jsem klikl (jinými slovy jak předávat a zpracovávat argumenty programu)? Tak to vše a mnohem více je obsahem lekce 23., lekce, ve které pokračujeme ve vytváření tkinterovského Prohlížeče obrázků.
Cesta k obrázku
Se zobrazením prvního obrázku nás čeká pár problémů. Obrázky, stejně jako ostatní soubory, většinou někde leží. Cestu k nim můžeme popsat absolutně nebo relativně. Kloním se k absolutním cestám v naději, že to bude lepší. Jistě by to šlo i relativně. No a dále je to čeština v názvu cest. Dnes již, bohužel pro programátory a bohudík pro uživatele, prakticky neexistuje cesta bez češtiny. Takže si vytvořte nějaký adresář s českými znaky, dejte do něj pár obrázků a vyzkoušejte, jestli je váš Python najde, jako např. mně:
# -*- coding: cp1250 -*-
import os
cesta = "C:\Documents and Settings\All Users\Dokumenty\Obrázky\nokia\Lekníny.jpg"
print os.path.exists(cesta)
Nebo v kódování UTF-8:
# -*- coding: utf-8 -*-
import os
cesta = u"C:\Documents and Settings\All Users\Dokumenty\Obrázky\nokia\Lekníny.jpg"
print os.path.exists(cesta)
Musíme použít cestu v Unicode. Bylo by to ostatně lepší i v předchozím příkladě, v CP-1250. Uvědomte si, že nestačí přepsat první řádek # -*- coding:…
. Musíte změnit kódování i fyzicky, tedy např. v PSPadu v menu Formát.
Zobrazení prvního obrázku
Tkinter nativně umí pracovat pouze s formátem GIF. Na všechny ostatní si vypomáhá skvělým modulem PIL. V PILu obrázek načteme, převedeme do formátu Tk, kterému rozumí Tkinter, a následně v Tkinteru zobrazíme. Konkrétně si tedy vytvoříme funkci – dejme tomu zobrazObrazek(obrazek)
– která bude v PIL (Image) obrázek otevírat (1. řádka), vytvářet z něj formát vhodný pro Tkinter (2. řádka), zobrazovat ho na plátně (3. řádka). 4. řádka je trochu magie – jde o to, že proměnná photo je lokální a po opuštění funkce zaniká, a tím zanikne i obrázek, který se má zobrazit. Aby se tak nestalo, uložíme si photo do kontejneru, a tím zajistíme obrázku nekonečný život.
from Tkinter import *
from PIL import Image, ImageTk
def zobrazObrazek(obrazek):
obr = Image.open(obrazek)
photo = ImageTk.PhotoImage(obr)
kontejner.platno.create_image(0,0,image=photo)
kontejner.obr=photo
Pokud máte obrázek větší než 640 × 480, určitě vidíte jako já pouze kousek obrázku, pravou dolní polovinu. Musíme tedy zajistit dvě věci: jednak obrázek umístit na střed a jednak ho umět zmenšit.
Výzva: Opravte a doplňte váš program tak, aby fungoval.
Umístění na střed
Funkce platno.create_image()
standardně umisťuje obrázek na střed, tedy místo 0,0
jí musíme předat souřadnice středu okna. Dalo by se tudíž napsat 640/2, 480/2
. Budeme však důslednější a podle pravidla „je-li v programu něco dvakrát stejného, dej to do proměnné“ to uděláme i s rozměry. Budeme tak mít zajištěno, že v budoucnu, až se rozhodneme změnit souřadnice okna, to bude stačit udělat na jednom místě a vše bude dál pěkně fungovat.
Do funkce vykresleniOkna
tedy vložte vytvoření nových proměnných, např.
kontejner.sirka=640
kontejner.vyska=480
Dále opravte příkaz, kde tyto hodnoty používáte – zaměňte čísla za proměnné. No a nyní můžete již opravit souřadnice 0,0
v zobrazObrazek()
na kontejner.sirka/2
a kontejner.vyska/2
. A máme zajištěno, že obrázek bude na středu.
Změna velikosti
Je potřeba zajistit, aby se vždy zmenšila velikost obrázku na šířku a výšku plátna. Trochu si to zjednodušíme (algoritmus):
pokud je šířka obrázku větší než šířka plátna:
zjisti kolikrát (poměr)
šířku tolikrát zmenši
stejně zmenši i výšku (aby se zachovala proporcionalita obrázku)
To vše a mnohem více umí právě PIL. Založme si tedy funkci zmenaVelikosti(obrazek)
, kde „obrazek“ není cesta k němu, ale instance PIL Image.open()
– v našem případě to bude proměnná obr ve funkci zobrazObrazek()
, odkud také budeme tuto funkci volat. Výšku a šířku obrázku zjistíme jednoduše:
sirka, vyska= obrazek.size
Příkaz „pokud je šířka obrázku větší než šířka plátna“ jistě dokážete sami. Zastavím se až u „zjisti kolikrát“. Tady je třeba pamatovat na to, že podíl dvou celých čísel je v Pythonu celé číslo a že poměr samozřejmě kvůli přesnosti chceme přesně. Zdálo by se, že
pomer=float(sirka/kontejner.sirka)
bude správně, ale nebude. Tím nejdříve získáte celé číslo dělením sirka/kontejner.sirka
a pak teprve z něho uděláte reálné. Jedno ze správných řešení je tedy takto:
pomer=float(sirka)/kontejner.sirka
Velmi malá změna polohy závorky, důsledky však velké.
Přepočítáte-li podle algoritmu šířku a výšku obrázku, je třeba ještě patřičně změnit velikost obrázku. To se zajistí metodou PIL resize()
:
obrazek=obrazek.resize((sirka, vyska))
Nezapomeňte použít return obrazek
, aby funkce obrazek
vracela do místa, odkud bude volána.
Výzva: Opravte a doplňte váš program tak, aby fungoval.
Klikáme na obrázky
Následující postup se ani tak netýká programování v Pythonu, ale ovládání Windows, ale to vůbec nevadí. Náš program musí s Windows spolupracovat, to se nedá nic dělat. Chceme, aby se spustil můj skript a aby se patřičný obrázek zobrazil, když na něj kliknu. Program již na to máme připravený – bude stačit zapsat do proměnné cesta adresu patřičného obrázku.
Zpracování argumentů
Vytvořte si program, např. pokus.py, ve kterém bude:
import sys
print sys.argv
print len(sys.argv)
V seznamu sys.argv se ukládají všechny argumenty, které jsou našemu programu předány. Pustíte-li tento program samostatně, zjistíte, že jako první (nultý) argument je vždy jméno samotného programu včetně cesty. Můžete tak, kromě jiného, pohodlně ve svém programu zjistit, odkud je váš program spuštěn a jak se jmenuje.
Předávání argumentů
Windows
Rozhodl jsem se – abych neuváděl do úžasu ostatní uživatele „svého“ počítače – že se můj program nebude spouštět na klik (aby nebyli zmateni, když neuvidí to, co jsou zvyklí vidět), ale na pravé tlačítko. Nic vám ale nebrání si to udělat na klik nebo se na to v Poradně zeptat.
Postup popíši v Total Commanderu, protože… Proto. Stojíme na nějakém obrázku, třeba JPG. Zvolíme Soubory-> Asociovat s-> Editovat typ-> Nový. Akce: cokoliv, Popis akce: cokoliv. To nejdůležitější a kritické je pole Příkaz. Pokud zde uděláte chybu, což se většinou napoprvé stane ;-), obrázek se nezobrazí, a dokonce se ani nespustí program, někdy ani samotný Python.
c:\python24\python.exe -i "i:\python\www.programujte.com\python\pokus.py" "%1"
Cesty si upravte podle svého. -i
je tam proto, aby program hned po skončení neskončil. Závěrečným "%1"
předáváte vašemu skriptu jméno kliknutého obrázku. Ty všechny uvozovky jsou tam proto, kdyby v cestě náhodou byly mezery, které často programátorům tímto způsobem komplikují život. Ale jak jsem říkal, tato problematika se spíše tyká ovládání Windows, případně Příkazového řádku.
No a můžete to vyzkoušet! Klikněte pravým tlačítkem na obrázek JPG a v nabídce by vám měl přibýt nový řádek, který po odkliknutí spustí Python, v něm váš pokus.py s předaným argumentem adresy toho kterého obrázku. To byste ostatně měli vidět, protože pokus.py všechno hezky vypíše.
Příkazový řádek
Velmi podobně to můžete zkoušet i na Příkazovém řádku. Stojíte-li v adresáři, kde leží váš skript, pak funguje
python.exe -i pokus.py "C:\Documents and Settings\All Users\Dokumenty\Obrázky\nokia\Lekníny.jpg"
případně
c:\python24\python.exe -i pokus.py "C:\Documents and Settings\All Users\Dokumenty\Obrázky\nokia\Lekníny.jpg"
Předávaných argumentů může být i více:
c:\python24\python.exe -i pokus.py prvni druhy treti čtvrtý "pátý argument" šestý....
Výzva: Vyzkoušejte, analyzujte a následně zapracujte do svého programu. Rozhodně na to vytvořte nějakou funkci, která bude do proměnné cesta vracet adresu kliknutého obrázku.
Úkol
Úkolem není jen úkol odevzdat, ale i zjistit, co má v úkolu být. Navíc zařiďte, kvůli mé lenosti, abych nemusel každý váš skript ukládat a asociovat, aby navíc fungoval i při obyčejném spuštění. Na všechna řešení se těším, bez ohledu na to, jestli tento článek čtete v den vydání nebo 5 let po ;-)
Dokončení příště.