Návrh na vylepšení Nette\Image

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Petr Motejlek
Člen | 293
+
+1
-

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.

pmg
Člen | 372
+
0
-

Přesně tohle jsem nedávno řešil. K requestu bych ještě přidal automatickou detekci imagemagick, případně fallback na GD.

Petr Motejlek
Člen | 293
+
0
-

Jj, s tím taky souhlasím.

Honza Kuchař
Člen | 1662
+
0
-

Jsem pro oboje. Nedávno jsem to taky řešil. (ale to jsem ještě nedělal s Nette)

David Grudl
Nette Core | 8169
+
0
-

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
+
0
-

Omlouvám se za delší neaktivitu, tvoje odpověď mi nějak unikla ;). Máš to v mailu.

kravčo
Člen | 721
+
0
-

Podľa mojich pokusov úplne stačí

$mark = Image::fromFile('images/watermark.png');
$image = Image::fromFile('images/bg-gradient.png');

$image->place($mark, '50%', '50%');

$image->saveAlpha(true);
$image->send(Image::PNG);
David Grudl
Nette Core | 8169
+
0
-

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?

pmg
Člen | 372
+
0
-

Alphablending je myslím defaultně TRUE.

Erik Ferčák
Člen | 10
+
0
-

Obe uvedené riešenia fungujú, len ak je parameter opacity = 100. Akonáhle nastavim opacity < 100, tak strácam alfa kanál.

Honza Kuchař
Člen | 1662
+
0
-

Verze PHP? Verze GD?

kravčo
Člen | 721
+
0
-

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
+
0
-

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#…