TYPO3  7.6
ImageManipulationElement.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Element;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
25 
30 {
36  protected $defaultConfig = array(
37  'file_field' => 'uid_local',
38  'enableZoom' => false,
39  'allowedExtensions' => null, // default: $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
40  'ratios' => array(
41  '1.7777777777777777' => 'LLL:EXT:lang/locallang_wizards.xlf:imwizard.ratio.16_9',
42  '1.3333333333333333' => 'LLL:EXT:lang/locallang_wizards.xlf:imwizard.ratio.4_3',
43  '1' => 'LLL:EXT:lang/locallang_wizards.xlf:imwizard.ratio.1_1',
44  'NaN' => 'LLL:EXT:lang/locallang_wizards.xlf:imwizard.ratio.free',
45  )
46  );
47 
53  public function render()
54  {
55  $resultArray = $this->initializeResultArray();
56  $languageService = $this->getLanguageService();
57 
58  $row = $this->data['databaseRow'];
59  $parameterArray = $this->data['parameterArray'];
60 
61  // If ratios are set do not add default options
62  if (isset($parameterArray['fieldConf']['config']['ratios'])) {
63  unset($this->defaultConfig['ratios']);
64  }
65  $config = ArrayUtility::arrayMergeRecursiveOverrule($this->defaultConfig, $parameterArray['fieldConf']['config']);
66 
67  // By default we allow all image extensions that can be handled by the GFX functionality
68  if ($config['allowedExtensions'] === null) {
69  $config['allowedExtensions'] = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
70  }
71 
72  if ($config['readOnly']) {
73  $options = array();
74  $options['parameterArray'] = array(
75  'fieldConf' => array(
76  'config' => $config,
77  ),
78  'itemFormElValue' => $parameterArray['itemFormElValue'],
79  );
80  $options['renderType'] = 'none';
81  return $this->nodeFactory->create($options)->render();
82  }
83 
84  $file = $this->getFile($row, $config['file_field']);
85  if (!$file) {
86  return $resultArray;
87  }
88 
89  $content = '';
90  $preview = '';
91  if (GeneralUtility::inList(mb_strtolower($config['allowedExtensions']), mb_strtolower($file->getExtension()))) {
92 
93  // Get preview
94  $preview = $this->getPreview($file, $parameterArray['itemFormElValue']);
95 
96  // Check if ratio labels hold translation strings
97  foreach ((array)$config['ratios'] as $ratio => $label) {
98  $config['ratios'][$ratio] = $languageService->sL($label, true);
99  }
100 
101  $formFieldId = StringUtility::getUniqueId('formengine-image-manipulation-');
102  $wizardData = array(
103  'zoom' => $config['enableZoom'] ? '1' : '0',
104  'ratios' => json_encode($config['ratios']),
105  'file' => $file->getUid(),
106  );
107  $wizardData['token'] = GeneralUtility::hmac(implode('|', $wizardData), 'ImageManipulationWizard');
108 
109  $buttonAttributes = array(
110  'data-url' => BackendUtility::getAjaxUrl('wizard_image_manipulation', $wizardData),
111  'data-severity' => 'notice',
112  'data-image-name' => $file->getNameWithoutExtension(),
113  'data-image-uid' => $file->getUid(),
114  'data-file-field' => $config['file_field'],
115  'data-field' => $formFieldId,
116  );
117 
118  $button = '<button class="btn btn-default t3js-image-manipulation-trigger"';
119  foreach ($buttonAttributes as $key => $value) {
120  $button .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
121  }
122  $button .= '><span class="t3-icon fa fa-crop"></span>';
123  $button .= $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.open-editor', true);
124  $button .= '</button>';
125 
126  $inputField = '<input type="hidden" '
127  . 'id="' . $formFieldId . '" '
128  . 'name="' . $parameterArray['itemFormElName'] . '" '
129  . 'value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
130 
131  $content .= $inputField . $button;
132 
133  $content .= $this->getImageManipulationInfoTable($parameterArray['itemFormElValue']);
134 
135  $resultArray['requireJsModules'][] = array(
136  'TYPO3/CMS/Backend/ImageManipulation' => 'function(ImageManipulation){ImageManipulation.initializeTrigger()}'
137  );
138  }
139 
140  $content .= '<p class="text-muted"><em>' . $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.supported-types-message', true) . '<br />';
141  $content .= mb_strtoupper(implode(', ', GeneralUtility::trimExplode(',', $config['allowedExtensions'])));
142  $content .= '</em></p>';
143 
144  $item = '<div class="media">';
145  $item .= $preview;
146  $item .= '<div class="media-body">' . $content . '</div>';
147  $item .= '</div>';
148 
149  $resultArray['html'] = $item;
150  return $resultArray;
151  }
152 
160  protected function getFile(array $row, $fieldName)
161  {
162  $file = null;
163  $fileUid = !empty($row[$fieldName]) ? $row[$fieldName] : null;
164  if (strpos($fileUid, 'sys_file_') === 0) {
165  if (strpos($fileUid, '|')) {
166  // @todo: uid_local is a group field that was resolved to table_uid|target - split here again
167  // @todo: this will vanish if group fields are moved to array
168  $fileUid = explode('|', $fileUid);
169  $fileUid = $fileUid[0];
170  }
171  $fileUid = substr($fileUid, 9);
172  }
174  try {
175  $file = ResourceFactory::getInstance()->getFileObject($fileUid);
176  } catch (FileDoesNotExistException $e) {
177  } catch (\InvalidArgumentException $e) {
178  }
179  }
180  return $file;
181  }
182 
190  public function getPreview(File $file, $crop)
191  {
192  $thumbnail = '';
193  $maxWidth = 150;
194  $maxHeight = 200;
195  if ($crop) {
196  $imageSetup = array('maxWidth' => $maxWidth, 'maxHeight' => $maxHeight, 'crop' => $crop);
197  $processedImage = $file->process(\TYPO3\CMS\Core\Resource\ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $imageSetup);
198  // Only use a thumbnail if the processing process was successful by checking if image width is set
199  if ($processedImage->getProperty('width')) {
200  $imageUrl = $processedImage->getPublicUrl(true);
201  $thumbnail = '<img src="' . $imageUrl . '" ' .
202  'class="thumbnail thumbnail-status" ' .
203  'width="' . $processedImage->getProperty('width') . '" ' .
204  'height="' . $processedImage->getProperty('height') . '" >';
205  }
206  }
207 
208  $preview = '<div class="media-left">';
209  $preview .= '<div class="t3js-image-manipulation-preview media-object' . ($thumbnail ? '' : ' hide') . '" ';
210  // Set preview width/height needed by cropper
211  $preview .= 'data-preview-width="' . $maxWidth . '" data-preview-height="' . $maxHeight . '">';
212  $preview .= $thumbnail;
213  $preview .= '</div></div>';
214 
215  return $preview;
216  }
217 
224  protected function getImageManipulationInfoTable($rawImageManipulationValue)
225  {
226  $content = '';
227  $imageManipulation = null;
228  $x = $y = $width = $height = 0;
229 
230  // Determine cropping values
231  if ($rawImageManipulationValue) {
232  $imageManipulation = json_decode($rawImageManipulationValue);
233  if (is_object($imageManipulation)) {
234  $x = (int)$imageManipulation->x;
235  $y = (int)$imageManipulation->y;
236  $width = (int)$imageManipulation->width;
237  $height = (int)$imageManipulation->height;
238  } else {
239  $imageManipulation = null;
240  }
241  }
242  $languageService = $this->getLanguageService();
243 
244  $content .= '<div class="table-fit-block table-spacer-wrap">';
245  $content .= '<table class="table table-no-borders t3js-image-manipulation-info' . ($imageManipulation === null ? ' hide' : '') . '">';
246  $content .= '<tr><td>' . $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.crop-x', true) . '</td>';
247  $content .= '<td class="t3js-image-manipulation-info-crop-x">' . $x . 'px</td></tr>';
248  $content .= '<tr><td>' . $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.crop-y', true) . '</td>';
249  $content .= '<td class="t3js-image-manipulation-info-crop-y">' . $y . 'px</td></tr>';
250  $content .= '<tr><td>' . $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.crop-width', true) . '</td>';
251  $content .= '<td class="t3js-image-manipulation-info-crop-width">' . $width . 'px</td></tr>';
252  $content .= '<tr><td>' . $languageService->sL('LLL:EXT:lang/locallang_wizards.xlf:imwizard.crop-height', true) . '</td>';
253  $content .= '<td class="t3js-image-manipulation-info-crop-height">' . $height . 'px</td></tr>';
254  $content .= '</table>';
255  $content .= '</div>';
256 
257  return $content;
258  }
259 }