d8eb50df292c9c4943043a081af574d6bfe3a772
[yaffs-website] / web / modules / contrib / imagemagick / src / Plugin / FileMetadata / ImagemagickIdentify.php
1 <?php
2
3 namespace Drupal\imagemagick\Plugin\FileMetadata;
4
5 use Drupal\Core\Cache\CacheBackendInterface;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\Extension\ModuleHandlerInterface;
8 use Drupal\file_mdm\FileMetadataException;
9 use Drupal\file_mdm\Plugin\FileMetadata\FileMetadataPluginBase;
10 use Drupal\imagemagick\ImagemagickExecArguments;
11 use Drupal\imagemagick\ImagemagickExecManagerInterface;
12 use Symfony\Component\DependencyInjection\ContainerInterface;
13
14 /**
15  * FileMetadata plugin for ImageMagick's identify results.
16  *
17  * @FileMetadata(
18  *   id = "imagemagick_identify",
19  *   title = @Translation("ImageMagick identify"),
20  *   help = @Translation("File metadata plugin for ImageMagick identify results."),
21  * )
22  */
23 class ImagemagickIdentify extends FileMetadataPluginBase {
24
25   /**
26    * The module handler service.
27    *
28    * @var \Drupal\Core\Extension\ModuleHandlerInterface
29    */
30   protected $moduleHandler;
31
32   /**
33    * The ImageMagick execution manager service.
34    *
35    * @var \Drupal\imagemagick\ImagemagickExecManagerInterface
36    */
37   protected $execManager;
38
39   /**
40    * Constructs an ImagemagickIdentify plugin.
41    *
42    * @param array $configuration
43    *   A configuration array containing information about the plugin instance.
44    * @param string $plugin_id
45    *   The plugin_id for the plugin instance.
46    * @param array $plugin_definition
47    *   The plugin implementation definition.
48    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_service
49    *   The cache service.
50    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
51    *   The config factory.
52    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
53    *   The module handler service.
54    * @param \Drupal\imagemagick\ImagemagickExecManagerInterface $exec_manager
55    *   The ImageMagick execution manager service.
56    */
57   public function __construct(array $configuration, $plugin_id, array $plugin_definition, CacheBackendInterface $cache_service, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ImagemagickExecManagerInterface $exec_manager) {
58     parent::__construct($configuration, $plugin_id, $plugin_definition, $cache_service, $config_factory);
59     $this->moduleHandler = $module_handler;
60     $this->execManager = $exec_manager;
61   }
62
63   /**
64    * {@inheritdoc}
65    */
66   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
67     return new static(
68       $configuration,
69       $plugin_id,
70       $plugin_definition,
71       $container->get('cache.file_mdm'),
72       $container->get('config.factory'),
73       $container->get('module_handler'),
74       $container->get('imagemagick.exec_manager')
75     );
76   }
77
78   /**
79    * {@inheritdoc}
80    *
81    * Supported keys are:
82    *   'format' - ImageMagick's image format identifier.
83    *   'width' - Image width.
84    *   'height' - Image height.
85    *   'colorspace' - Image colorspace.
86    *   'profiles' - Image profiles.
87    *   'exif_orientation' - Image EXIF orientation (only supported formats).
88    *   'source_local_path' - The local file path from where the file was
89    *     parsed.
90    *   'frames_count' - Number of frames in the image.
91    */
92   public function getSupportedKeys($options = NULL) {
93     return [
94       'format',
95       'width',
96       'height',
97       'colorspace',
98       'profiles',
99       'exif_orientation',
100       'source_local_path',
101       'frames_count',
102     ];
103   }
104
105   /**
106    * {@inheritdoc}
107    */
108   protected function doGetMetadataFromFile() {
109     return $this->identify();
110   }
111
112   /**
113    * Validates a file metadata key.
114    *
115    * @return bool
116    *   TRUE if the key is valid.
117    *
118    * @throws \Drupal\file_mdm\FileMetadataException
119    *   In case the key is invalid.
120    */
121   protected function validateKey($key, $method) {
122     if (!is_string($key)) {
123       throw new FileMetadataException("Invalid metadata key specified", $this->getPluginId(), $method);
124     }
125     if (!in_array($key, $this->getSupportedKeys(), TRUE)) {
126       throw new FileMetadataException("Invalid metadata key '{$key}' specified", $this->getPluginId(), $method);
127     }
128     return TRUE;
129   }
130
131   /**
132    * {@inheritdoc}
133    */
134   protected function doGetMetadata($key = NULL) {
135     if ($key === NULL) {
136       return $this->metadata;
137     }
138     else {
139       $this->validateKey($key, __FUNCTION__);
140       switch ($key) {
141         case 'source_local_path':
142           return isset($this->metadata['source_local_path']) ? $this->metadata['source_local_path'] : NULL;
143
144         case 'frames_count':
145           return isset($this->metadata['frames']) ? count($this->metadata['frames']) : 0;
146
147         default:
148           return isset($this->metadata['frames'][0][$key]) ? $this->metadata['frames'][0][$key] : NULL;
149
150       }
151     }
152   }
153
154   /**
155    * {@inheritdoc}
156    */
157   protected function doSetMetadata($key, $value) {
158     $this->validateKey($key, __FUNCTION__);
159     switch ($key) {
160       case 'source_local_path':
161         $this->metadata['source_local_path'] = $value;
162         return TRUE;
163
164       case 'frames_count':
165         return FALSE;
166
167       default:
168         $this->metadata['frames'][0][$key] = $value;
169         return TRUE;
170
171     }
172   }
173
174   /**
175    * {@inheritdoc}
176    */
177   protected function doRemoveMetadata($key) {
178     $this->validateKey($key, __FUNCTION__);
179     switch ($key) {
180       case 'source_local_path':
181         if (isset($this->metadata['source_local_path'])) {
182           unset($this->metadata['source_local_path']);
183           return TRUE;
184         }
185         return FALSE;
186
187       default:
188         return FALSE;
189
190     }
191   }
192
193   /**
194    * {@inheritdoc}
195    */
196   protected function getMetadataToCache() {
197     $metadata = $this->metadata;
198     // Avoid caching the source_local_path.
199     unset($metadata['source_local_path']);
200     return $metadata;
201   }
202
203   /**
204    * Calls the identify executable on the specified file.
205    *
206    * @return array
207    *   The array with identify metadata, if the file was parsed correctly.
208    *   NULL otherwise.
209    */
210   protected function identify() {
211     $arguments = new ImagemagickExecArguments($this->execManager);
212
213     // Add source file.
214     $arguments->setSource($this->getLocalTempPath());
215
216     // Prepare the -format argument according to the graphics package in use.
217     switch ($this->execManager->getPackage()) {
218       case 'imagemagick':
219         $arguments->add(
220           '-format ' . $arguments->escape("format:%[magick]|width:%[width]|height:%[height]|colorspace:%[colorspace]|profiles:%[profiles]|exif_orientation:%[EXIF:Orientation]\\n"),
221           ImagemagickExecArguments::PRE_SOURCE
222         );
223         break;
224
225       case 'graphicsmagick':
226         $arguments->add(
227           '-format ' . $arguments->escape("format:%m|width:%w|height:%h|exif_orientation:%[EXIF:Orientation]\\n"),
228           ImagemagickExecArguments::PRE_SOURCE
229         );
230         break;
231
232     }
233
234     // Allow modules to alter source file and the command line parameters.
235     $command = 'identify';
236     $this->moduleHandler->alter('imagemagick_pre_parse_file', $arguments);
237     $this->moduleHandler->alter('imagemagick_arguments', $arguments, $command);
238
239     // Execute the 'identify' command.
240     $output = NULL;
241     $ret = $this->execManager->execute($command, $arguments, $output);
242
243     // Process results.
244     $data = [];
245     if ($ret) {
246       // Remove any CR character (GraphicsMagick on Windows produces such).
247       $output = str_replace("\r", '', $output);
248
249       // Builds the frames info.
250       $frames = [];
251       $frames_tmp = explode("\n", $output);
252       // Remove empty items at the end of the array.
253       while (empty($frames_tmp[count($frames_tmp) - 1])) {
254         array_pop($frames_tmp);
255       }
256       foreach ($frames_tmp as $i => $frame) {
257         $info = explode('|', $frame);
258         foreach ($info as $item) {
259           list($key, $value) = explode(':', $item);
260           if (trim($key) === 'profiles') {
261             $profiles_tmp = empty($value) ? [] : explode(',', $value);
262             $frames[$i][trim($key)] = $profiles_tmp;
263           }
264           else {
265             $frames[$i][trim($key)] = trim($value);
266           }
267         }
268       }
269       $data['frames'] = $frames;
270       // Adds the local file path that was resolved via
271       // hook_imagemagick_pre_parse_file implementations.
272       $data['source_local_path'] = $arguments->getSourceLocalPath();
273     }
274
275     return ($ret === TRUE) ? $data : NULL;
276   }
277
278 }