Skip to content

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

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

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

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

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
--- i/config/packages/workflow.yaml
+++ w/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

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

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

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

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

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 readonly Imagine $imagine;

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

    public function resize(string $filename): void
    {
        [$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);
    }
}

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

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

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

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
--- i/src/MessageHandler/CommentMessageHandler.php
+++ w/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;
@@ -25,6 +26,8 @@ class CommentMessageHandler
         private WorkflowInterface $commentStateMachine,
         private MailerInterface $mailer,
         #[Autowire('%admin_email%')] private string $adminEmail,
+        private ImageOptimizer $imageOptimizer,
+        #[Autowire('%photo_dir%')] private string $photoDir,
         private ?LoggerInterface $logger = null,
     ) {
     }
@@ -54,6 +57,12 @@ class CommentMessageHandler
                 ->to($this->adminEmail)
                 ->context(['comment' => $comment])
             );
+        } elseif ($this->commentStateMachine->can($comment, 'optimize')) {
+            if ($comment->getPhotoFilename()) {
+                $this->imageOptimizer->resize($this->photoDir.'/'.$comment->getPhotoFilename());
+            }
+            $this->commentStateMachine->apply($comment, 'optimize');
+            $this->entityManager->flush();
         } elseif ($this->logger) {
             $this->logger->debug('Dropping comment message', ['comment' => $comment->getId(), 'state' => $comment->getState()]);
         }

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

config/services.yaml
1
2
parameters:
    photo_dir: "%kernel.project_dir%/public/uploads/photos"

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

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

1
2
3
4
5
6
7
8
9
10
--- i/.upsun/config.yaml
+++ w/.upsun/config.yaml
@@ -15,6 +15,9 @@ services:
                 type: string
                 path: config.vcl

+    files:
+        type: network-storage:2.0
+
 applications:

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

1
2
3
4
5
6
7
8
9
10
11
--- i/.upsun/config.yaml
+++ w/.upsun/config.yaml
@@ -54,7 +54,7 @@ applications:
         mounts:
             "/var/cache": { source: instance, source_path: var/cache }
             "/var/share": { source: storage, source_path: var/share }
-            "/public/uploads": { source: storage, source_path: uploads }
+            "/public/uploads": { source: service, service: files, source_path: uploads }


         relationships:

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

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