ImagickDriver.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. /**
  3. * This file is part of the ForkBB <https://github.com/forkbb>.
  4. *
  5. * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
  6. * @license The MIT License (MIT)
  7. */
  8. declare(strict_types=1);
  9. namespace ForkBB\Core\Image;
  10. use Imagick;
  11. use ForkBB\Core\Files;
  12. use ForkBB\Core\Image\DefaultDriver;
  13. use ForkBB\Core\Exceptions\FileException;
  14. use Exception;
  15. class ImagickDriver extends DefaultDriver
  16. {
  17. const DEFAULT = false;
  18. public function __construct(Files $files)
  19. {
  20. parent::__construct($files);
  21. $this->ready = \extension_loaded('imagick') && \class_exists('\\Imagick');
  22. }
  23. public function readFromStr(string $data) /* : mixed|false */
  24. {
  25. if ($this->ready) {
  26. try {
  27. $imagick = new Imagick();
  28. $imagick->readImageBlob($data);
  29. return $imagick;
  30. } catch (Exception $e) {
  31. }
  32. }
  33. return false;
  34. }
  35. public function readFromPath(string $path) /* : mixed|false */
  36. {
  37. if (
  38. ! $this->ready
  39. || $this->files->isBadPath($path)
  40. ) {
  41. return false;
  42. } else {
  43. try {
  44. return new Imagick(\realpath($path));
  45. } catch (Exception $e) {
  46. return false;
  47. }
  48. }
  49. }
  50. public function writeToPath(/* mixed */ $imagick, string $path, int $quality): ?bool
  51. {
  52. if (! $this->ready) {
  53. return null;
  54. }
  55. try {
  56. $type = \pathinfo($path, \PATHINFO_EXTENSION);
  57. switch ($type) {
  58. case 'png':
  59. $imagick->setImageCompressionQuality(0); // ???? пересчитать как в GD?
  60. break;
  61. default:
  62. $imagick->setImageCompressionQuality($quality);
  63. break;
  64. }
  65. return $imagick->writeImages($path, true);
  66. } catch (Exception $e) {
  67. return false;
  68. }
  69. }
  70. public function resize(/* mixed */ $imagick, int $maxW, int $maxH) /* : mixed */
  71. {
  72. if (! $this->ready) {
  73. throw new FileException('ImageMagick library not enabled');
  74. }
  75. try {
  76. $oldW = $imagick->getImageWidth();
  77. $oldH = $imagick->getImageHeight();
  78. $wr = $maxW < 16 ? 1 : $maxW / $oldW;
  79. $hr = $maxH < 16 ? 1 : $maxH / $oldH;
  80. $r = \min($wr, $hr, 1);
  81. if (1 == $r) {
  82. return $imagick;
  83. }
  84. $width = (int) \round($oldW * $r);
  85. $height = (int) \round($oldH * $r);
  86. // есть анимация
  87. if ($imagick->getImageDelay() > 0) {
  88. $images = $imagick->coalesceImages();
  89. foreach ($images as $frame) {
  90. $frame->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
  91. $frame->setImagePage($width, $height, 0, 0);
  92. }
  93. return $images->deconstructImages();
  94. // нет анимации
  95. } else {
  96. $imagick->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
  97. return $imagick;
  98. }
  99. } catch (Exception $e) {
  100. throw new FileException($e->getMessage());
  101. }
  102. }
  103. public function destroy(/* mixed */ $imagick): void
  104. {
  105. }
  106. }