|
@@ -10,9 +10,11 @@ declare(strict_types=1);
|
|
|
|
|
|
namespace ForkBB\Core\Image;
|
|
|
|
|
|
+use Imagick;
|
|
|
use ForkBB\Core\Files;
|
|
|
use ForkBB\Core\Image\DefaultDriver;
|
|
|
use ForkBB\Core\Exceptions\FileException;
|
|
|
+use Exception;
|
|
|
|
|
|
class ImagickDriver extends DefaultDriver
|
|
|
{
|
|
@@ -25,5 +27,103 @@ class ImagickDriver extends DefaultDriver
|
|
|
$this->ready = \extension_loaded('imagick') && \class_exists('\\Imagick');
|
|
|
}
|
|
|
|
|
|
+ public function readFromStr(string $data) /* : mixed|false */
|
|
|
+ {
|
|
|
+ if ($this->ready) {
|
|
|
+ try {
|
|
|
+ $imagick = new Imagick();
|
|
|
+ $imagick->readImageBlob($data);
|
|
|
+
|
|
|
+ return $imagick;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function readFromPath(string $path) /* : mixed|false */
|
|
|
+ {
|
|
|
+ if (
|
|
|
+ ! $this->ready
|
|
|
+ || $this->files->isBadPath($path)
|
|
|
+ ) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ return new Imagick(\realpath($path));
|
|
|
+ } catch (Exception $e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function writeToPath(/* mixed */ $imagick, string $path, int $quality): ?bool
|
|
|
+ {
|
|
|
+ if (! $this->ready) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ $type = \pathinfo($path, \PATHINFO_EXTENSION);
|
|
|
+
|
|
|
+ switch ($type) {
|
|
|
+ case 'png':
|
|
|
+ $imagick->setImageCompressionQuality(0); // ???? пересчитать как в GD?
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ $imagick->setImageCompressionQuality($quality);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $imagick->writeImages($path, true);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ public function resize(/* mixed */ $imagick, int $maxW, int $maxH) /* : mixed */
|
|
|
+ {
|
|
|
+ if (! $this->ready) {
|
|
|
+ throw new FileException('ImageMagick library not enabled');
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ $oldW = $imagick->getImageWidth();
|
|
|
+ $oldH = $imagick->getImageHeight();
|
|
|
+ $wr = $maxW < 16 ? 1 : $maxW / $oldW;
|
|
|
+ $hr = $maxH < 16 ? 1 : $maxH / $oldH;
|
|
|
+ $r = \min($wr, $hr, 1);
|
|
|
+
|
|
|
+ if (1 == $r) {
|
|
|
+ return $imagick;
|
|
|
+ }
|
|
|
+
|
|
|
+ $width = (int) \round($oldW * $r);
|
|
|
+ $height = (int) \round($oldH * $r);
|
|
|
+
|
|
|
+ // есть анимация
|
|
|
+ if ($imagick->getImageDelay() > 0) {
|
|
|
+ $images = $imagick->coalesceImages();
|
|
|
+
|
|
|
+ foreach ($images as $frame) {
|
|
|
+ $frame->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
|
|
|
+ $frame->setImagePage($width, $height, 0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $images->deconstructImages();
|
|
|
+ // нет анимации
|
|
|
+ } else {
|
|
|
+ $imagick->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
|
|
|
+
|
|
|
+ return $imagick;
|
|
|
+ }
|
|
|
+ } catch (Exception $e) {
|
|
|
+ throw new FileException($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function destroy(/* mixed */ $imagick): void
|
|
|
+ {
|
|
|
+ }
|
|
|
}
|