Zur Navigation

Bilder über htaccess dynamisch verkleinern

1 Rudy

Hi,

ich analysiere gerade die Möglichkeit, für ein großes Projekt eine Logik zu implementieren, die es mir erlaubt, Bilder aus einem Pool mittels überschriebener URLs dynamisch zu verkleinern.

Die Theorie:

ich spreche ein Bild über
<img src="/pics/user/000000001-35x35.jpg" />

an. Mittels htaccess wird diese URL überschrieben und gelangt zu

/php/tools/getimage.php?category=user&filename=000000001.jpg&width=35&height=35

Das Skript verkleinert das Bild /pics/user/000000001.jpg mit den angegebene Maßen, speichert es als /pics/user/000000001-35x35.jpg und liefert es zurück. Soweit sogut. Das soll es aber nur tun, wenn das Bild nicht existiert. Nun könnte ich das ja im Skript prüfen, lieber wäre mir aber, das Skript würde gar nicht aufgerufen, wenn wie im Beispiel /pics/user/000000001-35x35.jpg bereits existiert. Kann ich das bereits in der htaccess kontrollieren? Wenn ja, wie?

Danke für Tips,
Rudy

28.10.2007 11:40

2 Jörg Kruse

Hallo Rudy,

mit dieser RewriteCond kannst du ausschließen, dass es die Datei gibt:

RewriteCond %{REQUEST_FILENAME} !-f

28.10.2007 12:54

3 Rudy

Optimal, Danke!

28.10.2007 12:58

4 Rudy

Da es sehr gut funktioniert, möchte ich die fertige Ausführung hierzu noch reinstellen, wenn es jemand selbst mal versuchen möchte.

Vielleicht hat ja jemand noch Verbesserungsvorschläge, was den Algorithmus zur Bildverkleinerung anbelangt?

Die Ordnerstruktur:

Alle hochgeladenen Bilder liegen in Originalgröße in /pics/pool/ und haben das Format 0000000001.jpg - 4294967295.jpg (MySQL Unsignend INT(10) Größe - für mich reicht das aus, sonst kann man auch Unsigned BigInt nehmen für bis zu 18446744073709551615 Bilder).

Die dynamisch verkleinerten Bilder werden vom Skript "getimage.php" abgelegt in /pics/, ein Skript muss da also schreiben können.

Das Skript "getimage.php" liegt in /php/tools/.

Die .htaccess liegt im Root-Verzeichnis /.

Der Code

.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^pics/([0-9]{10})\-(([1-9][0-9]*)|_)x(([1-9][0-9]*)|_)\.jpg$ ./php/tools/getimage.php?filename=$1&width=$2&height=$3 [L]
PHP-Skript "getimage.php"
<?php
          
function resizepicture($sourcefilename, $destfilename, $destwidth, $destheight) {
  $sourceimage = imagecreatefromjpeg($sourcefilename);
  list($sourcewidth, $sourceheight) = getimagesize($sourcefilename);
  if ($destwidth == '_') $destwidth = $sourcewidth;
  if ($destheight == '_') $destheight = $sourceheight;
  if ($sourcewidth > $sourceheight) {   //source is landscape format
    if ($destheight / $destwidth > $sourceheight / $sourcewidth) {
      $copyheight = $sourceheight;
      $copywidth = floor($destwidth / $destheight * $copyheight);
    } else {
      $copywidth = $sourcewidth;
      $copyheight = floor($destheight / $destwidth * $copywidth);
    }
  } else { //source is portrait or quadratic format
    if ($destwidth / $destheight > $sourcewidth / $sourceheight) {
      $copywidth = $sourcewidth;
      $copyheight = floor($destheight / $destwidth * $copywidth);
    } else {
      $copyheight = $sourceheight;
      $copywidth = floor($destwidth / $destheight * $copyheight);
    }      
  }
  $copyx = $copyy = 0;
  if ($copyheight < $sourceheight) {
    $copyy = floor(($sourceheight - $copyheight) / 2);                  
  }
  if ($copywidth < $sourcewidth) {
    $copyx = floor(($sourcewidth - $copywidth) / 2);
  }
  $destimage = imagecreatetruecolor($destwidth, $destheight);
  imagealphablending($destimage, false);
  imagecopyresized($destimage, $sourceimage, 0, 0, $copyx, $copyy, $destwidth, $destheight, $copywidth, $copyheight);
  @unlink($destfilename);
  imagejpeg($destimage, $destfilename);
}

$filename = $_GET['filename'];
$width = $_GET['width'];
$height = $_GET['height'];
if (!preg_match('/^[0-9]{10}$/', $filename) || 
    ($width != '_' && !(int)$width) || 
    ($height != '_' && !(int)$height)) {
   die('Bad parameters.');
}
$picturefilename = '../../pics/'.$filename.'-'.$width.'x'.$height.'.jpg';
if (!file_exists($picturefilename)) {
  $sourcepicture = '../../pics/pool/'.$filename.'.jpg';
  if (file_exists($sourcepicture)) {
    resizepicture($sourcepicture, $picturefilename, $width, $height);
  } else {
    die('Picture not found!');
  }
}
header('content-type: image/jpeg');
readfile('../../pics/'.$filename.'-'.$width.'x'.$height.'.jpg');
?>

Funktion

Um das nutzen zu können, reicht es einen einfachen Dateiupload für jpg-Dateien in den Ordner /pics/pool/ zu realisieren um die Bilder dort abzulegen und dafür zu sorgen, dass die Bilder ordnungsgemäß fortlaufend nummeriert werden. Ich habe das mit einer Tabelle gelöst, deren id Unsigned INT(10) / Autoincrement ist, und in dem immer ein Datensatz eingefügt wird, wenn ein Bild hochgeladen wird. Dort kann man dann auch Bildtitel, Text usw. ablegen, und die ID kann für den Bildnamen verwendet werden.

Wenn das Bild dort liegt, kann man nun von jeder Stelle aus einfach das Bild abrufen und die gewünschte Größe angeben:

<img src="/pics/0000000001-150x100.jpg" alt="" />
Verkleinert und schneidet das Bild auf das Format 150 Pixel Breite und 100 Pixel Höhe zu,

<img src="/pics/0000000001-150x_.jpg" alt="" />
Verkleinert das Bild auf die Breite 150 und lässt die Höhe proportional (Bild wird nicht geschnitten)

<img src="/pics/0000000001-_x200.jpg" alt="" />
Verkleinert das Bild auf 200 Pixel Höhe und die Breite bleibt proportional.

Man sollte sich aber von Anfang an bewusst sein, welche Bildgrößen man braucht, denn sonst hat man irgendwann sehr viele unnütze Bildgrößen in /pics/ liegen. Die muss man dann von Hand löschen. Der Vorteil des Systems liegt darin, dass man bei CMS-Modulen nicht noch herumfummeln muss, wenn man eine neue Seite / Modul hinzufügt, in der das Bildmaterial in anderer Größe gebraucht wird - man ruft es einfach auf und es steht so zur Verfügung.

28.12.2007 14:39 | geändert: 02.01.2008 17:22

5 mats

Eine sehr nette Sache, um automatisch Thumbnails zu produzieren, wenn ich mich nicht irre.
Werde ich wohl noch drauf zurückkommen, zumal ich Weihnachtens ja endlich eine DigiCam bekommen habe und fleissig Galerien aufbaue.

Gruß,

Mats

01.01.2008 15:56

6 Rudy

Ich würde mich freuen, weitere Implementationen zu sehen.

Gedacht ist das ursprünglich für eine Community-Seite, die ich machen muss. Dort können User ihr eigenes Foto und selbstgeschossene für Ihre Beiträge hochladen, und diese werden an verschiedenen Stellen verwendet, wobei Teile noch nach der Publizierung entwickelt werden.

Da das nette Designer-Völkchen sich zurecht herzlich wenig darum sorgt, ob das Bildmaterial so vorliegt wie es im Design benötigt wird, bietet sich zum Schutz der Programmierer-Nerven der Pool an. So ist keine händische Nachbearbeitung des Bildmaterials oder Programmierung notwendig, wenn man das Design umsetzt und vorhandenes Bildmaterial einpflegen muss - das Originalmaterial der User liegt ja noch vor.

Es ist aber ein etwas verschwenderischer Umgang mit Server-Speicherplatz. Mir mangelt es daran nicht; wenn das für jemanden ein Problem ist, würde ich die gute alte Methode - also beim Hochladen verkleinern und Original löschen - verwenden, anstatt wie hier Original zu speichern und alles on-the-fly zu verkleinern.

Eine gute Idee wäre das Original noch beim Hochladen gleich auf eine Maximalgröße zu verkleinern, z.B. Maximalbreite / Höhe 800px. So hält sich der Speicher für die Originale in Grenzen.

02.01.2008 17:45 | geändert: 02.01.2008 17:47

... 2 Jahre und 11 Monate später ...

7 Steffen (Gast)

Hallo,
irgendwie will das bei mir nicht klappen. Ich habe die bilder außerhalb von root angelegt. über ein php-skript kann ich die auch ansprechen über:

datei.php?file=testbild.jpg

nun dachte ich, dass ich mit diesen hinweisen hier meine .htaccess so anpassen kann, dass ich bilderpfade in meinen dateien erzeuge, die so lauten

<img src="media-content/testbild.jpg"> und sie dann eben an die "datei.php übergeben kann und das bild dann in der html-datei angezeigt werden kann.

Kann mir jemand hier weiterhelfen?
Meine htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^media-content/(.*)$ ./bildertest.php?file=$1 [L]

07.12.2010 20:10

8 Rudy

Das Minus muss escaped werden, sonst ist es a-c :
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^media\-content/(.*)$ ./bildertest.php?file=$1 [L]

07.12.2010 20:43

9 Steffen (Gast)

Danke für die schnelle Antwort. Das liefert mir aber leider einen Fehler 500.
Vielleicht zur näheren Beschreibung:
bildertest.php liegt in dem Verzeichnis in dem auch die htaccess liegt. Der Ordner media-content existert nicht.

07.12.2010 21:26

10 Jörg Kruse

irgendwie will das bei mir nicht klappen.

Kannst du das "irgendwie nicht" etwas genauer ausführen?

mod_rewrite ist bei dir aktiviert (siehe diesen Test)?

07.12.2010 21:37