<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ROAE-Blog &#187; Durchschnittsfarbe</title>
	<atom:link href="http://blog.root-of-all-evil.com/tag/durchschnittsfarbe/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.root-of-all-evil.com</link>
	<description>Studium, Codeing und Gedachtes</description>
	<lastBuildDate>Mon, 30 Jan 2012 22:58:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Thumbnails erzeugen und Durchschnittsfarbe in PHP ermitteln</title>
		<link>http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/</link>
		<comments>http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 19:36:22 +0000</pubDate>
		<dc:creator>Philipp</dc:creator>
				<category><![CDATA[Codeschnipsel]]></category>
		<category><![CDATA[Guides]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projekt]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Durchschnittsfarbe]]></category>
		<category><![CDATA[Imagecolorat]]></category>
		<category><![CDATA[Imagecopyresampled]]></category>
		<category><![CDATA[Thumbnails generieren]]></category>

		<guid isPermaLink="false">http://blog.root-of-all-evil.com/?p=435</guid>
		<description><![CDATA[<a href="http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/" title="Thumbnails erzeugen und Durchschnittsfarbe in PHP ermitteln"></a>Eines meiner etwas zurückliegenden Projekte zwang mich externe Bilder durch meinen Server zu laden, zu verkleinern und schließlich auch die Durchschnittsfarbe zu berechnen. Aus Gründen der Performancesteigerung war ich nie ein Fan davon die Durchschnittsfarbe Pixel für Pixel des Originalbildes &#8230;<p class="read-more"><a href="http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/" title="Thumbnails erzeugen und Durchschnittsfarbe in PHP ermitteln"></a><p>Eines meiner etwas <a title="qolors.net Visual Bookmarking" href="http://www.qolors.net" target="_blank">zurückliegenden Projekte</a> zwang mich externe Bilder durch meinen Server zu laden, zu verkleinern und schließlich auch die Durchschnittsfarbe zu berechnen. Aus Gründen der Performancesteigerung war ich nie ein Fan davon die Durchschnittsfarbe Pixel für Pixel des Originalbildes zu berechnen. <a href="http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln#durchschnittsfarbe" title="zum Berechnen der Durchschnittsfarbe springen">Es gibt eine viel elegantere und fast genauso exakte Lösung</a>:</p>
<p><span id="more-435"></span>Unser Ziel: Wir möchten ein Bild (jpg, gif, png) über einen HTTP-Stream laden,  dieses lokal auf dem Server speichern, ein entsprechendes Thumbnail  (eine verkleinerte Version) erzeugen, speichern und schlussendlich die  dominierende &#8211; oder auch durchschnittliche &#8211; Farbe im Bild berechnen und  abspeichern. Eventuell möchten wir zusätzlich alles in einer Datenbank  hinterlegen &#8211; das soll aber zunächst außerhalb unserer Betrachtung  liegen.</p>
<p>Für das Berechnen der Durchschnittsfarbe gibt es einen wunderbar  einfachen Trick. Doch dazu später mehr. Beginnen wir zunächst einmal mit  einer Konstante und einer Funktion, die wir später noch benötigen:</p>
<pre class="php" title="code">DEFINE('CTX', stream_context_create(array(
    'http' =&gt; array(
        'timeout' =&gt; 20,
        'method' =&gt; 'get',
        'header' =&gt; 'Referer: XYZ'
    )
)));</pre>
<p>Unsere Konstante CTX ist also ein array. Wir benötigen es für unsere  HTTP-Anfrage, mit der wir das gewünschte Bild auf unseren Server laden.  Für diese Anfrage verwenden wir die HTTP-GET-Methode, definieren einen  Timeout von maximal 20 Sekunden und senden einen Referer im Header, den  ich hier mal einfach nur &#8220;XYZ&#8221; genannt habe.</p>
<pre class="php" title="code">function randomstring_creator($len = 20) {
    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $string = '';
    mt_srand((double) microtime() * 1000000);
    for($i = 0; $i &lt; $len; $i++) {
        $string .= $chars{mt_rand(0, strlen($chars))};
    }
    return($string);
}</pre>
<p>Die Funktion randomstring_creator() generiert uns eine zufällige Zeichenfolge mit einer beliebigen Länge. Wir benötigen diese Funktion, da wir in diesem Beispiel die Bilder lokal unter einem zufälligem Namen speichern werden.</p>
<p>Weiter geht es mit unseren Klassen. Beginnen wir mit der Klasse <em>Image</em>:</p>
<pre class="php" title="code">class Image {
    var $img;
    var $source;
    var $local;
    var $dimX;
    var $dimY;
    var $avg_colour;
    function get($source, $quality = 90) {
// siehe unten
    }
    function calc_avg_colour() {
// siehe unten
    }
}</pre>
<p>Unsere Klasse besitzt also die Eigenschaften <em>source </em>(die Url,  von der das Bild stammt), <em>local </em>(den lokalen Speicherpfad), <em>dimX</em>,  <em>dimY </em>(die Abmessungen des Bildes in Pixel) und <em>avg_colour</em> (den farblichen Durchschnittswert als HEX-Code in der Form rrggbb). Die  Eigenschaft <em>img </em>ist eine Referenz auf das Image-Objekt, dass ich  aber später noch näher beleuchten werde.</p>
<p>Die beiden Funktionen <em>get()</em> und <em>calc_avg_colour()</em> der  Klasse sollten selbsterklärend sein. Mit der Funktion <em>get()</em>, die  gleichzeitig auch als Konstruktor dient, laden wir das Bild, dass unter <em>source </em>zu finden ist, auf unseren Server und speichern es in der  gewünschten JPEG-Qualität (90 als Standard) lokal.</p>
<p><em>calc_avg_colour()</em> berechnet &#8211; wie der Name schon sagt &#8211; die  Durchschnittsfarbe des in der Eigenschaft <em>img</em> gespeicherten  Bildes.</p>
<p>Wir wollen zusätzlich aber auch kleine Abbilder des Originalbildes  erstellen und erweitern dazu unsere <em>Image</em>-Klasse um die Klasse <em>Thumbnail</em>:</p>
<pre class="php" title="code">class Thumbnail extends Image {
    function create($parent, $X = 300, $Y = 300, $quality = 60) {
// siehe unten
    }
}</pre>
<p>Diese Erweiterung besitzt zunächst nur eine Funktion, mit der das  Thumbnail erstellt wird. Die übergebene Variable <em>parent </em>enthält  dabei eine bereits existierende <em>Image</em>-Klasse, die  herunterskaliert werden soll. Die maximale Breite und Höhe werden mit  den Variablen <em>X</em> und <em>Y</em> (standard bei 300 Pixel) übergeben.  Die JPEG-Qualität beträgt standardmäßig nur 60.</p>
<p>Das eigentliche Programm sieht dann nur noch so aus:</p>
<pre class="php" title="code">$imgurl = 'original.jpg';
// neues Objekt der Klasse Image erzeugen
$img = new Image;
// Bild aus der imgurl laden
if($img-&gt;get($imgurl)) {
    // ein Objekt der Klasse Thumbnail erzeugen
    $thumb = new Thumbnail;
    // und ein Thumbnail des oben definierten Objektes der Klasse Image generieren
    $thumb-&gt;create($img, 300, 300);
    // dann noch die Durschschnittsfarbe berechnen
    $thumb-&gt;calc_avg_colour();
    // und Daten ausgeben... fertig
    echo('Image: ' . $img-&gt;source . "\n");
    echo('Thumbnail: ' . $thumb-&gt;source . "\n");
    echo('Average colour: #' . $thumb-&gt;avg_colour . "\n");
} else {
    echo('Could not get the image.');
}</pre>
<p>So, dann sehen wir uns also mal unsere Funktionen der Klassen an.  Beginnen wir mit der Funktion <em>get()</em>:</p>
<pre class="php" title="code">function get($source, $quality = 90) {
    $this-&gt;source = $source;
    // wir laden das Bild von $source:
    if(($file = file_get_contents($this-&gt;source, false, CTX))) {
        // wenn erfolgreich, erzeugen wir mit den geladenen Daten
        // ein neues Bild und speichern dieses in der Eigenschaft img
        $this-&gt;img = imagecreatefromstring($file);
        // wir lesen die Höhe und Breite des Bildes aus
        $this-&gt;dimX = imagesx($this-&gt;img);
        $this-&gt;dimY = imagesy($this-&gt;img);
        // und speichern das Bild unter zufälligem Namen mit imagejpeg lokal im Ordner "raw"
        $this-&gt;local = 'raw/' . randomstring_creator() . '.jpg';
        imagejpeg($this-&gt;img, $this-&gt;local, $quality);
        // bei Erfolg true zurückgeben
        return(true);
    } else {
        // false, wenn das Bild nicht geladen werden konnte
        return(false);
    }
}</pre>
<p>Ein Thumbnail erzeugen wir mit dieser Funktion der Klasse <em>Thumbnail</em>:</p>
<pre class="php" title="code">function create($parent, $X = 300, $Y = 300, $quality = 60) {
    // zunächst die vorläufigen Abmessungen speichern
    $this-&gt;dimX = $X;
    $this-&gt;dimY = $Y;
    // die Abmessungen und deren Verhältnis des Originalbildes holen
    $origX = $parent-&gt;dimX;
    $origY = $parent-&gt;dimY;
    $ratio = $origX / $origY;
    // wenn das Originalbild breiter als hoch ist, kürzen wir die Höhe
    if($X / $Y &gt; $ratio) {
        $this-&gt;dimX = $Y * $ratio;
    } else {
    // wenn das Originalbild höher als breit ist, kürzen wir die Breite
        $this-&gt;dimY = $X / $ratio;
    }
    // hier erstellen wir ein neues Bild mit den oben berechneten Abmessungen
    $this-&gt;img = imagecreatetruecolor($this-&gt;dimX, $this-&gt;dimY);
    // und kopieren das Originalbild einfach in das eben erstellte kleinere, dabei wird es verkleinert
    imagecopyresampled($this-&gt;img, $parent-&gt;img, 0, 0, 0, 0, $this-&gt;dimX, $this-&gt;dimY, $origX, $origY);
    // jetzt speichern wir das neue Thumbnail noch unter zufälligem Namen im Ordner "thumb"
    $this-&gt;source = $parent-&gt;local;
    $this-&gt;local = 'thumb/' . randomstring_creator() . '.jpg';
    imagejpeg($this-&gt;img, $this-&gt;local, $quality);
}</pre>
<p>Das Herzstück: Wir wollen die  Durchschnittsfarbe ermitteln. Dazu könnten wir einfach alle Farbwerte  aller Pixel zusammen addieren und dann durch die Anzahl der Pixel  teilen. Bei einem Thumbnail von der Größe 300 x 300 Pixel, würden wir  aber eine Schleife mit 90.000 Durchläufen benötigen. Es gibt einen  besseren Weg &#8211; einen ganz logischen Trick.<br />
<a name="durchschnittsfarbe"></a><br />
<h3>Durchschnittsfarbe berechnen</h3>
<p>Wir haben oben beim Erstellen des Thumbnails die Funktion <em>imagecopyresampled()</em> verwendet. Was wenn wir unser Thumbnail einfach auf eine Größe von 1&#215;1  Pixel skalieren? Genau: Es bleibt ein Pixel mit der Durschnittsfarbe  übrig. Dessen Farbe auszulesen ist mit <em>imagecolorat()</em> dann nur  noch eine Kleinigkeit. Los gehts:</p>
<pre class="php" title="code">function calc_avg_colour() {
    // ein temporäres Bild mit den Abmessungen 1x1 Pixel erstellen
    $avrg = imagecreatetruecolor(1, 1);
    // Das Thumbnail einfach reinkopieren, dabei auf 1x1 Pixel skalieren
    imagecopyresampled($avrg, $this-&gt;img, 0, 0, 0, 0, 1, 1, $this-&gt;dimX, $this-&gt;dimY);
    // Die Farbe des verbleibenden Pixels auslesen
    $rgb = imagecolorat($avrg, 0, 0);
    // Das temporäre Bild wieder löschen
    imagedestroy($avrg);
    // Und die Farbe in HEX umwandeln
    $r = dechex($rgb &gt;&gt; 16);
    $g = dechex($rgb &gt;&gt; 8 &amp; 255);
    $b = dechex($rgb &amp; 255);
    if(strlen($r) &lt; 2) $r = 0 . $r;
    if(strlen($g) &lt; 2) $g = 0 . $g;
    if(strlen($b) &lt; 2) $b = 0 . $b;
    // tataaaa... da ist unsere Durchschnittsfarbe:
    $this-&gt;avg_colour = $r . $g . $b;
}</pre>
<p>Super. Das wäre es. Ende und aus.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.root-of-all-evil.com/2010/02/thumbnails-erzeugen-und-durchschnittsfarbe-in-php-ermitteln/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

