Крок 23: Зміна розміру зображень

5.2 version
Maintained

Зміна розміру зображень

У дизайні сторінки конференції фотографії обмежені максимальним розміром 200 на 150 пікселів. Як щодо оптимізації зображень та зменшення їх розміру, якщо завантажений оригінал перевищує встановлені обмеження?

Це ідеальне завдання, яке можна додати в робочий процес коментарів, ймовірно, відразу після перевірки коментаря і безпосередньо перед його публікацією.

Додаймо новий стан ready та перехід optimize:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
--- a/config/packages/workflow.yaml
+++ b/config/packages/workflow.yaml
@@ -16,6 +16,7 @@ framework:
                 - potential_spam
                 - spam
                 - rejected
+                - ready
                 - published
             transitions:
                 accept:
@@ -29,13 +30,16 @@ framework:
                     to:   spam
                 publish:
                     from: potential_spam
-                    to:   published
+                    to:   ready
                 reject:
                     from: potential_spam
                     to:   rejected
                 publish_ham:
                     from: ham
-                    to:   published
+                    to:   ready
                 reject_ham:
                     from: ham
                     to:   rejected
+                optimize:
+                    from: ready
+                    to:   published

Згенеруйте візуальне представлення нової конфігурації робочого процесу, щоб переконатися, що воно описує те, що ми хочемо:

1
$ symfony console workflow:dump comment | dot -Tpng -o workflow.png
../_images/workflow-final.png

Оптимізація зображень за допомогою Imagine

Процеси оптимізації зображення будуть здійснені завдяки GD (переконайтеся, що у вашій локальній збірці PHP увімкнено розширення GD) та Imagine:

1
$ symfony composer req "imagine/imagine:^1.2"

Зміну розміру зображення можна здійснити за допомогою наступного сервісного класу:

src/ImageOptimizer.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace App;

use Imagine\Gd\Imagine;
use Imagine\Image\Box;

class ImageOptimizer
{
    private const MAX_WIDTH = 200;
    private const MAX_HEIGHT = 150;

    private $imagine;

    public function __construct()
    {
        $this->imagine = new Imagine();
    }

    public function resize(string $filename): void
    {
        list($iwidth, $iheight) = getimagesize($filename);
        $ratio = $iwidth / $iheight;
        $width = self::MAX_WIDTH;
        $height = self::MAX_HEIGHT;
        if ($width / $height > $ratio) {
            $width = $height * $ratio;
        } else {
            $height = $width / $ratio;
        }

        $photo = $this->imagine->open($filename);
        $photo->resize(new Box($width, $height))->save($filename);
    }
}

Після оптимізації фотографії ми зберігаємо новий файл замість оригінального. Хоча, можливо, ви захочете зберегти оригінальне зображення.

Додавання нового кроку в робочий процес

Змініть робочий процес для обробки нового стану:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
--- a/src/MessageHandler/CommentMessageHandler.php
+++ b/src/MessageHandler/CommentMessageHandler.php
@@ -2,6 +2,7 @@

 namespace App\MessageHandler;

+use App\ImageOptimizer;
 use App\Message\CommentMessage;
 use App\Repository\CommentRepository;
 use App\SpamChecker;
@@ -21,10 +22,12 @@ class CommentMessageHandler implements MessageHandlerInterface
     private $bus;
     private $workflow;
     private $mailer;
+    private $imageOptimizer;
     private $adminEmail;
+    private $photoDir;
     private $logger;

-    public function __construct(EntityManagerInterface $entityManager, SpamChecker $spamChecker, CommentRepository $commentRepository, MessageBusInterface $bus, WorkflowInterface $commentStateMachine, MailerInterface $mailer, string $adminEmail, LoggerInterface $logger = null)
+    public function __construct(EntityManagerInterface $entityManager, SpamChecker $spamChecker, CommentRepository $commentRepository, MessageBusInterface $bus, WorkflowInterface $commentStateMachine, MailerInterface $mailer, ImageOptimizer $imageOptimizer, string $adminEmail, string $photoDir, LoggerInterface $logger = null)
     {
         $this->entityManager = $entityManager;
         $this->spamChecker = $spamChecker;
@@ -32,7 +35,9 @@ class CommentMessageHandler implements MessageHandlerInterface
         $this->bus = $bus;
         $this->workflow = $commentStateMachine;
         $this->mailer = $mailer;
+        $this->imageOptimizer = $imageOptimizer;
         $this->adminEmail = $adminEmail;
+        $this->photoDir = $photoDir;
         $this->logger = $logger;
     }

@@ -64,6 +69,12 @@ class CommentMessageHandler implements MessageHandlerInterface
                 ->to($this->adminEmail)
                 ->context(['comment' => $comment])
             );
+        } elseif ($this->workflow->can($comment, 'optimize')) {
+            if ($comment->getPhotoFilename()) {
+                $this->imageOptimizer->resize($this->photoDir.'/'.$comment->getPhotoFilename());
+            }
+            $this->workflow->apply($comment, 'optimize');
+            $this->entityManager->flush();
         } elseif ($this->logger) {
             $this->logger->debug('Dropping comment message', ['comment' => $comment->getId(), 'state' => $comment->getState()]);
         }

Зверніть увагу, що $photoDir впроваджено автоматично, оскільки ми визначили прив’язку контейнера до імені цієї змінної на попередньому кроці:

config/packages/services.yaml
1
2
3
4
services:
    _defaults:
        bind:
            $photoDir: "%kernel.project_dir%/public/uploads/photos"

Зберігання завантажених даних у продакшн

Ми вже визначили спеціальний каталог, доступний для читання та запису, для завантажених файлів у .symfony.cloud.yaml. Але він монтується локально. Якщо ми хочемо, щоб веб-контейнер і воркер споживача повідомлень мали можливість отримати доступ до того ж монтування, нам потрібно створити файловий сервіс:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
--- a/.symfony/services.yaml
+++ b/.symfony/services.yaml
@@ -19,3 +19,7 @@ varnish:
         vcl: !include
             type: string
             path: config.vcl
+
+files:
+    type: network-storage:1.0
+    disk: 256

Використовуйте його для каталогу завантаження фотографій:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/.symfony.cloud.yaml
+++ b/.symfony.cloud.yaml
@@ -37,7 +37,7 @@ web:

 mounts:
     "/var": { source: local, source_path: var }
-    "/public/uploads": { source: local, source_path: uploads }
+    "/public/uploads": { source: service, service: files, source_path: uploads }

 hooks:
     build: |

Цього має бути достатньо для того, щоб функція працювала в продакшн.


  • « Previous Крок 22: Стилізація інтерфейсу користувача за допомогою Webpack
  • Next » Крок 24: Виконання завдань cron

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.