Add image cropper configuration
authorCyperghost <olaf_schmitz_1@t-online.de>
Tue, 5 Nov 2024 10:54:21 +0000 (11:54 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Tue, 5 Nov 2024 10:54:21 +0000 (11:54 +0100)
wcfsetup/install/files/lib/system/file/processor/AbstractFileProcessor.class.php
wcfsetup/install/files/lib/system/file/processor/IFileProcessor.class.php
wcfsetup/install/files/lib/system/file/processor/ImageCropSize.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/file/processor/ImageCropperConfiguration.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/file/processor/ImageCropperType.class.php [new file with mode: 0644]

index 750edfeb35a1c0322ca1ed1e88d759fda2cda55f..21634bd5a02c88e4be7d2438c502094ea84a0408 100644 (file)
@@ -90,4 +90,11 @@ abstract class AbstractFileProcessor implements IFileProcessor
     {
         // Do not track downloads.
     }
+
+    #[\Override]
+    public function getImageCropperConfiguration(): ?ImageCropperConfiguration
+    {
+        // Do not crop images.
+        return null;
+    }
 }
index 701d22ce1a6080357f391e516fb4ca50c44014b1..2682d3057086a735c783350ff6919edca0eb4b67 100644 (file)
@@ -156,4 +156,9 @@ interface IFileProcessor
      * file types that are served by the web server itself.
      */
     public function trackDownload(File $file): void;
+
+    /**
+     * Returns the image cropper configuration for this file processor.
+     */
+    public function getImageCropperConfiguration(): ?ImageCropperConfiguration;
 }
diff --git a/wcfsetup/install/files/lib/system/file/processor/ImageCropSize.class.php b/wcfsetup/install/files/lib/system/file/processor/ImageCropSize.class.php
new file mode 100644 (file)
index 0000000..993fb20
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+namespace wcf\system\file\processor;
+
+final class ImageCropSize
+{
+    public function __construct(
+        public readonly int $width,
+        public readonly int $height
+    ) {
+        if ($width <= 0 || $height <= 0) {
+            throw new \OutOfRangeException("The width and height values must be larger than 0.");
+        }
+    }
+
+    public function aspectRatio(): float
+    {
+        return $this->width / $this->height;
+    }
+}
diff --git a/wcfsetup/install/files/lib/system/file/processor/ImageCropperConfiguration.class.php b/wcfsetup/install/files/lib/system/file/processor/ImageCropperConfiguration.class.php
new file mode 100644 (file)
index 0000000..4929f6d
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+
+namespace wcf\system\file\processor;
+
+final class ImageCropperConfiguration
+{
+    public readonly float $aspectRatio;
+
+    /**
+     * @var ImageCropSize[]
+     */
+    public readonly array $sizes;
+
+    public function __construct(
+        public readonly ImageCropperType $type,
+        ImageCropSize ...$sizes
+    ) {
+        if ($sizes === []) {
+            throw new \InvalidArgumentException('At least one size must be provided.');
+        }
+
+        $size = $sizes[0];
+        $this->aspectRatio = $size->aspectRatio();
+
+        foreach ($sizes as $size) {
+            if ($size->aspectRatio() !== $this->aspectRatio) {
+                throw new \InvalidArgumentException('All sizes must have the same aspect ratio.');
+            }
+        }
+
+        \usort($sizes, function (ImageCropSize $a, ImageCropSize $b) {
+            if ($a->width > $a->height) {
+                return $a->width <=> $b->width;
+            } else {
+                return $a->height <=> $b->height;
+            }
+        });
+        $this->sizes = $sizes;
+    }
+
+    /**
+     * Creates an image cropper with minimum and maximum size with the same aspect ratio.
+     * The user can freely select, move and scale.
+     * However, the cropping area is limited to `$min` and `$max`.
+     */
+    public static function createMinMax(ImageCropSize $min, ImageCropSize $max): self
+    {
+        return new self(ImageCropperType::MinMax, $min, $max);
+    }
+
+    /**
+     * Creates an image cropper that reduces the image to a specific size
+     * and only allows the user to move the cropping area.
+     * The size is determined by `$sizes` and corresponds to the smallest side of the image that is the next smaller
+     * or equal size of `$sizes`. The aspect ratio of the uploaded image is retained.
+     *
+     * Example:
+     * `$sizes` is [128x128, 256x256]
+     * - Image is 100x200
+     *   - Image is rejected
+     * - Image is 200x150
+     *   - Image is resized to 170x128
+     * - Image is 150x200
+     *   - Image is resized to 128x170
+     * - Image is 300x300
+     *   - Image is resized to 256x256
+     */
+    public static function createExact(ImageCropSize ...$sizes): self
+    {
+        return new self(ImageCropperType::Exact, ...$sizes);
+    }
+}
diff --git a/wcfsetup/install/files/lib/system/file/processor/ImageCropperType.class.php b/wcfsetup/install/files/lib/system/file/processor/ImageCropperType.class.php
new file mode 100644 (file)
index 0000000..54330f3
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace wcf\system\file\processor;
+
+enum ImageCropperType
+{
+    case MinMax;
+    case Exact;
+}