Vodotisk

Školení, která pořádám

Původní obrázekOsobně nejsem příznivcem znehodnocování obrázků přidáním vodotisku, ale někdy to může být jediná možnost, jak se ubránit jejich rozkradení. V PHP se pro vložení vodotisku dá použít funkce imagecopymerge, ve které lze určit, jak moc má cílový obrázek překrýt obrázek původní. Následující kód např. načte vodotisk ze souboru $watermark a vloží ho do pravého dolního rohu plnobarevného obrázku $img:

<?php
$imagesize_watermark = getimagesize($watermark);
if ($imagesize_watermark && $imagesize_watermark[2] <= 3) {
    $img_watermark = ($imagesize_watermark[2] == 2 ? imagecreatefromjpeg($watermark) : ($imagesize_watermark[2] == 1 ? imagecreatefromgif($watermark) : imagecreatefrompng($watermark)));
    imagecopymerge($img, $img_watermark, imagesx($img) - $imagesize_watermark[0] - 5, imagesy($img) - $imagesize_watermark[1] - 5, 0, 0, $imagesize_watermark[0], $imagesize_watermark[1], 50);
}
?>

Po aplikaci vodotiskuKdyž už obrázky vodotiskem znehodnotíme, je vhodné si v adresáři nedostupném z webu uložit i jejich originál pro případ, že bychom vodotisk chtěli v budoucnu změnit. Pokud na to zapomeneme a máme k dispozici obrázek použitý pro vodotisk, můžeme ho z obrázků zpětně odstranit:

<?php
function orig_color($result, $watermark, $component, $pct = 50) {
    // result = pct * (1 - alpha) * watermark + (1 - pct + alpha * pct) * orig
    return ($result[$component] - $pct / 100 * (1 - $watermark["alpha"] / 127) * $watermark[$component]) / (1 - $pct / 100 + $watermark["alpha"] / 127 * $pct / 100);
}

for ($j=0; $j < imagesy($img_watermark); $j++) {
    for ($i=0; $i < imagesx($img_watermark); $i++) {
        $color = imagecolorsforindex($img, imagecolorat($img, $i, $j));
        $color2 = imagecolorsforindex($img_watermark, imagecolorat($img_watermark, $i, $j));
        imagesetpixel($img, $i, $j, (orig_color($color, $color2, "red") << 16) + (orig_color($color, $color2, "green") << 8) + orig_color($color, $color2, "blue"));
    }
}
?>

Po odstranění vodotiskuPokud byl výsledek uložen ve ztrátovém formátu (obvykle JPG), zůstanou po vodotisku patrné stopy způsobené nepřesným uložením.

Jakub Vrána, Řešení problému, 1.12.2006, diskuse: 24 (nové: 0)

Diskuse

Strom?:

Nevim jestli je to stastne reseni, prece kdyz uz nahravam neaky obrazek na servr napred si nekam zalohuju original a potom teprv z toho udelam vodotisk, nez udelat vodotisk a pak to ho odstranovat.(Pokud autor nechtel nahodou ukazat jak ho zas zpetne odstranit :)

ikona Jakub Vrána OpenID:

Vždyť to přesně takhle je napsané v článku: "Když už obrázky vodotiskem znehodnotíme, je vhodné si v adresáři nedostupném z webu uložit i jejich originál" a "Pokud na to zapomeneme a máme k dispozici obrázek použitý pro vodotisk, můžeme ho z obrázků zpětně odstranit".

Trupik:

Již před nějakým časem jsem napsal článek, který se právě tímto zabývá. Myslím, že moje funkce je o něco víc připravená k okamžitému nasazení (pomocí parametrů lze snadno ovládat umístění watermarku na obrázku), takže:
http://trupik.aspweb.cz/programovani/php/watermark-v-php.aspx

Strom?:

Tak v tom pripade se omlouvam moje chyba :)

pa3k:

Len malá poznámka. Pod pojmom vodotisk (vodotlač) je obvykle chápené niečo malinko iné. Za vodotlač (watermarkt) by som označil skôr niečo takéto: http://kvalitne.sk/sample/DSCF2396m+WM.jpg
Robí sa to použitím vodoznaku vo formáte png s nastaveným alfa kanálom pre priehľadnosť. Možno to niekomu pomôže.

<?php
function image_overlap($background, $foreground) {

    $insertWidth = imagesx($foreground);
    $insertHeight = imagesy($foreground);

    $imageWidth = imagesx($background);
    $imageHeight = imagesy($background);

    imagealphablending($foreground, TRUE);
    imagecopy(
        $background,
        $foreground,
        0,
        $imageHeight-26,
        0,
        0,
        $imageWidth,
        26
   
);

    imagealphablending($foreground,FALSE);
    imagesavealpha($foreground,TRUE);

    return $background;

}
?>

ikona Jakub Vrána OpenID:

Zkus popsat slovy, jaký je rozdíl mezi vodoznakem v mém pojetí a v tvém pojetí. Já žádný rozdíl nevidím.

pa3k:

Jabub sorry, nepostrehol som, že príklad, ktorý uvádzaš vie aj priehľadnosť. Ani pri detailnom skúmaní toho výsledného obrázku mi to nedošlo. Chcelo by to asi lepší príklad :) Z kódu je to ale jasné, už som si všimol, že je použitý posledný parameter funkcie imagecopymerge pre priehľadnosť. O tejto možnosti som vôbec netušil. Ono bez priehľadnosti by sa vlastne nedal spätne dopočítať ten pôvodný obrázok. Drobný rozdiel tam ale predsalen je. Pri použití png s alfa kanálom, je výhoda v tom, že vodoznak môže mať rôzne stupne priehľadnosti, teda dá sa vytvoriť napríklad postupný prechod a podobné srandičky.

png vodoznak s alfa kanálom:
http://kvalitne.sk/sample/wm.png
výsledok:
http://kvalitne.sk/sample/DSCF2396m+WM2.jpg

Martin:

Já vidím rozdíl při použití 24bit png. Verze v článku s imagecopymerge nechce pracovat s alfa kanálem, zatímco imagecopy ho použije a tedy průhlednost png se zachová. U gif je to jedno.

Johnyz:

Ahoj, zkoušel jsem ten skript a z nepochopitelného důvodu (pro mne) mi to hází tuto chybu (u všech imagesx a imagesy):

Warning: imagesx(): supplied argument is not a valid Image resource in ........... on line 86

Obrázky jsem hodil přímo do rootu, kde je skript
<?php
$background
= 'Hell.jpg';
$foreground = 'vodotisk.png';
?>

Nevíte někdo, co s tím?

ikona Jakub Vrána OpenID:

Přesně, jak říká chybová hláška - $foreground a $background musí být Image resource. Tedy:
<?php
$background
= imagecreatefromjpeg('Hell.jpg');
$foreground = imagecreatefromjpeg('vodotisk.png');
?>

Johnyz:

DÍKY !

Blizard:

Ahoj, chtěl jsem využít tvůj script. Ale hlásí mi to chyby. A opravdu si nevím rady.

Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]: '../vodotisk.png' is not a valid JPEG file in ...

Warning: imagesx(): supplied argument is not a valid Image resource in ...

Warning: imagesy(): supplied argument is not a valid Image resource in ...

Warning: imagealphablending(): supplied argument is not a valid Image resource ...

Warning: imagecopy(): supplied argument is not a valid Image resource in ...

Warning: imagealphablending(): supplied argument is not a valid Image resource in ...

Warning: imagesavealpha(): supplied argument is not a valid Image resource in ...

ikona v6ak:

Ehm, přečti si první chybovou hlášku a může ti to být jasný.

Blizard:

No už jsem to vyřešil :). Ale Obrázek na kterém by měl být ten vodotisk. Tak je stále stejný.

Stujky:

Poprosim o radu,

kdyz do promene $watermark vlozim obrazek v .png, vysledek je jen pruhledny obdelnik. GIF mi funguje bez problemu.

Prosim v cem je problem?

dekuji

MCleaner:

Zdravim,

mam takovy postreh a byl bych rad, pokud mi ho tu nekdo z vas potvrdi.
Trochu jsem s vkladanim vodoznaku do obrazku laboroval a pokud jsem pouzil kombinaci JPG (hlavni obrazek) a GIF (vkladany vodoznak), tak vysledek byl dle ocekavani. Pokud jsem ale pouzil JPG s PNG (ktery mel nastavenou pruhlednost) tak ve vyslednem obrazku byla pruhlednost puvodniho PNG zrejme zrusena, protoze pruhledna mista puvodniho PNG byla na vyslednem obrazku normalne videt. Nakonec jsem prisel na to, ze tato kombinace funguje (JPG, PNG) pokud misto funkce imagecopymerge pouziji pouze funkci imagecopy. Pak je vysledek tak jak bych chtel a puvodni pruhlednost PNG je ve vysledku spravne videt (vlastne nevidet :) ). Je tento zpusob spravny nebo je jina moznost jak spravne spojit JPG a PNG s pruhlednosti pomoci imagecopymerge?
Diky.

flam:

Přesně s tímto jsem se taky potýkal, akorát místo funkce ImageCopy() jsem použil ImageCopyResized() - také fungovalo. Jakmile jsem použil funkci ImageCopyMerge() na vodotisk ve formátu PNG, tak vložený vodoznak měl s původním obrázkem pramálo společného.

Juraj Krivda:

Použi funkciu imagecopy miesto ImageCopyMerge

Miroslav:

Zdravím Tě, Jakube. Díky za Tvůj web, člověk najde, co hledá, když hledá. :-) Zrovna článek http://php.vrana.cz/vodotisk.php mi moc pomohl. Žel jsem puntičkář a z PNG s alfa kanálem chci dostat 100% výsledek, což se mi nedaří stejně jako u http://kvalitne.sk/sample/DSCF2396m+WM2.jpg - jde mi konkrétně o roztřepení okrajů vodotisku. Je to věc PHP knihovny, nebo zdrojového PNG souboru? Předem díky za případnou odpověď.

dust:

trochu offtopic, ale nemohu si pomoci. SUPER WEB, diky za nej

Pinqui:

Prosím mám dotaz. Jak vložím do obrázku, který budu uploadovat přez formulář šikmě pod sebou třeba 3 texty přez obrázek??? Jde třebas o to když budu dělat i miniatury, tak aby byl ten text taky vidět. Děkuji

Francek Vosmrádlo:

V PHP, za pomoci funkcí knihovny GD si můžeš:
* vytvořit pomocný obrázek (v tomto případě může/měl by být s indexovanými barvami),
* vložit do něj tvůj text,
* obrázek s tímto textem natočit o požadovaný úhel,
* určit si barvu pozadí jako průhlednou,
* obrázek použít jako vodoznak.
Pokud víš, co v těch řádkách bude (a je to konstantní), pak by mi přišlo lepší udělat si tento natočený text v nějakým grafickým editoru a pak ho jako obrázek též používat. Výše popsané řešení je vhodné, pokud by se onen text měl měnit.

ikona Ghostshape:

Taky díky, netušil jsem, že je to až takhle jednoduché..

Šimon:

Ahoj. Zajímalo by mě jestli můžu zadat umístění do obrázku třeba procenty, nebo tam dát nějaký výpočet kdyby byl obrázek třeba na výšku, vodotisk by se schoval pryč, jde mi o to že mám fotky různých velikostí a nechce se mi to předělávat na 140 dalších fotek... možná bych to mohl i zautomatizovat nějakým cyklem - mám fotky 1.jpg, 2.jpg, 3.jpg...

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.