{"id":603,"date":"2012-11-26T13:09:13","date_gmt":"2012-11-26T11:09:13","guid":{"rendered":"http:\/\/www.phreekz.de\/wordpress\/?p=603"},"modified":"2013-04-04T18:03:58","modified_gmt":"2013-04-04T16:03:58","slug":"bilder-per-php-verkleinern","status":"publish","type":"post","link":"http:\/\/www.phreekz.de\/wordpress\/2012\/11\/bilder-per-php-verkleinern\/","title":{"rendered":"[php] Bilder verkleinern"},"content":{"rendered":"<h3>Das Gro\u00dfe kleinmachen<\/h3>\n<p>Der Bildartist m\u00f6chte auch in der Webansicht eine hohe Qualit\u00e4t vorlegen. Entweder man skaliert manuell alle Bilder in der Bildbearbeitung und legt sie auf dem Server ab, oder man \u00fcberl\u00e4sst die Aufgabe dem Server. Voraussetzung f\u00fcr folgende Code-Snippets ist nat\u00fcrlich php. In der Regel ist auf jedem Webserver, auf dem php l\u00e4uft, auch die GDLib installiert. Eine Ansammlung von bilderstellenden und -ver\u00e4ndernden Funktionen.<\/p>\n<h4>Was hab ich auf meinem Server?<\/h4>\n<p><code lang=\"php\">phpinfo();<\/code>listet alle Informationen zur php-Installation auf. Alle Module samt der Einstellungen werden ausgegeben. Nun kann man durchscrollen, um bei den Extensions nach gd bzw. imagick zu schauen. \u00dcbrigens kann man daf\u00fcr auch simple php-Abfragen nutzen:<br \/>\n<code lang=\"php\">if(extension_loaded(\"gd\"))<br \/>\n  {echo\"gdlib is installed<br \/>\";}<br \/>\n  else<br \/>\n  {echo\"gdlib is not here<br \/>\";}<br \/>\nif(extension_loaded(\"imagick\"))<br \/>\n  {echo\"imagemagick is installed<br \/>\";}<br \/>\n  else<br \/>\n  {echo\"imagemagick is not here<br \/>\";}<\/code><\/p>\n<h4>GDlib &#8211; &#8222;Einfaches&#8220; Verkleinern auf 50% bzw. ein festes Ma\u00df<\/h4>\n<p>F\u00fcr das Verkleinern mu\u00df im Vornherein das Endma\u00df bekannt sein, also errechnen wir erstmal die neuen Bildma\u00dfe mittels einfachem Dreisatz. Die zu bearbeitende Bilddatei mu\u00df sich auf dem Server befinden.<br \/>\n<code lang=\"php\">$bildName=\"testbild.jpg\";<\/p>\n<p># -- Ordner Originale<br \/>\n$ordnerO=\".\/Fotos\/\";<br \/>\n# -- Ordner Verkleinerungen<br \/>\n$ordnerK=\".\/Fotos\/thumbs\/\";<\/p>\n<p>$originalBild = $ordnerO.$bildName;<\/p>\n<p># -- Faktor berechnen bei vorgegebener H\u00f6he in px<br \/>\n# -- oX alte Breite -- oY alte H\u00f6he<br \/>\n# -- nX neue Breite -- nY neue H\u00f6he<br \/>\n# -- getimagesize() ist eine gdlib-funktion!<br \/>\n$size = getimagesize($originalBild);<br \/>\n$oY = $size[1];<br \/>\n$oX = $size[0];<\/p>\n<p># -- Breite auf 50% festlegen<br \/>\n$nX = intval($oX*0.5);<br \/>\n$nY = intval($oY*$nX\/$oX);<\/p>\n<p>echo \"Die neuen Bildma\u00dfe (relativ 50% zu Original) sind \";<br \/>\necho \"Breite:\".$nX.\"px und H\u00f6he:\".$nY;<br \/>\necho \"<br \/>\";<\/p>\n<p># -- H\u00f6he auf fix 100px festlegen<br \/>\n# $nY = 100;<br \/>\n# $nX = intval($oX*$nY\/$oY);<br \/>\n# echo \"Die neuen Bildma\u00dfe (fixe Gr\u00f6\u00dfe) sind \";<br \/>\n# echo \"Breite:\".$nX.\"px und H\u00f6he:\".$nY<\/p>\n<p># -- und nun die gdlib rechnen und speichern lassen<br \/>\n$altesBild = ImageCreateFromJPEG($originalBild);<br \/>\n$neuesBild = ImageCreateTrueColor($nX,$nY);<br \/>\n# -- Resized - Pixelwiederholung<br \/>\n# imageCopyResized($neuesBild, $altesBild, 0, 0, 0, 0,$nX, $nY, $oX, $oY);<br \/>\n# echo \".als Resized berechnet<br \/>\";<br \/>\n# -- Resampled = bilinear Algorithm<br \/>\nimageCopyResampled($neuesBild, $altesBild, 0, 0, 0, 0,$nX, $nY, $oX, $oY);<br \/>\nimageJPEG($neuesBild,$ordnerK.\"thumb_\".$bildName);<br \/>\necho \".als Resampled (bilinear) berechnet\";<br \/>\necho \"<br \/>\";<br \/>\n<\/code><br \/>\nW\u00e4hrend imageCopyResized aussieht wie die Pixelwiederholung aus Photoshop (NearestNeighbour-Algorithmus), benutzt imageCopyResampled die bilineare Interpolation, wesentlich besser, aber noch nicht perfekt. Irgendwo irgendwann hab ich nen Codesnippet als php-Funktion gefunden f\u00fcr die bikubische Berechnung. Diese findet sich in den Beitr\u00e4gen unter folgendem Link. <a href=\"http:\/\/www.navioo.com\/php\/docs\/function.imagecopyresampled.php\">php-snippet bicubic resampling for gdlib<\/a> Ich habe den Code um den Farbpalettenteil gek\u00fcrzt, nun sieht er so aus:<\/p>\n<p><code lang=\"php\"><br \/>\n# -- found on - http:\/\/www.navioo.com\/php\/docs\/function.imagecopyresampled.php<br \/>\n# -- written by rob and scott 2007<\/p>\n<p>function imageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)<br \/>\n{<br \/>\n $scaleX = ($src_w - 1) \/ $dst_w;<br \/>\n $scaleY = ($src_h - 1) \/ $dst_h;<br \/>\n $scaleX2 = $scaleX \/ 2.0;<br \/>\n $scaleY2 = $scaleY \/ 2.0;<br \/>\n # is it truecolor? $tc = imageistruecolor($src_img);<br \/>\n for ($y = $src_y; $y < $src_y + $dst_h; $y++)\n {\n   $sY   = $y * $scaleY;\n   $siY  = (int) $sY;\n   $siY2 = (int) $sY + $scaleY2;\n   for ($x = $src_x; $x < $src_x + $dst_w; $x++)\n   {\n     $sX   = $x * $scaleX;\n     $siX  = (int) $sX;\n     $siX2 = (int) $sX + $scaleX2;\n     $c1 = imagecolorat($src_img, $siX, $siY2);\n     $c2 = imagecolorat($src_img, $siX, $siY);\n     $c3 = imagecolorat($src_img, $siX2, $siY2);\n     $c4 = imagecolorat($src_img, $siX2, $siY);\n     $r = (($c1 + $c2 + $c3 + $c4) >> 2) & 0xFF0000;<br \/>\n     $g = ((($c1 & 0xFF00) + ($c2 & 0xFF00) + ($c3 & 0xFF00) + ($c4 & 0xFF00)) >> 2) & 0xFF00;<br \/>\n     $b = ((($c1 & 0xFF)   + ($c2 & 0xFF)   + ($c3 & 0xFF)   + ($c4 & 0xFF))   >> 2);<br \/>\n     imagesetpixel($dst_img, $dst_x + $x - $src_x, $dst_y + $y - $src_y, $r+$g+$b);<br \/>\n   }<br \/>\n }<br \/>\n}<\/code><br \/>\nJetzt schauen wir uns mal das Ergebnis des php-Codes an. Das Originalbild (in Photoshop verkleinert auf Bloggr\u00f6\u00dfe)<br \/>\n<a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/testbild2.jpg\" alt=\"\" title=\"testbild2\" width=\"550\" height=\"825\" class=\"aligncenter size-full wp-image-1197\" srcset=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/testbild2.jpg 550w, http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/testbild2-200x300.jpg 200w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n(vlnr) Pixelwiederholung (resized) &#8212; Bilinear (resampled) &#8212; Bicubic (resampleBicubic)<br \/>\n<a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_testbild2.jpg\" alt=\"\" title=\"thumb_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1196\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\" alt=\"\" title=\"thumb2_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1194\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\" alt=\"\" title=\"thumb3_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1195\" \/><\/a><\/p>\n<p>Pixelwiederholung leidet deutlich unter Pixelartefakten an Kanten, Bilinear sieht erstmal ok aus, erweist sich reel doch als zu weich, die Bicubic (in dieser Form) ist letztlich auch nicht optimal und so manche Kante wird unzureichend (siehe zB Socke links) wiedergegeben. Was ist nun die L\u00f6sung?<\/p>\n<h4>Nachsch\u00e4rfen mit der gdlib und imageconvolution<\/h4>\n<p>Damit kann man die &#8222;Eigenen Filter&#8220; aus Photoshop nachbauen, insbesondere den Hochpassfilter.<br \/>\n<code lang=\"php\"><br \/>\n\/\/ define the sharpen matrix<br \/>\n$sharpen = array(<br \/>\n\tarray(-1.2, -1.0, -1.2),<br \/>\n\tarray(-1.0, 20.0, -1.0),<br \/>\n\tarray(-1.2, -1.0, -1.2)<br \/>\n);<\/p>\n<p>\/\/ calculate the sharpen divisor<br \/>\n$divisor = array_sum(array_map('array_sum', $sharpen));<\/p>\n<p>\/\/ apply the matrix<br \/>\nimageconvolution($neuesBild, $sharpen, $divisor, 0);<br \/>\nimageJPEG($neuesBild,$ordnerK.\"thumb_ic_\".$bildName);<br \/>\n<\/code><br \/>\n(vlnr) bilinear (resampled) &#8212; bilinear nachgesch\u00e4rft (resampled+imageconvolution) &#8212; bicubic<br \/>\n<a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\" alt=\"\" title=\"thumb2_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1194\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2ic_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2ic_testbild2.jpg\" alt=\"\" title=\"thumb2ic_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1202\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\" alt=\"\" title=\"thumb3_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1195\" \/><\/a><br \/>\nIch halte das bilinear+imageconvolution-Thumbnail f\u00fcr ein recht gutes Ergebnis. Jeder kann auch nach eigenem Gutd\u00fcnken Hand an die Konvolutionsmatrix anlegen. Dass es besser geht, beweist uns gleich die Extension imagemagick (imagick), die aber idR nicht standardm\u00e4\u00dfig installiert ist. <\/p>\n<h4>Imagemagick<\/h4>\n<p>Gl\u00fccklich ist jener, der imagemagick (kurz imagick) als Extension zu laufen hat. Die Anweisungen (f\u00fcr das Verkleinern) sind k\u00fcrzer und die Auswahl an Algorithmen ist gro\u00df, die Qualit\u00e4t ohne gro\u00dfen Aufwand deutlich besser als bei der gdlib. Hier also der Code dazu:<br \/>\n<code lang=\"php\"><br \/>\n$thumb = new Imagick($originalBild);<br \/>\n# -- lanczos ausgewaehlt<br \/>\n# -- Bilinear = FILTER_TRIANGLE<br \/>\n# -- Bikubisch = FILTER_CATROM<br \/>\n$thumb->resizeImage($nX, $nY, Imagick::FILTER_LANCZOS, 1);<br \/>\n$thumb->writeImage($ordnerK.\"thumb_lan_\".$bildName);<br \/>\n$thumb->destroy();<br \/>\n<\/code><br \/>\nDie imagick-Ergebnisse in Bildform (darunter nochmal die Versionen aus der gdlib)<br \/>\n(vlnr) bilinear &#8212; bikubisch &#8212; lanczos<br \/>\n<a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_bil_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_bil_testbild2.jpg\" alt=\"\" title=\"thumb_img_bil_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1212\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_cub_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_cub_testbild2.jpg\" alt=\"\" title=\"thumb_img_cub_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1213\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_lan_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb_img_lan_testbild2.jpg\" alt=\"\" title=\"thumb_img_lan_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1214\" \/><\/a><br \/>\n(vlnr) gdlib bilinear &#8212; gdlib bikubisch &#8212; gdlib bilinear+imageconvolution<br \/>\n<a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2_testbild2.jpg\" alt=\"\" title=\"thumb2_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1194\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb3_testbild2.jpg\" alt=\"\" title=\"thumb3_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1195\" \/><\/a> <a href=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2ic_testbild2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.phreekz.de\/wordpress\/wp-content\/uploads\/2012\/11\/thumb2ic_testbild2.jpg\" alt=\"\" title=\"thumb2ic_testbild2\" width=\"181\" height=\"271\" class=\"alignleft size-full wp-image-1202\" \/><\/a><\/p>\n<h3>Res\u00fcmee<\/h3>\n<p>Nun, auf Anhieb w\u00fcrde ich sagen, Jupp, die LANCZOS-Version aus imagick schl\u00e4gt alle anderen Rescaler. (wobei man Lanczos zugestehen mu\u00df, dass er eher f\u00fcr Upscaling-Operationen gedacht ist) &#8211; dennoch ist die Kombination aus bilinear und imageconvolution eine (meiner Ansicht nach) passable L\u00f6sung, wenn man kein imagick installiert hat (dies wird der h\u00f6chstwahrscheinliche Fall sein, wenn man einen Webhost betreibt) &#8211; auch wenn die Nachsch\u00e4rfung im direkten Vergleich deutlich sichtbar ist. Der php-Sourcecode oben bietet noch Platz f\u00fcr Optimierungen, f\u00fcr die Verst\u00e4ndlichkeit sind aber einige Arbeitsschritte bzw. Speicherbelegungen doppelt ausgef\u00fchrt.<\/p>\n<p>Ich versuche, in den n\u00e4chsten Tagen noch den Mythos um die Bild-Verkleinerung in mehreren Durchg\u00e4ngen anzugehen. Lohnt es sich, ist der Unterschied sichtbar oder f\u00fchrt es zu sichtbaren Nachteilen? Bis demn\u00e4chst.<\/p>\n<p>Quellen:<br \/>\n<a href=\"http:\/\/www.imagemagick.org\/Usage\/filter\/\">imagick Filter usage<\/a><br \/>\n<a href=\"http:\/\/www.php.net\/manual\/en\/imagick.constants.php#imagick.constants.filters\">imagick Filter Constants<\/a><br \/>\n<a href=\"http:\/\/www.php.net\/manual\/de\/function.imagecopyresampled.php\">gdlib imagecopyresampled()<\/a><br \/>\n<a href=\"http:\/\/www.php.net\/manual\/de\/function.imageconvolution.php\">gdlib imageconvolution()<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Das Gro\u00dfe kleinmachen Der Bildartist m\u00f6chte auch in der Webansicht eine hohe Qualit\u00e4t vorlegen. Entweder man skaliert manuell alle Bilder in der Bildbearbeitung und legt sie auf dem Server ab, oder man \u00fcberl\u00e4sst die Aufgabe dem Server. Voraussetzung f\u00fcr folgende Code-Snippets ist nat\u00fcrlich php. In der Regel ist auf jedem Webserver, auf dem php l\u00e4uft,&hellip; <a class=\"more-link\" href=\"http:\/\/www.phreekz.de\/wordpress\/2012\/11\/bilder-per-php-verkleinern\/\"><span class=\"screen-reader-text\">[php] Bilder verkleinern<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":1197,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[137,29],"tags":[110,12,201,202,252,200,187],"class_list":["post-603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-foto-ebb","category-pc-leben-und-leiden","tag-coding","tag-fotografie","tag-gdlib","tag-imagemagick","tag-imagick","tag-php","tag-webseite","entry"],"_links":{"self":[{"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/posts\/603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/comments?post=603"}],"version-history":[{"count":70,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/posts\/603\/revisions"}],"predecessor-version":[{"id":1313,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/posts\/603\/revisions\/1313"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/media\/1197"}],"wp:attachment":[{"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/media?parent=603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/categories?post=603"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.phreekz.de\/wordpress\/wp-json\/wp\/v2\/tags?post=603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}