Frage

Was ist der effizienteste Weg, um die Größe großer Bilder in PHP?

Ich bin derzeit mit der GD Funktion imagecopyresampled, um nehmen Sie Bilder mit hoher Auflösung und sauber skalieren Sie Sie nach unten, um eine Größe für die Anzeige im web (etwa 700 Pixel breit und 700 Pixel hoch).

Dies funktioniert gut auf kleinen (unter 2 MB) Fotos und der gesamte Größe Vorgang dauert weniger als eine Sekunde auf dem server.Aber die Website wird schließlich Dienst Fotografen, die möglicherweise das hochladen von Bildern bis zu einer Größe von 10 MB (oder-Bilder bis zu 5000x4000 Pixel in der Größe).

Diese Art der Größenänderung, die mit großen Bildern dazu neigt, zu erhöhen die Speicher-Auslastung durch einen sehr großen Spielraum (größere Bilder können spike die Speicherauslastung für das Skript letzten 80 MB).Gibt es eine Möglichkeit, diese Größe noch effizienteren Betrieb?Soll ich mich mit einem alternativen Bild-Bibliothek wie ImageMagick?

Jetzt, das resize-code sieht ungefähr so aus

function makeThumbnail($sourcefile, $endfile, $thumbwidth, $thumbheight, $quality) {
    // Takes the sourcefile (path/to/image.jpg) and makes a thumbnail from it
    // and places it at endfile (path/to/thumb.jpg).

    // Load image and get image size.
    $img = imagecreatefromjpeg($sourcefile);
    $width = imagesx( $img );
    $height = imagesy( $img );

    if ($width > $height) {
        $newwidth = $thumbwidth;
        $divisor = $width / $thumbwidth;
        $newheight = floor( $height / $divisor);
    } else {
        $newheight = $thumbheight;
        $divisor = $height / $thumbheight;
        $newwidth = floor( $width / $divisor );
    }

    // Create a new temporary image.
    $tmpimg = imagecreatetruecolor( $newwidth, $newheight );

    // Copy and resize old image into new image.
    imagecopyresampled( $tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height );

    // Save thumbnail into a file.
    imagejpeg( $tmpimg, $endfile, $quality);

    // release the memory
    imagedestroy($tmpimg);
    imagedestroy($img);
War es hilfreich?

Lösung

Die Leute sagen, dass ImageMagick ist viel schneller.Am besten vergleichen Sie beide Bibliotheken und Messen, die.

  1. Bereiten 1000 typischen Bilder.
  2. Schreiben Sie zwei Skripte -- eine für GD, eines für ImageMagick.
  3. Führen Sie beide ein paar mal.
  4. Vergleichen Sie die Ergebnisse (Gesamt Ausführung die Zeit, CPU-und I/O-Auslastung, Ergebnis Bildqualität).

Etwas, das Sie sich die besten jeder andere, könnte nicht die beste für Sie.

Auch, meiner Meinung nach, ImageMagick hat viel bessere API-Schnittstelle.

Andere Tipps

Hier ist ein Ausschnitt aus dem php.net docs, ich habe in einem Projekt verwendet und funktioniert einwandfrei:

<?
function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) {
    // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
    // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
    // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
    // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
    //
    // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
    // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
    // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
    // 2 = Up to 95 times faster.  Images appear a little sharp, some prefer this over a quality of 3.
    // 3 = Up to 60 times faster.  Will give high quality smooth results very close to imagecopyresampled, just faster.
    // 4 = Up to 25 times faster.  Almost identical to imagecopyresampled for most images.
    // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.

    if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
    if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
        $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1);
        imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
        imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
        imagedestroy ($temp);
    } else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
    return true;
}
?>

http://us.php.net/manual/en/function.imagecopyresampled.php#77679

phpThumb verwendet ImageMagick-Wann immer möglich-für die Geschwindigkeit (falling back to GD falls erforderlich) und scheint cache ziemlich gut, die Belastung zu reduzieren auf dem server.Es ist ziemlich leicht zu versuchen (um die Größe eines Bildes ändern, rufen Sie einfach an phpThumb.php mit einer GET-Abfrage, die die Grafik mit dem Namen und Ausgang Abmessungen), so dass Sie vielleicht geben Sie ihm einen Schuss, um zu sehen, wenn es Ihren Anforderungen entspricht.

Für größere Bilder verwenden, libjpeg, um die Größe auf das Bild laden in ImageMagick und damit wesentlich zur Verringerung der Speichernutzung und die Leistung verbessert, ist es nicht möglich, mit GD.

$im = new Imagick();
try {
  $im->pingImage($file_name);
} catch (ImagickException $e) {
  throw new Exception(_('Invalid or corrupted image file, please try uploading another image.'));
}

$width  = $im->getImageWidth();
$height = $im->getImageHeight();
if ($width > $config['width_threshold'] || $height > $config['height_threshold'])
{
  try {
/* send thumbnail parameters to Imagick so that libjpeg can resize images
 * as they are loaded instead of consuming additional resources to pass back
 * to PHP.
 */
    $fitbyWidth = ($config['width_threshold'] / $width) > ($config['height_threshold'] / $height);
    $aspectRatio = $height / $width;
    if ($fitbyWidth) {
      $im->setSize($config['width_threshold'], abs($width * $aspectRatio));
    } else {
      $im->setSize(abs($height / $aspectRatio), $config['height_threshold']);
    }
    $im->readImage($file_name);

/* Imagick::thumbnailImage(fit = true) has a bug that it does fit both dimensions
 */
//  $im->thumbnailImage($config['width_threshold'], $config['height_threshold'], true);

// workaround:
    if ($fitbyWidth) {
      $im->thumbnailImage($config['width_threshold'], 0, false);
    } else {
      $im->thumbnailImage(0, $config['height_threshold'], false);
    }

    $im->setImageFileName($thumbnail_name);
    $im->writeImage();
  }
  catch (ImagickException $e)
  {
    header('HTTP/1.1 500 Internal Server Error');
    throw new Exception(_('An error occured reszing the image.'));
  }
}

/* cleanup Imagick
 */
$im->destroy();

Aus Sie Frage, es scheint, Sie sind irgendwie neu zu GD, werde ich teilen einige experence von mir, dies ist vielleicht ein bisschen off-topic, aber ich denke, es wird hilfreich sein, um jemand, der neu in GD, wie Sie:

Schritt 1 Datei überprüfen. Verwenden Sie die folgende Funktion, um zu prüfen, ob die $_FILES['image']['tmp_name'] Datei gültig ist-Datei:

   function getContentsFromImage($image) {
      if (@is_file($image) == true) {
         return file_get_contents($image);
      } else {
         throw new \Exception('Invalid image');
      }
   }
   $contents = getContentsFromImage($_FILES['image']['tmp_name']);

Schritt 2 get file format Versuchen Sie die folgende Funktion, mit finfo-Erweiterung zu überprüfen, format der Datei(Inhalt).Würden Sie sagen, warum verwenden Sie nicht nur $_FILES["image"]["type"] um zu überprüfen, Datei-format?Weil es NUR überprüfen Sie die Dateiendung nicht den Inhalt der Datei, wenn jemand eine Datei umbenennen ursprünglich genannt Welt.png zu world.jpg, $_FILES["image"]["type"] zurück jpeg png nicht, so $_FILES["image"]["type"] können Rückkehr falschen Ergebnis.

   function getFormatFromContents($contents) {
      $finfo = new \finfo();
      $mimetype = $finfo->buffer($contents, FILEINFO_MIME_TYPE);
      switch ($mimetype) {
         case 'image/jpeg':
            return 'jpeg';
            break;
         case 'image/png':
            return 'png';
            break;
         case 'image/gif':
            return 'gif';
            break;
         default:
            throw new \Exception('Unknown or unsupported image format');
      }
   }
   $format = getFormatFromContents($contents);

Schritt.3, Erhalten GD-Ressource Holen Sie sich GD-Ressource von Inhalt, wir haben vor:

   function getGDResourceFromContents($contents) {
      $resource = @imagecreatefromstring($contents);
      if ($resource == false) {
         throw new \Exception('Cannot process image');
      }
      return $resource;
   }
   $resource = getGDResourceFromContents($contents);

Schritt 4 Holen Sie sich Bild-dimension Jetzt können Sie die Bildgröße mit den folgenden einfachen code:

  $width = imagesx($resource);
  $height = imagesy($resource);

Jetzt, Lassen Sie uns sehen, welche Variablen wir haben aus dem ursprünglichen Bild, dann:

       $contents, $format, $resource, $width, $height
       OK, lets move on

Schritt 5 berechnen verkleinerte Bild Argumente Dieser Schritt ist in Bezug auf Ihre Frage, ist der Zweck der folgenden Funktion um die Größe Argumente für die GD-Funktion imagecopyresampled(), der code ist ein bisschen lang, aber es funktioniert großartig, es hat sogar drei Optionen:stretch, shrink, und füllen.

stretch:Ausgang Bild die dimension ist die gleiche wie die neue dimension, die Sie festlegen.Nicht halten Höhe/Breite-Verhältnis.

schrumpfen:output image dimension nicht überschreiten, die neue dimension, die Sie geben, und halten Bild Höhe/Breite-Verhältnis.

füllen:Ausgang Bild ist dimension die gleiche, wie die neue dimension, die Sie geben, wird es crop & resize Bild, wenn nötig, und halten Bild Höhe/Breite-Verhältnis. Diese option ist, was Sie brauchen, in Ihrer Frage.

   function getResizeArgs($width, $height, $newwidth, $newheight, $option) {
      if ($option === 'stretch') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
         $src_w = $width;
         $src_h = $height;
         $src_x = 0;
         $src_y = 0;
      } else if ($option === 'shrink') {
         if ($width <= $newwidth && $height <= $newheight) {
            return false;
         } else if ($width / $height >= $newwidth / $newheight) {
            $dst_w = $newwidth;
            $dst_h = (int) round(($newwidth * $height) / $width);
         } else {
            $dst_w = (int) round(($newheight * $width) / $height);
            $dst_h = $newheight;
         }
         $src_x = 0;
         $src_y = 0;
         $src_w = $width;
         $src_h = $height;
      } else if ($option === 'fill') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         if ($width / $height >= $newwidth / $newheight) {
            $src_w = (int) round(($newwidth * $height) / $newheight);
            $src_h = $height;
            $src_x = (int) round(($width - $src_w) / 2);
            $src_y = 0;
         } else {
            $src_w = $width;
            $src_h = (int) round(($width * $newheight) / $newwidth);
            $src_x = 0;
            $src_y = (int) round(($height - $src_h) / 2);
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
      }
      if ($src_w < 1 || $src_h < 1) {
         throw new \Exception('Image width or height is too small');
      }
      return array(
          'dst_x' => 0,
          'dst_y' => 0,
          'src_x' => $src_x,
          'src_y' => $src_y,
          'dst_w' => $dst_w,
          'dst_h' => $dst_h,
          'src_w' => $src_w,
          'src_h' => $src_h
      );
   }
   $args = getResizeArgs($width, $height, 150, 170, 'fill');

Schritt 6, die Größe von Bild Verwenden $args, $width, $height, $format und $resource bekamen wir von oben in die folgenden Funktion, und die neue Ressource in der Größe veränderte Bild:

   function runResize($width, $height, $format, $resource, $args) {
      if ($args === false) {
         return; //if $args equal to false, this means no resize occurs;
      }
      $newimage = imagecreatetruecolor($args['dst_w'], $args['dst_h']);
      if ($format === 'png') {
         imagealphablending($newimage, false);
         imagesavealpha($newimage, true);
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
      } else if ($format === 'gif') {
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
         imagecolortransparent($newimage, $transparentindex);
      }
      imagecopyresampled($newimage, $resource, $args['dst_x'], $args['dst_y'], $args['src_x'], $args['src_y'], $args['dst_w'], $args['dst_h'], $args['src_w'], $args['src_h']);
      imagedestroy($resource);
      return $newimage;
   }
   $newresource = runResize($width, $height, $format, $resource, $args);

Schritt 7 neue Inhalte, Verwenden Sie die folgende Funktion verwenden, um Inhalte aus dem neuen GD-Ressource:

   function getContentsFromGDResource($resource, $format) {
      ob_start();
      switch ($format) {
         case 'gif':
            imagegif($resource);
            break;
         case 'jpeg':
            imagejpeg($resource, NULL, 100);
            break;
         case 'png':
            imagepng($resource, NULL, 9);
      }
      $contents = ob_get_contents();
      ob_end_clean();
      return $contents;
   }
   $newcontents = getContentsFromGDResource($newresource, $format);

Schritt 8 erste Erweiterung, Verwenden Sie die folgende Funktion verwenden, um Erweiterung von Bild-format(Hinweis: Bildformat ist nicht gleich Bild-Erweiterung):

   function getExtensionFromFormat($format) {
      switch ($format) {
         case 'gif':
            return 'gif';
            break;
         case 'jpeg':
            return 'jpg';
            break;
         case 'png':
            return 'png';
      }
   }
   $extension = getExtensionFromFormat($format);

Schritt 9 Bild speichern Wenn wir einen Benutzer mit dem Namen mike, können Sie Folgendes tun, speichert Sie in demselben Ordner wie das php-Skript:

$user_name = 'mike';
$filename = $user_name . '.' . $extension;
file_put_contents($filename, $newcontents);

Schritt 10 Zerstöre Ressource Vergessen Sie nicht zerstören GD-Ressource!

imagedestroy($newresource);

oder schreiben Sie den gesamten code in eine Klasse, und verwenden Sie einfach die folgende:

   public function __destruct() {
      @imagedestroy($this->resource);
   }

TIPPS

Ich empfehle, nicht konvertieren die Datei format, die Benutzer hochladen, Sie treffen viele Probleme.

Ich schlage vor, dass Sie etwas in dieser Richtung:

  1. Führen Sie eine getimagesize( ) auf die Datei hochgeladen um zu überprüfen, Bildtyp und-Größe
  2. Speichern von hochgeladenen JPEG-Bilddatei, die kleiner als 700x700px in den Ziel-Ordner "als-ist"
  3. Verwenden Sie GD-Bibliothek für mittelgroße Bilder (siehe diesen Artikel für code-Beispiel: Die Größe von Bildern Mit PHP und der GD-Bibliothek)
  4. Verwenden Sie ImageMagick für große Bilder.Sie können die Verwendung von ImageMagick im hintergrund, wenn Sie bevorzugen.

Nutzen von ImageMagick im hintergrund verschieben Sie die hochgeladenen Dateien in einen temporären Ordner und planen Sie einen CRON-job, der "konvertieren"s alle Dateien, jpeg-und passt Sie entsprechend an.Siehe Befehls-syntax an: imagemagick-Befehl line-Verarbeitung

Sie können den Benutzer auffordern, die Datei wird hochgeladen und geplant verarbeitet werden.Der CRON-job konnte ausgeführt werden soll, täglich in einem bestimmten Intervall.Quelle Bild könnte gelöscht werden, nachdem Verarbeitung, um sicherzustellen, dass ein Bild nicht zweimal verarbeitet.

Ich habe gehört, große Dinge über die Imagick-Bibliothek, leider konnte ich nicht installieren es in mein computer in der Arbeit und auch zu Hause (und Vertrauen Sie mir, ich verbrachte Stunden und Stunden auf allen Arten von Foren).

Anschliessend habe ich beschlossen, zu versuchen, diese PHP-Klasse:

http://www.verot.net/php_class_upload.htm

Es ist ziemlich cool und ich kann die Größe ändern alle Arten von Bilder (ich können konvertieren Sie JPG auch).

ImageMagick ist multithreaded, so scheint es, schneller zu sein, aber tatsächlich verbraucht viel mehr Ressourcen als GD.Wenn Sie lief mehrere PHP-Skripte parallel alle mit GD-dann würden Sie schlagen ImageMagick in der Geschwindigkeit für einfache Operationen.ExactImage ist weniger leistungsfähig als die ImageMagick-aber viel schneller, aber nicht in PHP, müssen Sie auf dem server installieren, und führen Sie es durch exec.

Für größere Bilder benutzen phpThumb().Hier ist, wie zu verwenden es: http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/.Es funktioniert auch für große beschädigten Bildern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top