Использовать LiipImagineBundle для изменения размера изображения после загрузки?

Я использую LiipImagineBundle с Symfony 2.1 и хотел бы изменить размер загруженных пользователем изображений при загрузке, прежде чем сохранять их в постоянном режиме расположение файловой системы (разделение метаданных, наложение формата jpeg и ограничение размера файла). Мне нужно вызвать фильтр "strip" и "resize" из контроллера, а затем сохранить отфильтрованное изображение из временного местоположения в папку, выбранную мной в файловой системе.

Я попытался использовать LiipImageBundle Controller как службу, указанную в файле readme, но вызываемое действие предназначено в основном для создания отфильтрованного изображения в каталоге кеша, когда запрос делается для отображения изображения (его использование для фильтрации при загрузке - это еще один случай). Я попытался реализовать его в любом случае, и получил его на работу. Мне пришлось сначала перенести файл из временного каталога php веб-сервера в каталог в веб-папке, чтобы иметь возможность применить фильтр. Во-вторых, я применил фильтр и удалил (unlink()) исходный нефильтрованный файл. Наконец, мне пришлось переместить (переименовать()) отфильтрованный файл в постоянное место в файловой системе. Необходимо было дважды переместить файл, применить фильтр один раз и удалить (отсоединить) 1 файл, чтобы все работало. Есть ли лучший способ (не требующий промежуточного перемещения) использовать пакет при загрузке?

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);
    }
}

Мой фильтр в app/config/config.yml выглядит следующим образом:

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

Аналогичный вопрос был задан для ImagineAvalancheBundle, но подробностей не было представлено. Возможно, более эффективное решение еще одна услуга из представленного здесь списка

Ответы

Ответ 1

Итак, вот способ создания эскизов при загрузке с помощью LiipImagineBundle. Хитрость заключается в использовании некоторых из их других сервисов:

    /**
     * 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
    }

Это также можно сделать, напрямую вызвав функции библиотеки Imagine, если у вас не было другой причины включать LiipImagineBundle. Я, вероятно, буду смотреть на это в будущем, но это работает для моего случая и очень хорошо работает.

Ответ 2

Модифицированная версия @Peter Wooster и сделала ее более общей, поэтому, если кто-то использует ее без объекта изображения, он может легко взять с собой benifet. Я даю здесь две версии, которые можно использовать в классе служебных или неконтролируемых. И другая версия предназначена для классов контроллера. Это вам, где вам нравится:)

Использовать вне контроллера, например. сохраняя его в служебных классах

/**
 * 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
}

Для использования в контроллере, например. CommonController или любой другой контроллер.

/**
 * 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
}

Ответ 3

Учитывая, что я не нашел лучшего способа, я сохранил решение, описанное в описании вопроса. Это решение не кажется оптимальным с точки зрения производительности (требуется дважды перемещать файл, применять фильтр один раз и отсоединить 1 файл), но он выполняет задание.

UPDATE:

Я изменил свой код, чтобы использовать службы, указанные в ответе Питера Уостера, как показано ниже (это решение более оптимально, поскольку отфильтрованное изображение сохраняется непосредственно в конечном месте назначения):

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);
    }
}

Ответ 4

Я написал пакет, который решает эту проблему. Хотя VichUploaderBundle обеспечивает легкую загрузку с использованием обратных вызовов ORM Lifecycle, LiipImagine отлично справляется с изменением размера.

Вот его комбинация: https://github.com/RSSfeed/VichImagineBundle

См. short readme о том, как реализовать его за несколько минут.

Ответ 5

Вместо того, чтобы загружать файл с помощью диспетчера данных liip, создайте двоичный объект liip из загруженного файла:

use Liip\ImagineBundle\Model\Binary;

затем используйте следующий код:

                // 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