Návrh na vylepšení Nette\Image
- Petr Motejlek
- Člen | 293
Ahoj,
už delší dobu laboruju s watermarkingem některých obrázků — úkol je
následující: vzít jakýkoliv obrázek, který v PHP (potažmo GD, potažmo
ImageMagick) jde zpracovat (s tím, že to klidně může být GIF a PNG
s průhledným pozadím) a přes ten obrázek vlepit watermark (např. logo
firmy). První, co běžného člověka napadne, je použít metodu
Nette\Image->place(), předat jí logo a nastavit $opacity na např. 20 –
tohle funguje super, když mám jako ten watermark např. PNG, které neobsahuje
žádné průhledné části a průhlednost potřebuju dělat pomocí
$opacity — bohužel, ne všechny loga jsou obdélníkovitého tvaru, takže
pokud máte logo např. kruhové a necháte průhledný zbytek obrázku,
běžná funkcionalita, která je v PHP dostupná (a kterou používá
Nette\Image) vám všechno, co je průhledné v tom PNG, nahradí černou
barvou (pokud nastavíte $opacity, tak POTOM do toho celého ošklivého
obdélníčku přidá průhlednost a to celé vlepí do obrázku, nad kterým
voláte place(). Zdá se, že je vše OK, pokud máte to štěstí, že
watermark je obdélník — chyba lávky! Pokud totiž chcete watermarkovat
průhledné PNG, tak to ten černý hnus přidá naopak do toho zdroje, což
vypadá jako výstup ještě hnusněji ;).
Dlouho jsem hledal a zjistil jsem, že za všema těma hnusárnama stojí funkce imagesavealpha() a imagealphablending(), které většina lidí moc použít nepotřebuje, ale právě pro práci s průhlednými obrázky jsou nepostradatelné.
Pro správné vlepení watermarku do obrázku je nutné, aby watermark byl ve formátu PNG a měl nastavenou požadovanou průhlednost už v sobě (umí to např. Gimp, takže předpokládám, že kdo dělá s něčím dražším, bude to umět taky ;)) — podle některých údajů v různých fórech na internetu nezvládá funkce imagecopymerge() moc dobře už průhledné obrázky (skončí to tím černým fuj pozadím). Funkci imagecopymerge() tímto zatracuji a doporučuji mít ty watermarky již předpřipravené jako průhledná PNG.
Následující kód ilustruje, co je třeba udělat, aby se do průhledného PNG obrázku vložil průhledný watermark a celé to stále zůstalo průhledné ;).
<?php
$watermark = Image::fromFile('logo.png');
$destination = Image::fromFile('pruhledneFoto.png');
$destination->alphablending(true);
$watermark->alphablending(true);
$destination->place($watermark, '50%', '50%');
$destination->alphablending(false);
$destination->savealpha(true);
$destination->send(Image::PNG, 100);
?>
A teď k tomu feature requestu — rád bych, aby se volání toho alphablendingu() a savealpha() daly nějak zautomatizovat — nenapadá mě situace, ve které by uživatel měl fakt zájem o to, aby se mu otevřel obrázek, který průhlednost podporuje, a ztratil ji. Proto už teď ve všech skriptech, co mám, vždycky hned po vytvoření instance Image, na ní volám alphablending(false) a savealpha(true). Myslím, že by nebylo naškodu vpravit ta volání přímo do Nette\Image, aby nikdo, kdo má podobné nároky na obrázky jako já, nemusel ty metody nad každou instancí volat ručně — pokud to nikdo nepotřebuje, tak by ho to ani tak nemělo nijak omezit ;).
Funkce imagesavealpha() a imagealphablending() je potřeba volat i při resize(), protože uvnitř té metody se opět vytváří nová instance a ve chvíli, kdy máte instanci, u které jste si alphablending vypnuli a zapnuli ukládání alpha kanálu, tak vám při resize() Nette\Image udělá rozměrově správný obrázek, ale už mu zpátky nenastaví alphablending ani savealpha, což je škoda, protože to pak uživatele nutí opakovat stejné řádky kódu na několika místech.
P. S. Vím, že tenhle příspěvek je docela dlouhý, ale nevím, jak bych to už nakrátil ;). Pro další informace jsem k dispozici :D.
- Honza Kuchař
- Člen | 1662
Jsem pro oboje. Nedávno jsem to taky řešil. (ale to jsem ještě nedělal s Nette)
- David Grudl
- Nette Core | 8218
Můžeš mi prosím hodit do emailu příklady nějakých obr. logo.png a pruhledneFoto.png, abych to mohl odladit?
- Petr Motejlek
- Člen | 293
Omlouvám se za delší neaktivitu, tvoje odpověď mi nějak unikla ;). Máš to v mailu.
- David Grudl
- Nette Core | 8218
Kravčo mě přeběhl – mi to taky funguje zcela stejně bez volání
alphablending
(viz například watermarky na www.vitalita.cz) a to
i s obrázky, které jsi mi poslal. Můžeš to ověřit znovu, nebo
lokalizovat, jestli to souvisí s nějakou verzí GD / PHP?
- Erik Ferčák
- Člen | 10
Obe uvedené riešenia fungujú, len ak je parameter opacity = 100. Akonáhle nastavim opacity < 100, tak strácam alfa kanál.
- kravčo
- Člen | 721
honzakuchar napsal(a):
Verze PHP? Verze GD?
To je asi celkom jedno, keďže funkcia, ktorá sa tam pri 0 < opacity < 100 využíva zrejme zahadzuje/ignoruje alfa kanál
gdImageCopyMerge():
/* This function is a substitute for real alpha channel operations, so it doesn't pay attention to the alpha channel. */
Aj celkom presne nerozumiem, čo tým celým chcel autor povedať, druhý riadok hovorí zreteľne – neberie na zreteľ alfa kanál.
V php dokumentácii sa v poznámkach objavili implementácie, ktoré alfa kanál zvládnu, no prebehol som ich len letmo…
- Erik Ferčák
- Člen | 10
kravčo napsal(a):
gdImageCopyMerge():
/* This function is a substitute for real alpha channel operations, so it doesn't pay attention to the alpha channel. */
Aj celkom presne nerozumiem, čo tým celým chcel autor povedať, druhý riadok hovorí zreteľne – neberie na zreteľ alfa kanál.
V php dokumentácii sa v poznámkach objavili implementácie, ktoré alfa kanál zvládnu, no prebehol som ich len letmo…
Chcel som poukázať na vlastnosť, ktorá mi v Nette\Image chýba. V dokumentácii sa žiadna limitácia neuvádza.
Navrhujem nahradiť použitie imagecopymerge jedným z riešení na php.net. Z riešení uvedených na php.net mi funguje toto: http://www.php.net/…opymerge.php#…