* thumbnail generation refactored

* thumbnail dimensions are also cached in db now
This commit is contained in:
Danyi Dávid 2017-08-14 23:01:33 +02:00
parent 998d825d46
commit 71253ff1ac
3 changed files with 159 additions and 104 deletions

View File

@ -7,7 +7,6 @@ use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface as ServerMiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Diactoros\Stream;
class GetImageAction implements ServerMiddlewareInterface
@ -25,18 +24,18 @@ class GetImageAction implements ServerMiddlewareInterface
$image = $request->getAttribute('image', false);
$thumb = $request->getAttribute('thumb', false);
$imageFileName = $this->galleryService->getImage($slug, $image, $thumb);
$stream = new Stream(fopen($imageFileName, 'r'));
$imageFileName = $this->galleryService->getImageFileName($slug, $image, $thumb);
$imageStream = new Stream(fopen($imageFileName, 'r'));
$response = new Response();
return $response
->withHeader('Content-Type', (new \finfo(FILEINFO_MIME))->file($imageFileName))
->withHeader('Content-Disposition', 'attachment; filename=' . basename($imageFileName))
->withHeader('Content-Disposition', 'inline; filename=' . basename($imageFileName))
->withHeader('Content-Transfer-Encoding', 'Binary')
->withHeader('Content-Description', 'File Transfer')
->withHeader('Pragma', 'public')
// ->withHeader('Expires', '0')
// ->withHeader('Cache-Control', 'must-revalidate')
->withBody($stream)
->withHeader('Content-Length', "{$stream->getSize()}");
->withBody($imageStream)
->withHeader('Content-Length', "{$imageStream->getSize()}");
}
}

View File

@ -56,6 +56,18 @@ class Image implements \JsonSerializable
*/
private $height = 0;
/**
* @ORM\Column(name="thumb_width", type="integer")
* @var string
*/
private $thumbWidth = 0;
/**
* @ORM\Column(name="thumb_type", type="integer")
* @var string
*/
private $thumbHeight = 0;
/**
* @return int
*/
@ -164,6 +176,42 @@ class Image implements \JsonSerializable
return $this;
}
/**
* @return int
*/
public function getThumbWidth(): ?int
{
return $this->thumbWidth;
}
/**
* @param int $width
* @return Image
*/
public function setThumbWidth(?int $width): Image
{
$this->thumbWidth = $width;
return $this;
}
/**
* @return int
*/
public function getThumbHeight(): ?int
{
return $this->thumbHeight;
}
/**
* @param int $height
* @return Image
*/
public function setThumbHeight(?int $height): Image
{
$this->thumbHeight = $height;
return $this;
}
public function jsonSerialize()
{
return [
@ -172,6 +220,8 @@ class Image implements \JsonSerializable
'path' => $this->getPath(),
'width' => $this->getWidth(),
'height' => $this->getHeight(),
'thumbWidth' => $this->getThumbWidth(),
'thumbHeight' => $this->getThumbHeight(),
];
}
}

View File

@ -36,98 +36,6 @@ class GalleryService
$this->em = $entityManager;
}
public function loadGalleryData($includeHidden = false)
{
$config = $this->getConfig();
$albums = [];
foreach ($config['galleries'] as $id => $data) {
if ($includeHidden || $data['public']) {
$albums[] = [
'slug' => $id,
'name' => $data['name'],
'coverImage' => isset($data['cover'])
? $this->getCoverImage($data['cover'])
: null,
'date' => $this->getGalleryDate($data['dir']),
'type' => $data['type'],
'isNew' => $data['new'],
'isPublic' => $data['public'],
'images' => $this->loadGalleryImages($data['dir']),
];
}
}
return $albums;
}
private function getGalleryDate(string $dir): string
{
$timestamp = sprintf("@%s", filemtime(sprintf(self::IMAGE_BASEDIR, $dir)));
$date = new \DateTime($timestamp);
return $date->format("Y-m-d");
}
/**
* @param string $dir
* @return Image[]
* @todo implement label for image in some way
*/
private function loadGalleryImages(string $dir): array
{
$images = array_map('basename', glob(
sprintf(self::IMAGE_BASEDIR . "*.{jpg,jpeg,png}", $dir),
GLOB_BRACE
));
$imagine = new Imagine();
return array_map(function ($image) use ($dir, $imagine) {
$imageEntity = $this->em->getRepository(Image::class)->findOneBy([
'dir' => $dir,
'path' => $image,
]);
if (null === $imageEntity) {
$imageEntity = new Image();
$imageEntity->setLabel("")
->setDir($dir)
->setPath($image);
$this->processImageSizes($dir, $imageEntity, $imagine);
$this->em->persist($imageEntity);
$this->em->flush();
}
return $imageEntity;
}, $images);
}
private function processImageSizes(string $dir, Image $image, Imagine $imagine)
{
$img = $imagine->open(sprintf(self::IMAGE_BASEDIR, $dir) . $image->getPath());
$imgSize = $img->getSize();
$image->setWidth($imgSize->getWidth())
->setHeight($imgSize->getHeight());
}
/**
* @param string $image
* @return Image
*/
private function getCoverImage(string $image): Image
{
$img = new Image();
return $img->setLabel("")
->setPath($image)
->setWidth(0)
->setHeight(0);
}
public function getImage(string $slug, string $image, $size = false): string
{
$config = $this->getConfig();
$galleryDir = sprintf(self::IMAGE_BASEDIR, $config['galleries'][$slug]['dir']);
$imageFileName = $size
? $this->getResizedImageName($galleryDir, $image, $size)
: ($galleryDir . $image);
return $imageFileName;
}
public function exportGallery(string $slug)
{
$config = $this->getConfig();
@ -149,18 +57,98 @@ class GalleryService
return $zipName;
}
protected function getResizedImageName($galleryDirectory, $imageName, $size): string
public function loadGalleryData($includeHidden = false)
{
$numericSize = $size == 'thumb' ? self::THUMBNAIL_SIZE : $size;
$config = $this->getConfig();
$albums = [];
foreach ($config['galleries'] as $id => $data) {
if ($includeHidden || $data['public']) {
$galleryImages = $this->loadGalleryImages($data['dir']);
$albums[] = [
'slug' => $id,
'name' => $data['name'],
'coverImage' => isset($data['cover'])
? $this->getCoverImage($galleryImages, $data['cover'])
: null,
'date' => $this->getGalleryDate($data['dir']),
'type' => $data['type'],
'isNew' => $data['new'],
'isPublic' => $data['public'],
'images' => $galleryImages,
];
}
}
return $albums;
}
$thumbPath = $galleryDirectory . "thumb_" . $numericSize;
private function getCoverImage(array &$images, string $coverFileName): Image
{
$filtered = array_values(array_filter($images, function(Image $image) use ($coverFileName) {
return $image->getPath() == $coverFileName;
}));
return array_pop($filtered);
}
private function getGalleryDate(string $dir): string
{
$timestamp = sprintf("@%s", filemtime($this->getImageDir($dir)));
$date = new \DateTime($timestamp);
return $date->format("Y-m-d");
}
/**
* @param string $dir
* @return Image[]
* @todo implement label for image in some way
*/
private function loadGalleryImages(string $dir): array
{
$images = array_map('basename', glob(
sprintf(self::IMAGE_BASEDIR . "*.{jpg,jpeg,png}", $dir),
GLOB_BRACE
));
$imagine = new Imagine();
return array_map(function ($imagePath) use ($dir, $imagine) {
$imageEntity = $this->em->getRepository(Image::class)->findOneBy([
'dir' => $dir,
'path' => $imagePath,
]);
$this->ensureThumbnailExists($dir, $imagePath);
if (null === $imageEntity) {
$image = $imagine->open($this->getImageDir($dir) . $imagePath);
$imageSize = $image->getSize();
unset($image);
$thumb = $imagine->open($this->getThumbDir($dir) . $imagePath);
$thumbSize = $thumb->getSize();
unset($thumb);
$imageEntity = new Image();
$imageEntity->setLabel("")
->setDir($dir)
->setPath($imagePath)
->setWidth($imageSize->getWidth())
->setHeight($imageSize->getHeight())
->setThumbWidth($thumbSize->getWidth())
->setThumbHeight($thumbSize->getHeight())
;
$this->em->persist($imageEntity);
$this->em->flush();
}
return $imageEntity;
}, $images);
}
private function ensureThumbnailExists(string $dir, string $imageName) {
$imageDir = $this->getImageDir($dir);
$thumbPath = $imageDir . "thumb_" . self::THUMBNAIL_SIZE;
@mkdir($thumbPath);
$thumbImageName = $thumbPath . "/" . $imageName;
if (!file_exists($thumbImageName)) {
$thumbSize = new Box($numericSize, $numericSize*10);
$thumbSize = new Box(self::THUMBNAIL_SIZE, self::THUMBNAIL_SIZE * 10);
$imagine = new Imagine();
$image = $imagine->open($galleryDirectory . $imageName)
$image = $imagine->open($imageDir . $imageName)
->thumbnail($thumbSize, ImageInterface::THUMBNAIL_INSET);
$image->effects()->sharpen();
$image->save($thumbImageName);
@ -169,7 +157,25 @@ class GalleryService
return $thumbImageName;
}
protected function getConfig()
public function getImageFileName(string $slug, string $image, $isThumbnail = false): string
{
$config = $this->getConfig();
$dir = $config['galleries'][$slug]['dir'];
$this->ensureThumbnailExists($config['galleries'][$slug]['dir'], $image);
return $isThumbnail
? ($this->getThumbDir($dir) . $image)
: ($this->getImageDir($dir) . $image);
}
private function getImageDir($dir): string {
return sprintf(self::IMAGE_BASEDIR, $dir);
}
private function getThumbDir($dir): string {
return sprintf(self::IMAGE_BASEDIR, "{$dir}/thumb_" . self::THUMBNAIL_SIZE);
}
private function getConfig()
{
if (null === $this->config) {
$parser = new Parser();