2013-02-24 4 views
15

Ich benutze die LiipImagineBundle mit Symfony 2.1 und möchte die Größe der vom Benutzer hochgeladenen Bilder beim Hochladen ändern, bevor sie in den permanenten Dateisystemspeicherort gespeichert werden (um Metadaten zu entfernen, JPEG-Format zu erzwingen und die Größe der Datei zu begrenzen). Ich muss einen 'strip' und 'resize' Filter vom Controller aufrufen und dann das gefilterte Bild von einem temporären Speicherort in einen Ordner meiner Wahl im Dateisystem speichern.Verwenden Sie LiipImagineBundle, um das Bild nach dem Hochladen zu skalieren?

Ich habe versucht, die LiipImageBundle Controller as a service as indicated in the bundle's readme zu verwenden, aber die aufgerufene Aktion dient hauptsächlich zum Erstellen eines gefilterten Bildes im Cache-Verzeichnis, wenn eine Anfrage zur Anzeige des Bildes gemacht wird (die Verwendung für die Filterung beim Hochladen ist ein weiterer Fall). Ich habe versucht, es wie folgt zu implementieren und es zum Laufen gebracht. Ich musste zuerst die Datei aus dem temporären PHP-Verzeichnis des Webservers in ein Verzeichnis im Webordner verschieben, um den Filter anwenden zu können. Zweitens habe ich den Filter angewendet und die ursprüngliche ungefilterte Datei gelöscht (unlink()). Zuletzt musste ich die gefilterte Datei an die permanente Stelle im Dateisystem verschieben (umbenennen). Es war notwendig, die Datei zweimal zu verschieben, den Filter einmal anzuwenden und 1 Datei zu löschen (aufheben), um alles zu funktionieren. Gibt es einen besseren Weg (ohne den Zwischenzug), das Bundle beim Upload zu verwenden?

class MyController extends Controller 
{ 
    public function new_imageAction(Request $request) 
    { 
     $uploadedFile = $request->files->get('file'); 
     $tmpFolderPathAbs = $this->get('kernel')->getRootDir() . '/../web/uploads/tmp/'; 
     $tmpImageNameNoExt = rand(); 
     $tmpImageName = $tmpImageNameNoExt . '.' . $fileExtension; 
     $uploadedFile->move($tmpFolderPathAbs, $tmpImageName); 
     $tmpImagePathRel = '/uploads/tmp/' . $tmpImageName; 
     // Create the filtered image in a tmp folder: 
     $this->container->get('liip_imagine.controller')->filterAction($request, $tmpImagePathRel, 'my_filter'); 
     unlink($tmpFolderPathAbs . $tmpImageName); 
     $filteredImagePathAbs = $this->get('kernel')->getRootDir() . '/../web/uploads/cache/my_filter/uploads/tmp/' . $tmpImageNameNoExt . '.jpeg'; 
     $imagePath = $imageManagerResponse->headers->get('location'); 
     // define permanent location ($permanentImagePathAbs)... 
     rename($filteredImagePathAbs, $permanentImagePathAbs); 
    } 
} 

Mein Filter in der app/config/config.yml ist wie folgt:

liip_imagine: 
    filter_sets: 
     my_filter: 
      format: jpeg 
      filters: 
       strip: ~ 
       thumbnail: { size: [1600, 1000], mode: inset } 

A similar question was asked for the ImagineAvalancheBundle aber keine viel Details gegeben. Vielleicht ist die Implementierung von another service from the here provided list eine bessere Lösung?

+0

Haben Sie jemals eine bessere Lösung finden? Ich möchte das auch. Der Filter funktioniert gut, aber die Leistung ist nicht gut, wenn ich viele Miniaturansichten habe, die beim Laden vom Cache an einen bekannten Ort verschoben werden, was die Geschwindigkeit dramatisch erhöht. –

+0

@PeterWooster: Ich habe keine andere Lösung gefunden, aber die oben beschriebene scheint gut zu funktionieren (ich behielt es so). – RayOnAir

+0

Ich arbeite an einer Lösung und werde hier posten, wenn es funktioniert. –

Antwort

16

Also hier ist eine Möglichkeit, Thumbnails beim Hochladen mit LiipImagineBundle zu erstellen. Der Trick ist, einige ihrer anderen Dienste zu nutzen:

/** 
    * Write a thumbnail image using the LiipImagineBundle 
    * 
    * @param Document $document an Entity that represents an image in the database 
    * @param string $filter the Imagine filter to use 
    */ 
    private function writeThumbnail($document, $filter) { 
     $path = $document->getWebPath();        // domain relative path to full sized image 
     $tpath = $document->getRootDir().$document->getThumbPath();  // absolute path of saved thumbnail 

     $container = $this->container;         // the DI container 
     $dataManager = $container->get('liip_imagine.data.manager'); // the data manager service 
     $filterManager = $container->get('liip_imagine.filter.manager');// the filter manager service 

     $image = $dataManager->find($filter, $path);     // find the image and determine its type 
     $response = $filterManager->get($this->getRequest(), $filter, $image, $path); // run the filter 
     $thumb = $response->getContent();        // get the image from the response 

     $f = fopen($tpath, 'w');          // create thumbnail file 
     fwrite($f, $thumb);            // write the thumbnail 
     fclose($f);              // close the file 
    } 

auch Dies könnte direkt durch den Aufruf der Imagine Bibliotheksfunktionen erfolgen, wenn Sie keinen anderen Grund hatte die LiipImagineBundle aufzunehmen. Ich werde mich wahrscheinlich in Zukunft damit beschäftigen, aber das funktioniert für meinen Fall und führt sehr gut aus.

+0

Vielen Dank für das Absenden dieser Antwort. Sobald ich ein wenig Zeit habe, es zu versuchen, werde ich Sie wissen lassen, wie es geht! – RayOnAir

+0

+1: Sie haben die richtigen Dienste zum Anwenden des Filters identifiziert und speichern das transformierte Bild am gewünschten Ziel. Die vollständige Antwort auf meine Frage ist eine Kombination meiner Schritte, um ein temporäres Bild im Dateisystem zu speichern und die Schritte, um den Filter anzuwenden und das transformierte Bild am endgültigen Ziel zu speichern (meine Frage ist, den Filter direkt auf das hochgeladene Bild anzuwenden) Größe ändern, bevor Sie es im Dateisystem speichern). Ihre Lösung besteht darin, Thumbnails zu erstellen und sie aus einem Bild zu speichern, das sich bereits im Dateisystem befindet. – RayOnAir

+0

Beachten Sie, dass es nicht möglich scheint, den Filter auf ein Bild anzuwenden, das sich noch nicht in einem Ordner irgendwo im Webverzeichnis befindet, es sei denn, spezielle Zugriffsrechte sind festgelegt. – RayOnAir

0

Da ich keinen besseren Weg gefunden habe, behielt ich die in der Fragebeschreibung beschriebene Lösung. Diese Lösung scheint von einem Leistungsstandpunkt aus nicht der optimale zu sein (es erfordert, dass die Datei zweimal verschoben, der Filter einmal angewendet und die Verknüpfung zu 1 Datei aufgehoben wird), aber der Auftrag wird ausgeführt.

UPDATE:

ich meinen Code geändert, um die Dienste in Peter Wooster Antwort angegeben zu verwenden, wie unten gezeigt (die Lösung ist optimal, da das gefilterte Bild direkt zum endgültigen Ziel gespeichert wird):

class MyController extends Controller 
{ 
    public function new_imageAction(Request $request) 
    { 
     $uploadedFile = $request->files->get('file'); 
     // ...get file extension and do other validation... 
     $tmpFolderPathAbs = $this->get('kernel')->getRootDir() . '/../web/uploads/tmp/'; // folder to store unfiltered temp file 
     $tmpImageNameNoExt = rand(); 
     $tmpImageName = $tmpImageNameNoExt . '.' . $fileExtension; 
     $uploadedFile->move($tmpFolderPathAbs, $tmpImageName); 
     $tmpImagePathRel = '/uploads/tmp/' . $tmpImageName; 
     // Create the filtered image: 
     $processedImage = $this->container->get('liip_imagine.data.manager')->find('my_filter', $tmpImagePathRel); 
     $filteredImage = $this->container->get('liip_imagine.filter.manager')->get($request, 'my_filter', $processedImage, $tmpImagePathRel)->getContent(); 
     unlink($tmpFolderPathAbs . $tmpImageName); // eliminate unfiltered temp file. 
     $permanentFolderPath = $this->get('kernel')->getRootDir() . '/../web/uploads/path_to_folder/'; 
     $permanentImagePath = $permanentFolderPath . 'my_image.jpeg'; 
     $f = fopen($permanentImagePath, 'w'); 
     fwrite($f, $filteredImage); 
     fclose($f); 
    } 
} 
+0

können Sie einen Dienst schreiben, der das ganze für Sie erledigt und dann anstelle von LiipImagine verwendet. –

7

Modifizierte Version von @Peter Wooster, und es generischer gemacht, also wenn jemand es ohne Image-Entität verwendet, kann er leicht Benifet davon nehmen. Ich gebe hier zwei Versionen, eine, die in der Utility- oder Nicht-Controller-Klasse verwendet werden kann. Und die andere Version ist für Controller-Klassen. Jetzt liegt es an Ihnen, wo Sie möchten :)

Um außerhalb des Controllers z. hält es in Utility-Klassen

/** 
* Write a thumbnail image using the LiipImagineBundle 
* 
* @param Document $fullSizeImgWebPath path where full size upload is stored e.g. uploads/attachments 
* @param string $thumbAbsPath full absolute path to attachment directory e.g. /var/www/project1/images/thumbs/ 
* @param string $filter filter defined in config e.g. my_thumb 
* @param Object $diContainer Dependency Injection Object, if calling from controller just pass $this 
*/ 
public function writeThumbnail($fullSizeImgWebPath, $thumbAbsPath, $filter, $diContainer) { 
    $container = $diContainer; // the DI container, if keeping this function in controller just use $container = $this 
    $dataManager = $container->get('liip_imagine.data.manager'); // the data manager service 
    $filterManager = $container->get('liip_imagine.filter.manager'); // the filter manager service 
    $image = $dataManager->find($filter, $fullSizeImgWebPath);     // find the image and determine its type 
    $response = $filterManager->applyFilter($image, $filter); 

    $thumb = $response->getContent();        // get the image from the response 

    $f = fopen($thumbAbsPath, 'w');          // create thumbnail file 
    fwrite($f, $thumb);            // write the thumbnail 
    fclose($f);              // close the file 
} 

Um zum Beispiel in der Steuerung zu verwenden CommonController oder jeder andere Controller.

/** 
* Write a thumbnail image using the LiipImagineBundle 
* 
* @param Document $fullSizeImgWebPath path where full size upload is stored e.g. uploads/attachments 
* @param string $thumbAbsPath full absolute path to attachment directory e.g. /var/www/project1/images/thumbs/ 
* @param string $filter filter defined in config e.g. my_thumb 
*/ 
public function writeThumbnail($fullSizeImgWebPath, $thumbAbsPath, $filter) { 
    $container = $this->container; 
    $dataManager = $container->get('liip_imagine.data.manager'); // the data manager service 
    $filterManager = $container->get('liip_imagine.filter.manager'); // the filter manager service 
    $image = $dataManager->find($filter, $fullSizeImgWebPath);     // find the image and determine its type 
    $response = $filterManager->applyFilter($image, $filter); 

    $thumb = $response->getContent();        // get the image from the response 

    $f = fopen($thumbAbsPath, 'w');          // create thumbnail file 
    fwrite($f, $thumb);            // write the thumbnail 
    fclose($f);              // close the file 
} 
+0

Ich bekomme den folgenden Fehler, wenn Sie versuchen, Ihren Code auf meinem Bitnami Wamp-Stack, der Mime-Typ des Bildes uploads/files/img-5535_05052015_923_c2a1a.JPG muss Bild/xxx inode/x-leer sein. Können Sie mir dabei helfen? – Adam

+0

@Adam versuchen, einige andere Bilder und mit einem anderen Typ auch hochzuladen, da der Bildmime-Typ beschädigt aussieht oder einige andere Probleme hat. –

0

Ich habe ein Bündel geschrieben, das genau dieses Problem löst.Während VichUploaderBundle das einfache Hochladen mit den Lifecycle-Rückrufen von ORM bietet, macht LiipImagine eine großartige Arbeit bei der Größenanpassung. Hier

ist die Kombination davon: https://github.com/RSSfeed/VichImagineBundle

Siehe short readme, wie man es in nur wenigen Minuten zu implementieren.

0

Statt das Laden der Datei Liip Datenmanager verwenden, erstellen Liip binäre Objekt aus der hochgeladenen Datei:

use Liip\ImagineBundle\Model\Binary; 

verwenden Sie dann den folgenden Code ein:

   // Generate a unique name for the file before saving it 
       $fileName = md5(uniqid()) . '.' . $uploadedFile->guessExtension(); 

       $contents = file_get_contents($uploadedFile); 

       $binary = new Binary(
        $contents, 
        $uploadedFile->getMimeType(), 
        $uploadedFile->guessExtension() 
       ); 

       $container = $this->container; 
       $filterManager = $container->get('liip_imagine.filter.manager'); // the filter manager service 
       $response = $filterManager->applyFilter($binary, 'my_thumb'); 

       $thumb = $response->getContent();        // get the image from the response 

       $f = fopen($webRootDir .'/images_dir/' . $fileName, 'w');          // create thumbnail file 
       fwrite($f, $thumb);            // write the thumbnail 
       fclose($f);              // close the file