Python Imaging Library je balíček modulů pro práci s grafickými daty z prostředí jazyka Python. Zdrojový tarball si můžete stáhnout z domovské stránky knihovny. Instrukce pro nainstalování jsou zahrnuty v balíčku. Je rovněž možné použít předkompilované balíčky pro vaši distribuci Linuxu (v Debianu např. python2.2-imaging).
Po nainstalování máte přístupný pythonovský balíček PIL, někdy (např. v Debianu) může být instalace Pythonu nakonfigurována tak, že cesta sys.path již obsahuje adresář tohoto balíčku, takže všechny jeho moduly jsou přístupné přímo bez uvedení prefixu (jméno balíčku).
JAK A K ČEMU LZE PIL POUŽÍT?
Především je PIL výhodná pro manipulaci s grafickými daty v různých formátech. Lze pomocí ní vytvářet náhledy souborů, generovat nové grafické soubory, provádět různé úpravy parametrů obrázku (změna kontrastu, jasu). Lze dokonce vytvořit u uživatelské filtry, které modifikují původní obrázek. Budete-li Python Imaging Library používat delší dobu, zjistíte, jaká síla se v ní ukrývá.
Jestliže budete chtít vytvořit nový obrázek, máte několik možností. Především lze obrázek načíst z nějakého souboru. Paleta podporovaných souborových formátů je velice široká, proto je téměř vyloučena možnost, že PIL nedokáže nějaký formát přečíst. Další možností, kterou máte, je vytvoření obrázku „na zelené louce“. Konečně, obrázek lze získat i operacemi nad jiným obrázkem (výřez, získání barevného kanálu apod.).
Grafická data lze přečíst ze souboru pomocí funkce open() modulu Image:
>>> import Image >>> obrazek = Image.open('galeon.png')
Tím jsme získali instanci třídy Image.Image, která nám poskytuje přístup k různým informacím ohledně obrázku:
>>> obrazek.size (48, 48) >>> obrazek.format 'PNG' >>> obrazek.mode 'RGBA'
Je důležité vědět, že PIL se nepokouší načíst celý obrázek hned při volání funkce open(), ale až při požadavku na nějaká grafická data. Proto lze při otevření souboru načíst relativně malou hlavičku informující o velikosti obrázku, případně jeho módu, a vyčkávat, zda uživatel nebude chtít obrázek zpracovávat. Proto můžeme velice rychle přečíst informace o mnoha souborech najednou.
Instance třídy Image.Image podporují také množství metod, díky kterým můžeme s obrázkem pracovat. Například již zmíněný náhled získáme voláním metody thumbnail():
>>> obrazek.thumbnail((96, 96))
Metoda thumbnail() modifikuje původní obrázek, abychom si mohli výsledky našeho snažení prohlédnout, musíme obrázek uložit pomocí volání metody save():
>>> obrazek.save('galeon.thumb.png')
V tomto případě je formát výstupního souboru určen na základě přípony souboru, pokud nebude knihovna moci formát souboru rozpoznat, musíte jí předat formát, který požadujete, např: obrazek.save(‚galeon.thumbnail‘, ‚PNG‘)
Pro účely ladění se může hodit metoda show(), která obrázek uloží do dočasného PPM souboru a zavolá program xv pro jeho zobrazení. Pokud se budete PIL zabývat více, zjistíte, že existuje dokonce rozhraní, které umožňuje z obrázku vytvořit Tk widget, tudíž takto lze spolupracovat s nejrozšířenějším toolkitem pro Python.
Pokročilejší metody nabízejí manipulaci s výřezy obrázku. Z obrázku můžete získat podobrázek, ten třeba upravit a navrátit ho zpět do původního:
>>> pulka = obrazek.crop((0, 0, 24, 47)) >>> pulka.load() >>> pulka = pulka.transpose(Image.FLIP_LEFT_RIGHT) >>> obrazek.paste(pulka, (0, 0))
Metoda crop() z původního obrázku získá obdélníkový podobrázek, přičemž levý horní roh má souřadnice [0, 0] a pravý dolní [24, 47]. Následné volání metody load() je sichr, metoda crop() totiž může, ale NEMUSÍ vytvořit nezávislou kopii data, tudíž změny v původním obrázku se nám mohou promítat do naší poloviny, se kterou chceme dále pracovat. Metoda load() zajistí, že se data zkopírují vždy, tudíž se přeruší jakékoli vazby mezi původním a novým obrázkem.
Následné volání metody transpose() zrcadlově překlopí obrázek. Existují i další možné konstanty, kterými lze řídit chování této funkce (např. FLIP_TOP_BOTTOM, ROTATE90, ROTATE180, ROTATE270). Tato funkce vrací nový obrázek, který vznikl aplikováním dané transformace na původní obrázek, v našem případě jsme tento obrázek uložili zpět do proměnné pulka. Nakonec jsme polovinu obrázku překlopenou kolem horizontální osy vložili zpět do původního obrázku pomocí metody paste(), té musíme předat obrázek a souřadnice, kam se má vložit.
Pro získání obrázku o jiných rozměrech, než má původní obrázek, použijte metodu resize() a jako první argument jí předejte velikost nového obrázku. Druhý argument může být volitelně jedna z konstant: Image.NEAREST, Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS. Ty specifikují filtr použitý pro přepočítání do jiného rozlišení. Implicitně je použit Image.NEAREST:
>>> obraz = obrazek.resize((128, 128), Image.ANTIALIAS)
PRÁCE S JEDNOTLIVÝMI KANÁLY
Jak nám již prozradila hodnota atributu mode, náš obrázek pracuje v módu RGBA, což znamená, že hodnota jednoho pixelu je složena ze čtyř složek – červené, zelené, modré a míry průhlednosti. PIL umožňuje práci s těmito barevnými módy: 1 (černá a bílá, 1b/px), L (256 odstínů šedi, 8b/px), P (mapování do jiného módu za použití palety, 8b/px), RGB (3×8b/px), RGBA (RGB a míra průhlednosti 4×8b/px), CMYK (4×8b/px), YCbCr (3×8b/px), I (32bitové celočíselné hodnoty pixelů), F (32bitové reálné hodnoty pixelů).
Knihovna bez problémů podporuje převody mezi jednotlivými módy, umožňuje to metoda convert(), které předáte řetězec reprezentující nový mód:
>>> cmyk_obrazek = obrazek.convert('CMYK')
Co víc, PIL dokáže pracovat s jednotlivými kanály odděleně. Metodou split() můžeme obrázek rozdělit na tuple dílčích obrázků (s módem L), které reprezentují každý jeden kanál (tj. jeden reprezentuje červenou složku obrázku, druhý zelenou, třetí modrou a čtvrtý míru průhlednosti).
S těmito obrázky potom můžeme pracovat jako s klasickými instancemi Image.Image. Pokud budeme chtít obrázek získat zpět z daných kanálů, použijeme funkci Image.merge(), které předáme jako první argument mód nového obrázku a jako druhý tuple, jehož prvky jsou kanály nového obrázku. Následující fragment kódu vzájemně prohodí všechny tři barevné kanály obrázku:
>>> R, G, B, A = obrazek.split() >>> obrazek2 = Image.merge('RGBA', (G, B, R, A))
KRESLENÍ DO OBRÁZKU
Jak jsme si již řekli, obrázek můžeme vytvořit celý od základů. Nyní si povíme, jak na to. Ti, kteří znají nějaký grafický toolkit (např. QT nebo GTK+), jistě ví, že pro kreslení do nějakého primitiva se používá tzv. „plátno“, čili objekt, pomocí jehož metod se dají kreslit čáry, obdélníky a další. Obdobou tohoto plátna je instance třídy ImageDraw.Draw. Jejímu konstruktoru jednoduše předáte obrázek a již můžete kreslit:
>>> import ImageDraw >>> obrazek3 = Image.new('RGB', (120, 90)) >>> platno = ImageDraw.Draw(obrazek3) >>> MODRA = 0xff0000 >>> BILA = 0xffffff >>> CERNA = 0x000000 >>> platno.rectangle((0, 0, 120, 90), fill = BILA, \ ... outline = CERNA) >>> platno.ellipse((40, 20, 50, 30), fill = MODRA, \ ... outline = CERNA) >>> platno.ellipse((70, 20, 80, 30), fill = MODRA, \ ... outline = CERNA) >>> platno.arc((20, 0, 100, 80), 25, 155, fill = MODRA) >>> del platno
Nyní máme v proměnné obrazek3 obrázek, který jsme si vlastnoručně nakreslili. Můžeme s ním manipulovat jako s jakýmkoli jiným obrázkem. (Zkuste si ho uložit a uvidíte, co těch několik řádek kódu kreslí.) Toto je jen ukázka, jak lze velice jednoduše kreslit do obrázku, budete-li chtít více informací, nahlédněte do dokumentace k této knihovně.
ZMĚNA PARAMETRŮ OBRÁZKU
Pokud budete chtít změnit parametry obrázku (např. jas, kontrast, barevný tón apod.), bude se vám hodit modul ImageEnhance. Ten nabízí několik filtrů, které jsou všechny odvozeny od třídy ImageEnhance._Enhance. Ta definuje jednotné rozhraní – konstruktor __init__(), kterému předáme obrázek, jehož parametry chceme měnit, a metodu enhance(), jež přebírá argument, pomocí kterého se řídí parametry filtru, přičemž po aplikování filtru vrátí nový obrázek. Například pro změnu jasu použijete třídu ImageEnhance.Brightness:
>>> obrazek4 = Image.open('galeon.png') >>> import ImageEnhance >>> filtr = ImageEnhance.Brightness(obrazek4) >>> jas = filtr.enhance(0.5) >>> del filtr
Další možné filtry, které můžete použít, jsou: Color (vyvážení barev), Brightness (jas), Contrast (kontrast) a Sharpness (vyostření).
VYTVÁŘENÍ POSTSCRIPTOVÝCH SOUBORŮ
Poslední zajímavou featurou knihovny PIL, kterou se budeme dnes zabývat, je možnost vytváření postscriptových souborů. (Každý UNIXový mág jistě ví, k čemu se nám hodí, lze pomocí nich například vyřešit tisk z programu apod.) Modul PSDraw nám poskytuje třídu PSDraw, pomocí jejíchž metod můžeme PS soubor vytvářet. Jejímu konstruktoru předáme pouze soubor otevřený pro zápis. Ten můžeme dokonce vynechat, pak PIL použije standardní výstup. Následně zavoláme metodu begin_document(), vesele si kreslíme, a až bude po všem, zavoláme end_document() a PSDraw nám postscriptový dokument uloží do souboru:
>>> import PSDraw >>> soubor = open('output.ps', 'w') >>> ps = PSDraw.PSDraw(soubor) >>> INCH = 72 >>> ps.begin_document() >>> ps.line((INCH, INCH), (5*INCH, INCH)) >>> ps.line((INCH, INCH), (3*INCH, 4*INCH)) >>> ps.line((3*INCH, 4*INCH), (5*INCH, INCH)) >>> ps.end_document() >>> soubor.close()
Pozor, všechny kreslící metody PSDraw používají souřadnicový systém PostScriptu, kde souřadnice [0, 0] odpovídá levému dolnímu rohu. Dále jeden palec odpovídá 72 bodům, proto každou souřadnici násobíme konstantou 72 (INCH). Více se dozvíte ze zdrojových souborů modulu PSDraw nebo z dokumentace knihovny PIL.
PŘÍŠTĚ
Další, již dvacátý díl Létajícího cirkusu věnujeme knihovně Numeric Python (zkráceně NumPy).