ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
CropSquare.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
33 
38 class CropSquare extends AbstractMachine implements FlavourMachine
39 {
41 
42  public const ID = 'crop_square';
43  public const QUALITY = 30;
44 
45  public function getId(): string
46  {
47  return self::ID;
48  }
49 
50  public function canHandleDefinition(FlavourDefinition $definition): bool
51  {
52  return $definition instanceof CropToSquare;
53  }
54 
55  public function dependsOnEngine(): ?string
56  {
57  return GDEngine::class;
58  }
59 
60  public function processStream(
61  FileInformation $information,
62  FileStream $stream,
63  FlavourDefinition $for_definition
64  ): \Generator {
65  if (!$for_definition instanceof \ILIAS\ResourceStorage\Flavour\Definition\CropToSquare) {
66  throw new \InvalidArgumentException('Invalid definition');
67  }
68  $image = $this->from($stream);
69  if (!is_resource($image) && !$image instanceof \GdImage) {
70  return;
71  }
72 
73  $stream_path = $stream->getMetadata()['uri'] ?? '';
74  $must_flip = $this->maybeRotate($stream_path, $image);
75 
76  if ($stream_path === 'php://memory') {
77  [$width, $height] = getimagesizefromstring((string) $stream);
78  } else {
79  [$width, $height] = getimagesize($stream_path);
80  }
81 
82  if ($must_flip) {
83  $tmp = $width;
84  $width = $height;
85  $height = $tmp;
86  }
87 
88  if ($width > $height) {
89  $y = 0;
90  $x = (int) (($width - $height) / 2);
91  $smallest_side = (int) $height;
92  } else {
93  $x = 0;
94  $y = (int) (($height - $width) / 2);
95  $smallest_side = (int) $width;
96  }
97 
98  $size = (int) $for_definition->getMaxSize();
99 
100  $thumb = imagecreatetruecolor($size, $size);
101 
102  imagecopyresampled(
103  $thumb,
104  $image,
105  0,
106  0,
107  $x,
108  $y,
109  $size,
110  $size,
111  $smallest_side,
112  $smallest_side
113  );
114 
115  imagedestroy($image);
116 
117  $stream = $this->to($thumb, $for_definition->getQuality());
118 
119  yield new Result(
120  $for_definition,
121  $stream,
122  0,
123  $for_definition->persist()
124  );
125  }
126 
127  protected function maybeRotate(string $stream_path, \GdImage &$image): bool
128  {
129  // if PHP exif is installed, this is quite easy
130  $exif = new ExifEngine();
131  if ($exif->isRunning() && ($exif_data = $exif->read($stream_path)) !== []) {
132  switch ($exif_data['Orientation'] ?? null) {
133  case 8:
134  $image = imagerotate($image, 90, 0);
135  return true;
136  case 3:
137  $image = imagerotate($image, 180, 0);
138  return false;
139  case 6:
140  $image = imagerotate($image, -90, 0);
141  return true;
142  default:
143  return false;
144  }
145  }
146  // otherwise we can use Imagick (if installed)
147  $imagick = new ImagickEngine();
148  if ($imagick->isRunning()) {
149  $imagick = new \Imagick($stream_path);
150  $image_orientation = $imagick->getImageOrientation();
151  switch ($image_orientation) {
152  case \Imagick::ORIENTATION_RIGHTTOP:
153  $imagick->rotateImage('none', 90);
154  $imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT);
155  $image = $this->from(Streams::ofString($imagick->getImageBlob()));
156  return true;
157  case \Imagick::ORIENTATION_BOTTOMRIGHT:
158  $imagick->rotateImage('none', 180);
159  $imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT);
160  $image = $this->from(Streams::ofString($imagick->getImageBlob()));
161  return false;
162  case \Imagick::ORIENTATION_LEFTBOTTOM:
163  $imagick->rotateImage('none', -90);
164  $imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT);
165  $image = $this->from(Streams::ofString($imagick->getImageBlob()));
166  return true;
167  default:
168  return false;
169  }
170  }
171 
172  // we did not find any way to rotate the image
173  return false;
174  }
175 }
Interface Observer Contains several chained tasks and infos about them.
persist()
Define whether the generated flavor and the respective streams should be persisted, or whether they should only be generated and used in-memory.
dependsOnEngine()
Return the class name of the Engine that is required for this Machine to work.
Definition: CropSquare.php:55
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
canHandleDefinition(FlavourDefinition $definition)
Check if a corresponding configuration can be processed by this Machine.
Definition: CropSquare.php:50
to(\GdImage $image, int $quality=null)
Currently this is the only way to make a FileStream from a GD image resource.
static ofString(string $string)
Creates a new stream with an initial value.
Definition: Streams.php:41
processStream(FileInformation $information, FileStream $stream, FlavourDefinition $for_definition)
Definition: CropSquare.php:60
The base interface for all filesystem streams.
Definition: FileStream.php:31