Wasserzeichen / Watermark für Produktbilder

Hallo liebe community,

anbei ein simples script dass alle eure Artikelbilder automatisch mit einem Wasserzeichen versieht. Ist noch Verbesserungswürdig, aber dafür ist es ja auch open source:

Datei anlegen views/watermark.php:

<?php

class Watermark extends oxUBase{
	
	public function render(){
		// load source image to memory
		$image = $this->_imagecreatefromfile(getShopBasePath().oxConfig::getParameter('image'));		       
		if (!$image) die('Unable to open image');
		
		// load watermark to memory
		$wm = $this->_imagecreatefromfile(getShopBasePath()."out/pictures/watermark.png");
		if (!$wm) die('Unable to open watermark');
		
		$maxw = imagesx($image);
		$maxh = imagesy($image);
		
		$watermark = imagecreatetruecolor($maxw, $maxh);
		imagealphablending($watermark, true);
		imagesavealpha($watermark, true);
		imagefill( $watermark, 0, 0, imagecolorallocatealpha( $watermark, 0, 0, 0, 127 ) );
		imagecopyresized($watermark,$wm,0,0,0,0,$maxw,$maxh,imagesx($wm),imagesy($wm));
		
		// calculate the position of the watermark in the output image (the
		// watermark shall be placed in the lower right corner)
		$watermark_pos_x = imagesx($image) / 2 - imagesx($watermark) / 2;
		$watermark_pos_y = imagesy($image) / 2 - imagesy($watermark) / 2;
		
		// merge the source image and the watermark
		imagecopy($image, $watermark,  $watermark_pos_x, $watermark_pos_y, 0, 0, imagesx($watermark), imagesy($watermark));
		
		// output watermarked image to browser
		header('Content-Type: image/png');
		imagepng($image, '', 0);  // use best image quality (100)
		
		// remove the images from memory
		imagedestroy($image);
		imagedestroy($watermark);
		
		exit();
	}
	
	protected function _imagecreatefromfile($image_path) {
		// retrieve the type of the provided image file
		if(!file_exists($image_path)) return;
		list($width, $height, $image_type) = getimagesize($image_path);
	
		// select the appropriate imagecreatefrom* function based on the determined
		// image type
		switch ($image_type)
		{
		  case IMAGETYPE_GIF: return imagecreatefromgif($image_path); break;
		  case IMAGETYPE_JPEG: return imagecreatefromjpeg($image_path); break;
		  case IMAGETYPE_PNG: 
		  	$img = imagecreatefrompng($image_path); 
		  	imagealphablending($img, true); // setting alpha blending on
			imagesavealpha($img, true); // save alphablending setting (important)		
			return $img;
		  	break;
		  default: return ''; break;
		}
	}

  
	
}

Nun im Ordner out/pictures/ ein Bild Namens watermark.png ablegen und folgendes in die .htaccess Datei eintragen:

<IfModule mod_rewrite.c>

Options +FollowSymLinks
RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_URI} oxseo\.php$
RewriteCond %{QUERY_STRING} mod_rewrite_module_is=off
RewriteRule oxseo\.php$ oxseo.php?mod_rewrite_module_is=on [L]

#Das folgende kommt dazu, am besten an diese Stelle
RewriteCond %{REQUEST_URI} (\/out\/pictures\/)
RewriteRule ^(.*\.(gif|jp?g|png))$ /index.php?cl=watermark&image=$1 [NC]

...

Viel spaß damit, Verbesserungen usw. könnt ihr gerne posten (z.B. ein caching der generierten Bilder wäre nicht schlecht)

Getestet unter CE 4.4.5_31315

Lizenz ist WTFPL -> http://sam.zoy.org/wtfpl/

Hallo,

danke :slight_smile:
Ich hab’s auf den Tutorial Ideen eingetragen und auf der Uservoice:
http://wiki.oxidforge.org/Tutorial_Ideas

Gruß

Vielen, vielen, vielen Dank für diese kleine und feine aber geniale, funktionale und direkt benötigte Modul.

Rating: :):):):):slight_smile:

Kleine Erweiterung für caching, Datei views/watermark.php:

<?php

class Watermark extends oxUBase{
	
	public function render(){
		// load source image to memory
		$sImage = getShopBasePath().oxConfig::getParameter('image');
		$sImageKey = md5($sImage);
		$sCachePath = getShopBasePath()."tmp/".$sImageKey.".png";
		header('Content-Type: image/png');
		
		// calc an offset of 7 days
		$offset = 3600 * 24 * 7;
		// calc the string in GMT not localtime and add the offset
		$expire = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
		//output the HTTP header
		header($expire);

		if(file_exists($sCachePath)){
			echo file_get_contents($sCachePath);
		}else{
			$image = $this->_imagecreatefromfile(getShopBasePath().oxConfig::getParameter('image'));		       
			if (!$image) die('Unable to open image');
			
			// load watermark to memory
			$wm = $this->_imagecreatefromfile(getShopBasePath()."out/pictures/watermark.png");
			if (!$wm) die('Unable to open watermark');
			
			$maxw = imagesx($image);
			$maxh = imagesy($image);
			
			$watermark = imagecreatetruecolor($maxw, $maxh);
			imagealphablending($watermark, true);
			imagesavealpha($watermark, true);
			imagefill( $watermark, 0, 0, imagecolorallocatealpha( $watermark, 0, 0, 0, 127 ) );
			imagecopyresized($watermark,$wm,0,0,0,0,$maxw,$maxh,imagesx($wm),imagesy($wm));
			
			// calculate the position of the watermark in the output image (the
			// watermark shall be placed in the lower right corner)
			$watermark_pos_x = imagesx($image) / 2 - imagesx($watermark) / 2;
			$watermark_pos_y = imagesy($image) / 2 - imagesy($watermark) / 2;
			
			// merge the source image and the watermark
			imagecopy($image, $watermark,  $watermark_pos_x, $watermark_pos_y, 0, 0, imagesx($watermark), imagesy($watermark));
			
			// output watermarked image to browser and store to cache	
			imagepng($image, $sCachePath, 0);  // use best image quality (100)
			imagepng($image, '', 0);
			
			// remove the images from memory
			imagedestroy($image);
			imagedestroy($watermark);
		}
		
		
		
		exit();
	}
	
	protected function _imagecreatefromfile($image_path) {
		// retrieve the type of the provided image file
		if(!file_exists($image_path)) return;
		list($width, $height, $image_type) = getimagesize($image_path);
	
		// select the appropriate imagecreatefrom* function based on the determined
		// image type
		switch ($image_type)
		{
		  case IMAGETYPE_GIF: return imagecreatefromgif($image_path); break;
		  case IMAGETYPE_JPEG: return imagecreatefromjpeg($image_path); break;
		  case IMAGETYPE_PNG: 
		  	$img = imagecreatefrompng($image_path); 
		  	imagealphablending($img, true); // setting alpha blending on
			imagesavealpha($img, true); // save alphablending setting (important)		
			return $img;
		  	break;
		  default: return ''; break;
		}
	}

  
	
}

Eine ganz dumme Frage, ich weiß, aber um den Eintrag in die .htaccess zu machen, muss ich diese erstmal finden. Im Grundpaket miener Shop Installation finde ich die ohne Probleme, aber auf dem Server nicht. Wie muss ich die Änderung vornehmen und muss ich dazu überhaupt eine Datei ändern?!?
:confused:

Wie Ihr sicher merkt habe ich keinen Plan von htaccess… also nochmal sorry, für die Frage, aber ich komm nicht weiter…

Danke schonmal!

Auf dem Server liegt die .htaccess direkt im Rootlevel, also im obersten Level der Shopinstallation.

Der Teil hier muss zusätzlich mit rein:

#Das folgende kommt dazu, am besten an diese Stelle
RewriteCond %{REQUEST_URI} (\/out\/pictures\/)
RewriteRule ^(.*\.(gif|jp?g|png))$ /index.php?cl=watermark&image=$1 [NC]

Ich bin einfach zu gut, ehrlich… ich hab die versteckten Datein im FTP Programm nihct anzeigen lassen… deswegen hab ichs nicht gefunden. Die Stelle war also schon richtig.

Danke!

Nur leider wird das Wasserzeichen in einer verzerrten Größe angezeigt und ist somit nicht wirklich brauchbar. Man kann doch bestimmt die Größe festlegen, damit er nicht verzerrt!?!?

Darf ich da nochmals um Hilfe bitten?
Danke

Bug Fix:
in der Datei htaccess
Aus der Zeile:
RewriteRule ^(..(gif|jp?g|png))$ /index.php?cl=watermark&image=$1 [NC]
in
RewriteRule ^(.
.(gif|jp?g|png))$ index.php?cl=watermark&image=$1 [NC]
überschreiben.

Dann funktioniert bei euch auch mit XAMPP

@Rackham
Nun zu deinem Problem:
Suche:
$maxw = imagesx($image);
$maxh = imagesy($image);
ersetze durch:
$maxw = imagesx($wm);
$maxh = imagesy($wm);
und Cash Leeren sonst sihst du keine änderung.

Diese Änderung verzährt das Wasserzeichen nicht mehr auf die gesamte Fläche des Bildes, sondern behält das original weiterhin.
Nachteil ist das bei kleinen bilder vom wasserzeichen garnicht mehr zusehen ist.

Aber ich denke das Modul sollte sowieso erweitert und nur auf die zoom bilder angewand werden, so das die icons davon verschont werden :slight_smile:

Aber ich denke das Modul sollte sowieso erweitert und nur auf die zoom bilder angewand werden, so das die icons davon verschont werden

Dafür ist es ja quelloffen, jeder darf mitmachen :wink:

Danke Oxy! Das funzt zwar so, ist aber leider in den Zooms und den Thumbs ein wenig doof. Sieht mir ehrlich gesagt nicht gut genug aus, als dass ich es so drin behalten würde. Er schneidet dann halt bei den Thumbs Teile ab wenn zu groß usw.

Irgendwie muss man doch die Variable auf die Breite beziehen können und sowas definieren können wie “maxw =image” und dann “maxh = maxw*2” oder so. Dann könnte man die Bilddatei einfach 2 mal so breit wie hoch machen und er würde es immer korrekt berechnen, zumindest solange die Thunbs, Bilder und Zooms die selben Seitenverhältnisse haben.

Kann da evtl jemand was mit anfangen? Wäre klasse.

Ebenso kann man natürlich auch die Datei also das Bild selbst einfach in der maximalen gewünschten Größe mit den selben Seitenverhältnissen wie die Produktbilder anlegen. Ist aber ehrlich gesagt ein riesen Pfusch, alleine wenn ich an den zusätzlichen Traffic denke, der durch die größeren Datein entsteht.

Wenn Thumbs, Images und Zoom das gleicher Grössenverhältnis haben, muß das Watermarkimage ebenfalls das gleiche Grössenverhältnis haben. Wenn du dann das
Watermarkimage auch noch auf die größte Größe der Bilder bringst, sollte eigentlich keine Verzerrung auftreten.

Selbst wenn du nur ein kleines Watermark-Bild mit gleichem Größenverhältnis benutzt, wirst du immer Verzerrungen haben, da bei der Vergrößerung des Bildes immer Verzerrungen und andere Effekte auftreten (Selbst in Photoshop). Fehlende Bildinformationen können nunmal nicht herbeigezaubert werden :).

edit:

Eine andere Möglichkeit wäre natürlich für die entsprechenden Bildgrößen unterschiedliche, angepasste Watermark-Images zu verwenden. Damit würde das Skalieren ganz entfallen.

hat jemand das Wasserzeichenmodul schon mit der Version 4.5.4 am laufen?

bei mir werden nach der Installation keine Bilder mehr angezeigt.

Hallo,

da es ja anscheinend noch keine lauffähige Version dieses Wasserzeichenmoduls gibt, wollte ich Versuchen eine Version zu programmieren.

Meine Idee ist das Wasserzeichen beim erzeugen der generated-Bilder einzufügen, so dass die erzeugten Bilder ein Wasserzeichen haben und die Bilder im Master Ordner ohne Wasserzeichen hochgeladen werden.

Ich habe eine PhP Datei mit der ich ein Wasserzeichen über ein Bild legen kann, diese muss ich jetzt halt noch mit dem Shop verbinden. Kann mir jemand einen Tipp geben wo ich da am Besten anfange.
Also an welcher Stelle im Core die Bilder vor dem kopieren angepasst werden.

Für Hinweise bzw. Hilfe wäre ich sehr dankbar.

Also bei mir funktioniert das eigentlich ganz gut. Hast du das tmp verzeichnis geleert? Cache vom Browser geleert?

Weiterer Grund könnte sein, dass du erst nachdem du die Funktion (.htaccess-Änderungen) aktiviert hast, Bilder hochgeladen hast?
Da kommen wir nämlich gleich zu meinem Problem:
Sobald die htaccess-Änderungen aktiv geschalten sind, werden weitere Uploads von Bildern unmöglich. d.h. der Rewrite scheint die imggenerator-Funktion auch umzuleiten, sobald sie auf die master-bilder zugreifen will. (master-bilder unter /out/pictures/master wurden manuell hinzugefügt, die dann von der imggenerator funktion in die verschiedenen verkleinerten Versionen in /out/pictures/generated/ umgewandelt werden - das geht aber nur solang die .htaccess-Änderungen auskommentiert sind)

Meine Frage also: Gibt es eine Möglichkeit in der .htaccess eine RewriteCond hinzuzufügen, die die Generator-Funktion NICHT umleitet?
also in Sinne von: RewriteCond %[abfragende Funktion] ! generatorfunkton.php

Das Modul ist für 4.4.x entwickelt worden, da lief es noch ohne probleme - inzwischen wäre es sicherlich sinniger ohne htaccess zu arbeiten und das ganze watermarking im image processor zu machen (liegt im übrigen unter core/utils/getimg.php - bzw. im oxdynimagegenerator im core Ordner)

Da ich es im Moment nicht brauche wird sich ein anderer erbarmen müssen den oxdynimagegenerator zu überschreiben.

Schade, ich fand die Idee nämlich garnicht schlecht, dass die Bilder nur im Speicher gehalten werden und die Originalen erhalten bleiben. Das bedeutet zwar teils eine große Last für den Server beim erstmaligen Anzeigen der Bilder aber hübsch war es trotzdem. Ich habe mich jetzt auch dazu entschieden, die Bilder beim Import/Upload zu brandmarken und so auch zu speichern, so dass die Serverlast nur beim Import/Upload entsteht. Leider hat es wenig Sinn, meine Lösung hier zu posten, wenn sie fertig ist, da diese nur für eine speziellen Fall eines Imports mit eigens geschrieben Funtionen gebraucht wird.

Dabei fällt mir ein, dass, wenn die getimg-funktion so angepasst wird, dass sie auch nur die Bilder im Speicher verändert, die Originalen auch nicht angefasst werden. Also jedes Mal, wenn ein Bild per get geholt werden soll, brandmarkt die Funktion die Bilder, solange sie nich im Cache liegen.

Hallo,

kann mir jemand sagen ob und wenn ja wie ich die dynimggenerator klasse via Modul überschreiben kann?
Mit einem Modul eintrag oxdynimggenerator => mymodul/mymodul klappt es nicht.

da musst du ein bisschen anders ran, das funktionert indem du in der oxfunctions oder config.inc php folgendes definierst:


if ( !function_exists( "getGeneratorInstanceName" ) ){
    function getGeneratorInstanceName()
    {
        return "MeinKopierterOxDynImageGeneratorKlassenName";
    }
}

Danke für den Tip.

Ich habe allerdings schon anders gelöst. Ich habe in der .htaccess den Eintrag
"RewriteRule (.jpg|.gif|.png)$ core/utils/getimg.php"
in
"RewriteRule (.jpg|.gif|.png)$ core/utils/watermark.php" geändert und diese Datei mit dem angepassten Inhalt von http://wiki.oxidforge.org/Tutorials/image_handling_changes erstellt. Dort wird diese Datei unter custgetimg.php verwendet.

Aber eine Frage habe ich dennoch, kannst du mir sagen wie ich in dieser Datei nun ein Bild aus dem pictures verzeichnis laden kann? Zur Zeit muss ich das Wasserzeichenbild noch in den Ordner core/utils legen.