[FEATURE] Add image cropping 77/34277/10
authorFrans Saris <franssaris@gmail.com>
Sun, 16 Nov 2014 20:54:33 +0000 (21:54 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Fri, 13 Mar 2015 11:17:16 +0000 (12:17 +0100)
This patch adds the "infrastructure" for single image cropping:

* Extends LocalCropScaleMaskHelper to support the new crop setting
* Adjusts the ViewHelpers to support the crop setting
* Extends typoscript imgResource to support the crop setting
* Adds a new db field for sys_file_reference to hold the crop settings

The GUI will be added in a follow up #65585

Resolves: #65584
Releases: master
Change-Id: I76c6ccd1f3f38e3a47f830115c7748ea4a6b10cd
Reviewed-on: http://review.typo3.org/34277
Reviewed-by: Mateusz Wojtuła <matw88@gmail.com>
Tested-by: Mateusz Wojtuła <matw88@gmail.com>
Reviewed-by: Frank Nägler <typo3@naegler.net>
Tested-by: Frank Nägler <typo3@naegler.net>
Reviewed-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Tested-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/backend/Classes/Form/Element/InlineElement.php
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/core/Classes/Resource/Processing/LocalCropScaleMaskHelper.php
typo3/sysext/core/Configuration/TCA/sys_file_reference.php
typo3/sysext/core/Documentation/Changelog/master/Feature-65584-AddImageCropping.rst [new file with mode: 0644]
typo3/sysext/core/ext_tables.sql
typo3/sysext/fluid/Classes/ViewHelpers/ImageViewHelper.php
typo3/sysext/fluid/Classes/ViewHelpers/Uri/ImageViewHelper.php
typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
typo3/sysext/lang/locallang_tca.xlf

index cf15b30..bed861a 100644 (file)
@@ -612,6 +612,9 @@ class InlineElement {
                                } elseif($fileObject) {
                                        $imageSetup = $config['appearance']['headerThumbnail'];
                                        unset($imageSetup['field']);
+                                       if (!empty($rec['crop'])) {
+                                               $imageSetup['crop'] = $rec['crop'];
+                                       }
                                        $imageSetup = array_merge(array('width' => '45', 'height' => '45c'), $imageSetup);
                                        $processedImage = $fileObject->process(\TYPO3\CMS\Core\Resource\ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $imageSetup);
                                        // Only use a thumbnail if the processing was successful.
index 7a1c801..7db8d14 100644 (file)
@@ -1624,9 +1624,10 @@ class BackendUtility {
 
                                // Web image
                                if (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileReferenceObject->getExtension())) {
-                                       $imageUrl = $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, array(
+                                       $imageUrl = $fileObject->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, array(
                                                'width' => $sizeParts[0],
-                                               'height' => $sizeParts[1]
+                                               'height' => $sizeParts[1] . 'c',
+                                               'crop' => $fileReferenceObject->getProperty('crop')
                                        ))->getPublicUrl(TRUE);
                                        $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileReferenceObject->getName()) . '" />';
                                } else {
index 8a8226e..f9ea7ab 100644 (file)
@@ -70,6 +70,16 @@ class LocalCropScaleMaskHelper {
 
                $options = $this->getConfigurationForImageCropScaleMask($targetFile, $gifBuilder);
 
+               $croppedImage = NULL;
+               if (!empty($configuration['crop'])) {
+                       $im = $gifBuilder->imageCreateFromFile($originalFileName);
+                       $croppedImage = Utility\GeneralUtility::tempnam('crop_', '.' . $sourceFile->getExtension());
+                       $gifBuilder->crop($im, ['crop' => $configuration['crop']]);
+                       if ($gifBuilder->ImageWrite($im, $croppedImage)) {
+                               $originalFileName = $croppedImage;
+                       }
+               }
+
                // Normal situation (no masking)
                if (!(is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'])) {
                                // the result info is an array with 0=width,1=height,2=extension,3=filename
@@ -144,9 +154,10 @@ class LocalCropScaleMaskHelper {
                                $result = $tempFileInfo;
                        }
                }
-               // check if the processing really generated a new file
+
+               // check if the processing really generated a new file (scaled and/or cropped)
                if ($result !== NULL) {
-                       if ($result[3] !== $originalFileName) {
+                       if ($result[3] !== $originalFileName || $originalFileName === $croppedImage) {
                                $result = array(
                                        'width' => $result[0],
                                        'height' => $result[1],
@@ -158,6 +169,11 @@ class LocalCropScaleMaskHelper {
                        }
                }
 
+               // Cleanup temp file if it isn't used as result
+               if ($croppedImage && ($result === NULL || $croppedImage !== $result['filePath'])) {
+                       Utility\GeneralUtility::unlink_tempfile($croppedImage);
+               }
+
                return $result;
        }
 
index 269ea15..9499f0c 100644 (file)
@@ -217,6 +217,16 @@ return array(
                                'default' => NULL,
                        ),
                ),
+               'crop' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.crop',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => '10',
+                               'max' => '30',
+                               'placeholder' => 'x,y,w,h',
+                       )
+               )
        ),
        'types' => array(
                // Note that at the moment we define the same fields for every media type.
@@ -262,7 +272,7 @@ return array(
                'imageoverlayPalette' => array(
                        'showitem' => '
                                title,alternative,--linebreak--,
-                               link,description
+                               link,description,--linebreak--,crop
                                ',
                        'canNotCollapse' => TRUE
                ),
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-65584-AddImageCropping.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-65584-AddImageCropping.rst
new file mode 100644 (file)
index 0000000..e8561b3
--- /dev/null
@@ -0,0 +1,47 @@
+====================================
+Feature: #65584 - Add image cropping
+====================================
+
+Description
+===========
+
+A new functionality is introduced that allows the editor to define image cropping settings to a *sys_file_reference*.
+
+The current support crop setting is a comma separated string defining: offsetX,offsetY,width,height
+
+
+Impact
+======
+
+The value set for a *sys_file_reference* will by default be passed through to the image rendering of TYPO3.
+The new option of *sys_file_reference* is defined as exclude field in TCA so it needs to be enabled for editors.
+
+
+Disable cropping of image when used with *typoscript* rendering:
+
+.. code-block:: typoscript
+
+       # Disable cropping for all images
+       tt_content.image.20.1.file.crop =
+
+Set custom cropping setting for when used with *typoscript* rendering:
+
+.. code-block:: typoscript
+
+       # Overrule/set cropping for all images
+       tt_content.image.20.1.file.crop = 50,50,100,100
+
+
+Disable cropping of image when used in *fluid*:
+
+.. code-block:: html
+
+       <f:image image="{imageObject}" crop="" />
+
+Set custom cropping setting for image when used in *fluid*:
+
+.. code-block:: html
+
+       <f:image image="{imageObject}" crop="50,50,100,100" />
+
+
index f05f5e2..7e714dd 100644 (file)
@@ -412,6 +412,7 @@ CREATE TABLE sys_file_reference (
        alternative tinytext,
        link varchar(1024) DEFAULT '' NOT NULL,
        downloadname tinytext,
+       crop varchar(64) DEFAULT '' NOT NULL,
 
        PRIMARY KEY (uid),
        KEY parent (pid,deleted),
index 3d79a27..571573c 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Fluid\ViewHelpers;
  *                                                                        */
 
 use TYPO3\CMS\Core\Resource\FileInterface;
+use TYPO3\CMS\Core\Resource\FileReference;
 use TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder;
 
 /**
@@ -92,15 +93,19 @@ class ImageViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedV
         * @param int $maxHeight maximum height of the image
         * @param bool $treatIdAsReference given src argument is a sys_file_reference record
         * @param FileInterface|AbstractFileFolder $image a FAL object
+        * @param string|bool $crop overrule cropping of image (setting to FALSE disables the cropping set in FileReference)
         *
         * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
         * @return string Rendered tag
         */
-       public function render($src = NULL, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL, $treatIdAsReference = FALSE, $image = NULL) {
+       public function render($src = NULL, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL, $treatIdAsReference = FALSE, $image = NULL, $crop = NULL) {
                if (is_null($src) && is_null($image) || !is_null($src) && !is_null($image)) {
                        throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('You must either specify a string src or a File object.', 1382284106);
                }
                $image = $this->imageService->getImage($src, $image, $treatIdAsReference);
+               if ($crop === NULL) {
+                       $crop = $image instanceof FileReference ? $image->getProperty('crop') : NULL;
+               }
                $processingInstructions = array(
                        'width' => $width,
                        'height' => $height,
@@ -108,6 +113,7 @@ class ImageViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedV
                        'minHeight' => $minHeight,
                        'maxWidth' => $maxWidth,
                        'maxHeight' => $maxHeight,
+                       'crop' => $crop,
                );
                $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
                $imageUri = $this->imageService->getImageUri($processedImage);
index e18e22c..44a72f5 100644 (file)
@@ -75,13 +75,17 @@ class ImageViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelpe
         * @param int $maxWidth maximum width of the image
         * @param int $maxHeight maximum height of the image
         * @param bool $treatIdAsReference given src argument is a sys_file_reference record
+        * @param string|bool $crop overrule cropping of image (setting to FALSE disables the cropping set in FileReference)
         * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
         * @return string path to the image
         */
-       public function render($src = NULL, $image = NULL, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL, $treatIdAsReference = FALSE) {
+       public function render($src = NULL, $image = NULL, $width = NULL, $height = NULL, $minWidth = NULL, $minHeight = NULL, $maxWidth = NULL, $maxHeight = NULL, $treatIdAsReference = FALSE, $crop = NULL) {
                if (is_null($src) && is_null($image) || !is_null($src) && !is_null($image)) {
                        throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('You must either specify a string src or a File object.', 1382284105);
                }
+               if ($crop === NULL) {
+                       $crop = $image instanceof FileReference ? $image->getProperty('crop') : NULL;
+               }
                $image = $this->imageService->getImage($src, $image, $treatIdAsReference);
                $processingInstructions = array(
                        'width' => $width,
@@ -90,6 +94,7 @@ class ImageViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelpe
                        'minHeight' => $minHeight,
                        'maxWidth' => $maxWidth,
                        'maxHeight' => $maxHeight,
+                       'crop' => $crop,
                );
                $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);
                return $this->imageService->getImageUri($processedImage);
index 1279d86..be39616 100644 (file)
@@ -5418,6 +5418,9 @@ class ContentObjectRenderer {
                                $fileObject = $file;
                        } elseif ($file instanceof FileReference) {
                                $fileObject = $file->getOriginalFile();
+                               if (!isset($fileArray['crop'])) {
+                                       $fileArray['crop'] = $file->getProperty('crop');
+                               }
                        } else {
                                try {
                                        if ($fileArray['import.']) {
@@ -5429,7 +5432,11 @@ class ContentObjectRenderer {
 
                                        if (MathUtility::canBeInterpretedAsInteger($file)) {
                                                if (!empty($fileArray['treatIdAsReference'])) {
-                                                       $fileObject = $this->getResourceFactory()->getFileReferenceObject($file)->getOriginalFile();
+                                                       $fileReference = $this->getResourceFactory()->getFileReferenceObject($file);
+                                                       $fileObject = $fileReference->getOriginalFile();
+                                                       if (!isset($fileArray['crop'])) {
+                                                               $fileArray['crop'] = $fileReference->getProperty('crop');
+                                                       }
                                                } else {
                                                        $fileObject = $this->getResourceFactory()->getFileObject($file);
                                                }
@@ -5462,6 +5469,7 @@ class ContentObjectRenderer {
                                $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'])) {
index 2c03d6d..60ea110 100644 (file)
                        <trans-unit id="sys_file_reference.link" xml:space="preserve">
                                <source>Link</source>
                        </trans-unit>
+                       <trans-unit id="sys_file_reference.crop" xml:space="preserve">
+                               <source>Crop image</source>
+                       </trans-unit>
                        <trans-unit id="sys_file_collection" xml:space="preserve">
                                <source>File collection</source>
                        </trans-unit>