From 71253ff1ac626247818373072e322647a940f9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danyi=20D=C3=A1vid?= Date: Mon, 14 Aug 2017 23:01:33 +0200 Subject: [PATCH] * thumbnail generation refactored * thumbnail dimensions are also cached in db now --- src/App/Action/GetImageAction.php | 11 +- src/App/Entity/Image.php | 50 +++++++ src/App/Service/GalleryService.php | 202 +++++++++++++++-------------- 3 files changed, 159 insertions(+), 104 deletions(-) diff --git a/src/App/Action/GetImageAction.php b/src/App/Action/GetImageAction.php index 2f4efe2..59fe5ae 100644 --- a/src/App/Action/GetImageAction.php +++ b/src/App/Action/GetImageAction.php @@ -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()}"); } } diff --git a/src/App/Entity/Image.php b/src/App/Entity/Image.php index 1a9c344..3ceb212 100644 --- a/src/App/Entity/Image.php +++ b/src/App/Entity/Image.php @@ -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(), ]; } } \ No newline at end of file diff --git a/src/App/Service/GalleryService.php b/src/App/Service/GalleryService.php index 7dd3723..2b95d98 100644 --- a/src/App/Service/GalleryService.php +++ b/src/App/Service/GalleryService.php @@ -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();