symfony - manipulation - ¿Usar LiipImagineBundle para cambiar el tamaño de la imagen después de subir?
symfony bundle image manipulation (5)
Estoy usando el LiipImagineBundle con Symfony 2.1 y me gustaría cambiar el tamaño de las imágenes subidas por el usuario al cargarlas antes de guardarlas en la ubicación permanente del sistema de archivos (para eliminar metadatos, imponer el formato jpeg y limitar el tamaño del archivo). Tengo que llamar a un filtro de ''tira'' y ''cambio de tamaño'' desde el controlador y luego guardar la imagen filtrada desde una ubicación temporal en una carpeta de mi elección en el sistema de archivos.
Intenté usar el controlador LiipImageBundle como un servicio como se indica en el archivo readme del paquete, pero la acción llamada es principalmente para crear una imagen filtrada en el directorio de la caché cuando se realiza una solicitud para mostrar la imagen (usarla para filtrar durante la carga es otro caso) ). Intenté implementarlo de la siguiente manera y lo hice funcionar. Primero tuve que mover el archivo del directorio temporal de php del servidor web a un directorio en la carpeta web para poder aplicar el filtro. En segundo lugar, apliqué el filtro y eliminé (unlink ()) el archivo sin filtrar inicial. Por último, tuve que mover (renombrar ()) el archivo filtrado a la ubicación permanente en el sistema de archivos. Fue necesario mover el archivo dos veces, aplicar el filtro una vez y eliminar (desvincular) 1 archivo para que todo funcione. ¿Hay una forma mejor (que no requiera el movimiento intermedio) de usar el paquete en la carga?
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);
}
}
Mi filtro en la aplicación / config / config.yml es el siguiente:
liip_imagine:
filter_sets:
my_filter:
format: jpeg
filters:
strip: ~
thumbnail: { size: [1600, 1000], mode: inset }
Se hizo una pregunta similar para ImagineAvalancheBundle pero no se dan muchos detalles. ¿Quizás implementar otro servicio de la lista provista aquí es una mejor solución?
Así que aquí hay una forma de crear miniaturas en la carga con LiipImagineBundle. El truco es utilizar algunos de sus otros servicios:
/**
* 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
}
Esto también podría hacerse llamando directamente a las funciones de la biblioteca Imagine si no tuviera otra razón para incluir LiipImagineBundle. Probablemente lo veré en el futuro, pero esto funciona para mi caso y funciona muy bien.
Dado que no encontré una mejor manera, mantuve la solución descrita en la descripción de la pregunta. Esa solución no parece la óptima desde el punto de vista del rendimiento (requiere mover el archivo dos veces, aplicar el filtro una vez y desvincular 1 archivo), pero logra el trabajo.
ACTUALIZAR:
Cambié mi código para usar los servicios indicados en la respuesta de Peter Wooster, como se muestra a continuación (esa solución es más óptima ya que la imagen filtrada se guarda directamente en el destino final):
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);
}
}
En lugar de cargar el archivo utilizando el administrador de datos liip, cree un objeto binario liip desde el archivo cargado:
use Liip/ImagineBundle/Model/Binary;
A continuación, utilice el siguiente código:
// 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
He escrito un paquete que resuelve exactamente este problema. Mientras que VichUploaderBundle
proporciona una carga sencilla utilizando las devoluciones de llamada del ciclo de vida de ORM, LiipImagine
hace un gran trabajo en el cambio de tamaño.
Aquí está la combinación de esto: https://github.com/RSSfeed/VichImagineBundle
Vea el breve archivo Léame sobre cómo implementarlo en solo unos minutos.
Versión modificada de @Peter Wooster, y la hizo más genérica, por lo que si alguien la usa sin la entidad de imagen, puede tomar benifet de ella fácilmente. Doy aquí dos versiones, una que se puede usar mantenida en la clase de utilidad o sin controlador. Y la otra versión es para clases de controlador. Depende de ti ahora donde quieras :)
Para usar fuera del controlador, por ejemplo, manteniéndolo en clases de utilidad
/**
* 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
}
Para usar en el controlador, por ejemplo, CommonController o cualquier otro controlador.
/**
* 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
}