/**
  * Creates and returns a TypoScript "imgResource".
  * The value ($file) can either be a file reference (TypoScript resource) or the string "GIFBUILDER".
  * In the first case a current image is returned, possibly scaled down or otherwise processed.
  * In the latter case a GIFBUILDER image is returned; This means an image is made by TYPO3 from layers of elements as GIFBUILDER defines.
  * In the function IMG_RESOURCE() this function is called like $this->getImgResource($conf['file'], $conf['file.']);
  *
  * Structure of the returned info array:
  *  0 => width
  *  1 => height
  *  2 => file extension
  *  3 => file name
  *  origFile => original file name
  *  origFile_mtime => original file mtime
  *  -- only available if processed via FAL: --
  *  originalFile => original file object
  *  processedFile => processed file object
  *  fileCacheHash => checksum of processed file
  *
  * @param string|File|FileReference $file A "imgResource" TypoScript data type. Either a TypoScript file resource, a file or a file reference object or the string GIFBUILDER. See description above.
  * @param array $fileArray TypoScript properties for the imgResource type
  * @return array|NULL Returns info-array
  * @see IMG_RESOURCE(), cImage(), \TYPO3\CMS\Frontend\Imaging\GifBuilder
  */
 public function getImgResource($file, $fileArray)
 {
     if (empty($file) && empty($fileArray)) {
         return null;
     }
     if (!is_array($fileArray)) {
         $fileArray = (array) $fileArray;
     }
     $imageResource = null;
     $tsfe = $this->getTypoScriptFrontendController();
     if ($file === 'GIFBUILDER') {
         /** @var GifBuilder $gifCreator */
         $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
         $gifCreator->init();
         $theImage = '';
         if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
             $gifCreator->start($fileArray, $this->data);
             $theImage = $gifCreator->gifBuild();
         }
         $imageResource = $gifCreator->getImageDimensions($theImage);
         $imageResource['origFile'] = $theImage;
     } else {
         if ($file instanceof File) {
             $fileObject = $file;
         } elseif ($file instanceof FileReference) {
             $fileObject = $file->getOriginalFile();
             if (!isset($fileArray['crop'])) {
                 $fileArray['crop'] = $file->getProperty('crop');
             }
         } else {
             try {
                 if ($fileArray['import.']) {
                     $importedFile = trim($this->stdWrap('', $fileArray['import.']));
                     if (!empty($importedFile)) {
                         $file = $importedFile;
                     }
                 }
                 if (MathUtility::canBeInterpretedAsInteger($file)) {
                     $treatIdAsReference = isset($fileArray['treatIdAsReference.']) ? $this->stdWrap($fileArray['treatIdAsReference'], $fileArray['treatIdAsReference.']) : $fileArray['treatIdAsReference'];
                     if (!empty($treatIdAsReference)) {
                         $fileReference = $this->getResourceFactory()->getFileReferenceObject($file);
                         $fileObject = $fileReference->getOriginalFile();
                         if (!isset($fileArray['crop'])) {
                             $fileArray['crop'] = $fileReference->getProperty('crop');
                         }
                     } else {
                         $fileObject = $this->getResourceFactory()->getFileObject($file);
                     }
                 } elseif (preg_match('/^(0|[1-9][0-9]*):/', $file)) {
                     // combined identifier
                     $fileObject = $this->getResourceFactory()->retrieveFileOrFolderObject($file);
                 } else {
                     if (isset($importedFile) && !empty($importedFile) && !empty($fileArray['import'])) {
                         $file = $fileArray['import'] . $file;
                     }
                     $fileObject = $this->getResourceFactory()->retrieveFileOrFolderObject($file);
                 }
             } catch (Exception $exception) {
                 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
                 $logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
                 $logger->warning('The image "' . $file . '" could not be found and won\'t be included in frontend output');
                 return null;
             }
         }
         if ($fileObject instanceof File) {
             $processingConfiguration = array();
             $processingConfiguration['width'] = isset($fileArray['width.']) ? $this->stdWrap($fileArray['width'], $fileArray['width.']) : $fileArray['width'];
             $processingConfiguration['height'] = isset($fileArray['height.']) ? $this->stdWrap($fileArray['height'], $fileArray['height.']) : $fileArray['height'];
             $processingConfiguration['fileExtension'] = isset($fileArray['ext.']) ? $this->stdWrap($fileArray['ext'], $fileArray['ext.']) : $fileArray['ext'];
             $processingConfiguration['maxWidth'] = isset($fileArray['maxW.']) ? (int) $this->stdWrap($fileArray['maxW'], $fileArray['maxW.']) : (int) $fileArray['maxW'];
             $processingConfiguration['maxHeight'] = isset($fileArray['maxH.']) ? (int) $this->stdWrap($fileArray['maxH'], $fileArray['maxH.']) : (int) $fileArray['maxH'];
             $processingConfiguration['minWidth'] = isset($fileArray['minW.']) ? (int) $this->stdWrap($fileArray['minW'], $fileArray['minW.']) : (int) $fileArray['minW'];
             $processingConfiguration['minHeight'] = isset($fileArray['minH.']) ? (int) $this->stdWrap($fileArray['minH'], $fileArray['minH.']) : (int) $fileArray['minH'];
             $processingConfiguration['noScale'] = isset($fileArray['noScale.']) ? $this->stdWrap($fileArray['noScale'], $fileArray['noScale.']) : $fileArray['noScale'];
             $processingConfiguration['additionalParameters'] = isset($fileArray['params.']) ? $this->stdWrap($fileArray['params'], $fileArray['params.']) : $fileArray['params'];
             $processingConfiguration['frame'] = isset($fileArray['frame.']) ? (int) $this->stdWrap($fileArray['frame'], $fileArray['frame.']) : (int) $fileArray['frame'];
             $processingConfiguration['crop'] = isset($fileArray['crop.']) ? $this->stdWrap($fileArray['crop'], $fileArray['crop.']) : (isset($fileArray['crop']) ? $fileArray['crop'] : null);
             // Possibility to cancel/force profile extraction
             // see $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_stripProfileCommand']
             if (isset($fileArray['stripProfile'])) {
                 $processingConfiguration['stripProfile'] = $fileArray['stripProfile'];
             }
             // Check if we can handle this type of file for editing
             if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
                 $maskArray = $fileArray['m.'];
                 // Must render mask images and include in hash-calculating
                 // - otherwise we cannot be sure the filename is unique for the setup!
                 if (is_array($maskArray)) {
                     $mask = $this->getImgResource($maskArray['mask'], $maskArray['mask.']);
                     $bgImg = $this->getImgResource($maskArray['bgImg'], $maskArray['bgImg.']);
                     $bottomImg = $this->getImgResource($maskArray['bottomImg'], $maskArray['bottomImg.']);
                     $bottomImg_mask = $this->getImgResource($maskArray['bottomImg_mask'], $maskArray['bottomImg_mask.']);
                     $processingConfiguration['maskImages']['maskImage'] = $mask['processedFile'];
                     $processingConfiguration['maskImages']['backgroundImage'] = $bgImg['processedFile'];
                     $processingConfiguration['maskImages']['maskBottomImage'] = $bottomImg['processedFile'];
                     $processingConfiguration['maskImages']['maskBottomImageMask'] = $bottomImg_mask['processedFile'];
                 }
                 $processedFileObject = $fileObject->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingConfiguration);
                 $hash = $processedFileObject->calculateChecksum();
                 // store info in the TSFE template cache (kept for backwards compatibility)
                 if ($processedFileObject->isProcessed() && !isset($tsfe->tmpl->fileCache[$hash])) {
                     $tsfe->tmpl->fileCache[$hash] = array(0 => $processedFileObject->getProperty('width'), 1 => $processedFileObject->getProperty('height'), 2 => $processedFileObject->getExtension(), 3 => $processedFileObject->getPublicUrl(), 'origFile' => $fileObject->getPublicUrl(), 'origFile_mtime' => $fileObject->getModificationTime(), 'originalFile' => $fileObject, 'processedFile' => $processedFileObject, 'fileCacheHash' => $hash);
                 }
                 $imageResource = $tsfe->tmpl->fileCache[$hash];
             }
         }
     }
     // If image was processed by GIFBUILDER:
     // ($imageResource indicates that it was processed the regular way)
     if (!isset($imageResource)) {
         $theImage = $tsfe->tmpl->getFileName($file);
         if ($theImage) {
             $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
             /** @var $gifCreator GifBuilder */
             $gifCreator->init();
             $info = $gifCreator->imageMagickConvert($theImage, 'WEB');
             $info['origFile'] = $theImage;
             // This is needed by \TYPO3\CMS\Frontend\Imaging\GifBuilder, ln 100ff in order for the setup-array to create a unique filename hash.
             $info['origFile_mtime'] = @filemtime($theImage);
             $imageResource = $info;
         }
     }
     // Hook 'getImgResource': Post-processing of image resources
     if (isset($imageResource)) {
         /** @var ContentObjectGetImageResourceHookInterface $hookObject */
         foreach ($this->getGetImgResourceHookObjects() as $hookObject) {
             $imageResource = $hookObject->getImgResourcePostProcess($file, (array) $fileArray, $imageResource, $this);
         }
     }
     return $imageResource;
 }