‪TYPO3CMS  9.5
ImageManipulationElement.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
30 
36 {
40  private ‪$wizardRouteName = 'ajax_wizard_image_manipulation';
41 
47  protected static ‪$defaultConfig = [
48  'file_field' => 'uid_local',
49  'allowedExtensions' => null, // default: $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
50  'cropVariants' => [
51  'default' => [
52  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.crop_variant.default',
53  'allowedAspectRatios' => [
54  '16:9' => [
55  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.16_9',
56  'value' => 16 / 9
57  ],
58  '3:2' => [
59  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.3_2',
60  'value' => 3 / 2
61  ],
62  '4:3' => [
63  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.4_3',
64  'value' => 4 / 3
65  ],
66  '1:1' => [
67  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.1_1',
68  'value' => 1.0
69  ],
70  'NaN' => [
71  'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.free',
72  'value' => 0.0
73  ],
74  ],
75  'selectedRatio' => 'NaN',
76  'cropArea' => [
77  'x' => 0.0,
78  'y' => 0.0,
79  'width' => 1.0,
80  'height' => 1.0,
81  ],
82  ],
83  ]
84  ];
85 
91  protected ‪$defaultFieldInformation = [
92  'tcaDescription' => [
93  'renderType' => 'tcaDescription',
94  ],
95  ];
96 
102  protected ‪$defaultFieldWizard = [
103  'localizationStateSelector' => [
104  'renderType' => 'localizationStateSelector',
105  ],
106  'otherLanguageContent' => [
107  'renderType' => 'otherLanguageContent',
108  'after' => [
109  'localizationStateSelector'
110  ],
111  ],
112  'defaultLanguageDifferences' => [
113  'renderType' => 'defaultLanguageDifferences',
114  'after' => [
115  'otherLanguageContent',
116  ],
117  ],
118  ];
119 
123  protected ‪$templateView;
124 
128  protected ‪$uriBuilder;
129 
134  public function ‪__construct(‪NodeFactory ‪$nodeFactory, array ‪$data)
135  {
136  parent::__construct(‪$nodeFactory, ‪$data);
137  // Would be great, if we could inject the view here, but since the constructor is in the interface, we can't
138  $this->templateView = GeneralUtility::makeInstance(StandaloneView::class);
139  $this->templateView->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Layouts/')]);
140  $this->templateView->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials/ImageManipulation/')]);
141  $this->templateView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/ImageManipulation/ImageManipulationElement.html'));
142  $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
143  }
144 
151  public function ‪render()
152  {
153  $resultArray = $this->‪initializeResultArray();
154  $parameterArray = $this->data['parameterArray'];
155  $config = $this->‪populateConfiguration($parameterArray['fieldConf']['config']);
156 
157  $file = $this->‪getFile($this->data['databaseRow'], $config['file_field']);
158  if (!$file) {
159  // Early return in case we do not find a file
160  return $resultArray;
161  }
162 
163  $config = $this->‪processConfiguration($config, $parameterArray['itemFormElValue'], $file);
164 
165  $fieldInformationResult = $this->‪renderFieldInformation();
166  $fieldInformationHtml = $fieldInformationResult['html'];
167  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
168 
169  $fieldControlResult = $this->‪renderFieldControl();
170  $fieldControlHtml = $fieldControlResult['html'];
171  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
172 
173  $fieldWizardResult = $this->‪renderFieldWizard();
174  $fieldWizardHtml = $fieldWizardResult['html'];
175  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
176 
177  $arguments = [
178  'fieldInformation' => $fieldInformationHtml,
179  'fieldControl' => $fieldControlHtml,
180  'fieldWizard' => $fieldWizardHtml,
181  'isAllowedFileExtension' => in_array(strtolower($file->getExtension()), GeneralUtility::trimExplode(',', strtolower($config['allowedExtensions'])), true),
182  'image' => $file,
183  'formEngine' => [
184  'field' => [
185  'value' => $parameterArray['itemFormElValue'],
186  'name' => $parameterArray['itemFormElName']
187  ],
188  'validation' => '[]'
189  ],
190  'config' => $config,
191  'wizardUri' => $this->‪getWizardUri(),
192  'wizardPayload' => json_encode($this->‪getWizardPayload($config['cropVariants'], $file)),
193  'previewUrl' => $this->‪getPreviewUrl($this->data['databaseRow'], $file),
194  ];
195 
196  if ($arguments['isAllowedFileExtension']) {
197  $resultArray['requireJsModules'][] = [
198  'TYPO3/CMS/Backend/ImageManipulation' => 'function (ImageManipulation) {top.require(["cropper"], function() { ImageManipulation.initializeTrigger(); }); }'
199  ];
200  $arguments['formEngine']['field']['id'] = ‪StringUtility::getUniqueId('formengine-image-manipulation-');
201  if (GeneralUtility::inList($config['eval'], 'required')) {
202  $arguments['formEngine']['validation'] = $this->‪getValidationDataAsJsonString(['required' => true]);
203  }
204  }
205  $this->templateView->assignMultiple($arguments);
206  $resultArray['html'] = $this->templateView->render();
207 
208  return $resultArray;
209  }
210 
218  protected function ‪getFile(array $row, $fieldName)
219  {
220  $file = null;
221  $fileUid = !empty($row[$fieldName]) ? $row[$fieldName] : null;
222  if (is_array($fileUid) && isset($fileUid[0]['uid'])) {
223  $fileUid = $fileUid[0]['uid'];
224  }
226  try {
228  } catch (FileDoesNotExistException $e) {
229  } catch (\InvalidArgumentException $e) {
230  }
231  }
232  return $file;
233  }
234 
240  protected function ‪getPreviewUrl(array $databaseRow, ‪File $file): string
241  {
242  $previewUrl = '';
243  // Hook to generate a preview URL
244  $hookParameters = [
245  'databaseRow' => $databaseRow,
246  'file' => $file,
247  'previewUrl' => $previewUrl,
248  ];
249  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Backend/Form/Element/ImageManipulationElement']['previewUrl'] ?? [] as $listener) {
250  $previewUrl = GeneralUtility::callUserFunction($listener, $hookParameters, $this);
251  }
252  return $previewUrl;
253  }
254 
260  protected function ‪populateConfiguration(array $baseConfiguration)
261  {
263 
264  // If ratios are set do not add default options
265  if (isset($baseConfiguration['cropVariants'])) {
266  unset(‪$defaultConfig['cropVariants']);
267  }
268 
269  $config = array_replace_recursive(‪$defaultConfig, $baseConfiguration);
270 
271  if (!is_array($config['cropVariants'])) {
272  throw new ‪InvalidConfigurationException('Crop variants configuration must be an array', 1485377267);
273  }
274 
275  $cropVariants = [];
276  foreach ($config['cropVariants'] as $id => $cropVariant) {
277  // Ignore disabled crop variants
278  if (!empty($cropVariant['disabled'])) {
279  continue;
280  }
281  // Enforce a crop area (default is full image)
282  if (empty($cropVariant['cropArea'])) {
283  $cropVariant['cropArea'] = ‪Area::createEmpty()->‪asArray();
284  }
285  $cropVariants[$id] = $cropVariant;
286  }
287 
288  $config['cropVariants'] = $cropVariants;
289 
290  // By default we allow all image extensions that can be handled by the GFX functionality
291  if ($config['allowedExtensions'] === null) {
292  $config['allowedExtensions'] = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
293  }
294  return $config;
295  }
296 
304  protected function ‪processConfiguration(array $config, string &$elementValue, ‪File $file)
305  {
306  $cropVariantCollection = ‪CropVariantCollection::create($elementValue, $config['cropVariants']);
307  if (empty($config['readOnly']) && !empty($file->‪getProperty('width'))) {
308  $cropVariantCollection = $cropVariantCollection->applyRatioRestrictionToSelectedCropArea($file);
309  $elementValue = (string)$cropVariantCollection;
310  }
311  $config['cropVariants'] = $cropVariantCollection->asArray();
312  $config['allowedExtensions'] = implode(', ', GeneralUtility::trimExplode(',', $config['allowedExtensions'], true));
313  return $config;
314  }
315 
319  protected function ‪getWizardUri(): string
320  {
321  return (string)$this->uriBuilder->buildUriFromRoute($this->wizardRouteName);
322  }
323 
329  protected function ‪getWizardPayload(array $cropVariants, ‪File $image): array
330  {
331  $arguments = [
332  'cropVariants' => $cropVariants,
333  'image' => $image->‪getUid(),
334  ];
335  $uriArguments['arguments'] = json_encode($arguments);
336  $uriArguments['signature'] = GeneralUtility::hmac($uriArguments['arguments'], $this->wizardRouteName);
337 
338  return $uriArguments;
339  }
340 }
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$wizardRouteName
‪string $wizardRouteName
Definition: ImageManipulationElement.php:39
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$templateView
‪StandaloneView $templateView
Definition: ImageManipulationElement.php:118
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:71
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:73
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: ImageManipulationElement.php:88
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\render
‪array render()
Definition: ImageManipulationElement.php:145
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:115
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪array initializeResultArray()
Definition: AbstractNode.php:88
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\getWizardPayload
‪array getWizardPayload(array $cropVariants, File $image)
Definition: ImageManipulationElement.php:323
‪TYPO3\CMS\Core\Imaging\ImageManipulation\Area
Definition: Area.php:21
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\getFile
‪File null getFile(array $row, $fieldName)
Definition: ImageManipulationElement.php:212
‪TYPO3\CMS\Backend\Form\AbstractNode\$nodeFactory
‪NodeFactory $nodeFactory
Definition: AbstractNode.php:34
‪TYPO3\CMS\Core\Resource\ResourceFactory\getInstance
‪static ResourceFactory getInstance()
Definition: ResourceFactory.php:39
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:31
‪TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
Definition: FileDoesNotExistException.php:21
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:2
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\populateConfiguration
‪array populateConfiguration(array $baseConfiguration)
Definition: ImageManipulationElement.php:254
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪string getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:153
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:87
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:35
‪TYPO3\CMS\Backend\Form\AbstractNode\$data
‪array $data
Definition: AbstractNode.php:40
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:33
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:23
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\getPreviewUrl
‪string getPreviewUrl(array $databaseRow, File $file)
Definition: ImageManipulationElement.php:234
‪TYPO3\CMS\Core\Resource\AbstractFile\getUid
‪int getUid()
Definition: AbstractFile.php:200
‪TYPO3\CMS\Core\Imaging\ImageManipulation\InvalidConfigurationException
Definition: InvalidConfigurationException.php:22
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: ImageManipulationElement.php:98
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\__construct
‪__construct(NodeFactory $nodeFactory, array $data)
Definition: ImageManipulationElement.php:128
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\processConfiguration
‪array processConfiguration(array $config, string &$elementValue, File $file)
Definition: ImageManipulationElement.php:298
‪TYPO3\CMS\Backend\Form\NodeFactory
Definition: NodeFactory.php:36
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:91
‪TYPO3\CMS\Fluid\View\StandaloneView
Definition: StandaloneView.php:32
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$uriBuilder
‪UriBuilder $uriBuilder
Definition: ImageManipulationElement.php:122
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Resource\File\getProperty
‪mixed getProperty($key)
Definition: File.php:74
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection
Definition: CropVariantCollection.php:21
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Resource\ResourceFactory\getFileObject
‪File getFileObject($uid, array $fileData=[])
Definition: ResourceFactory.php:399
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Imaging\ImageManipulation\Area\asArray
‪array asArray()
Definition: Area.php:97
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:21
‪TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection\create
‪static CropVariantCollection create(string $jsonString, array $tcaConfig=[])
Definition: CropVariantCollection.php:40
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:103
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement
Definition: ImageManipulationElement.php:36
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\$defaultConfig
‪static array $defaultConfig
Definition: ImageManipulationElement.php:45
‪TYPO3\CMS\Backend\Form\Element\ImageManipulationElement\getWizardUri
‪string getWizardUri()
Definition: ImageManipulationElement.php:313
‪TYPO3\CMS\Core\Imaging\ImageManipulation\Area\createEmpty
‪static Area createEmpty()
Definition: Area.php:88