diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst
new file mode 100644
index 0000000000000000000000000000000000000000..22db04de86a16aa06eabf7848caafadc8e50e04a
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-67663-IntroduceDataProcessorForMediaGalleries.rst
@@ -0,0 +1,64 @@
+=============================================================
+Feature: #67663 - Introduce DataProcessor for media galleries
+=============================================================
+
+Description
+===========
+
+The logic for working with galleries and calculating the maximum asset size is done in a separate GalleryProcessor.
+The GalleryProcessor uses the files already present in the processedData array for his calculations. The FilesProcessor can be used to fetch the files.
+
+.. code-block:: typoscript
+
+	tt_content.text_media.20 = FLUIDTEMPLATE
+	tt_content.image.20 {
+		file = EXT:myextension/Resources/Private/Templates/ContentObjects/Image.html
+
+		dataProcessing {
+
+			# Process files
+			10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
+
+			# Calculate gallery info
+			20 = TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor
+			20 {
+
+				# filesProcessedDataKey :: Key in processedData array that holds the files (default: files) + stdWrap
+				filesProcessedDataKey = files
+
+				# mediaOrientation :: Media orientation, see: TCA[tt_content][column][imageorient] (default: data.imageorient) + stdWrap
+				mediaOrientation.field = imageorient
+
+				# numberOfColumns :: Number of columns (default: data.imagecols) + stdWrap
+				numberOfColumns.field = imagecols
+
+				# equalMediaHeight :: Equal media height in pixels (default: data.imageheight) + stdWrap
+				equalMediaHeight.field = imageheight
+
+				# equalMediaWidth :: Equal media width in pixels (default: data.imagewidth) + stdWrap
+				equalMediaWidth.field = imagewidth
+
+				# maxGalleryWidth :: Max gallery width in pixels (default: 600) + stdWrap
+				maxGalleryWidth = 1000
+
+				# maxGalleryWidthInText :: Max gallery width in pixels when orientation intext (default: 300) + stdWrap
+				maxGalleryWidthInText = 1000
+
+				# columnSpacing :: Column spacing width in pixels (default: 0) + stdWrap
+				columnSpacing = 0
+
+				# borderEnabled :: Border enabled (default: data.imageborder) + stdWrap
+				borderEnabled.field = imageborder
+
+				# borderWidth :: Border width in pixels (default: 0) + stdWrap
+				borderWidth = 0
+
+				# borderPadding :: Border padding in pixels  (default: 0) + stdWrap
+				borderPadding = 10
+
+				# as :: Name of key in processedData array where result is placed (default: gallery) + stdWrap
+				as = gallery
+			}
+		}
+
+	}
\ No newline at end of file
diff --git a/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php b/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..5c4765f52abda31998defa26903575f3c6ce1923
--- /dev/null
+++ b/typo3/sysext/frontend/Classes/DataProcessing/GalleryProcessor.php
@@ -0,0 +1,492 @@
+<?php
+namespace TYPO3\CMS\Frontend\DataProcessing;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
+use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
+use TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException;
+
+/**
+ * This data processor will calculate rows, columns and dimensions for a gallery
+ * based on several settings and can be used for f.i. the CType "textmedia"
+ *
+ * The output will be an array which contains the rows and columns,
+ * including the file references and the calculated width and height for each media element,
+ * but also some more information of the gallery, like position, width and counters
+ *
+ * Example TypoScript configuration:
+ *
+ * 10 = TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor
+ * 10 {
+ *   filesProcessedDataKey = files
+ *   mediaOrientation.field = imageorient
+ *   numberOfColumns.field = imagecols
+ *   equalMediaHeight.field = imageheight
+ *   equalMediaWidth.field = imagewidth
+ *   columnSpacing = 0
+ *   borderEnabled.field = imageborder
+ *   borderPadding = 0
+ *   borderWidth = 0
+ *   maxGalleryWidth = {$styles.content.imgtext.maxW}
+ *   maxGalleryWidthInText = {$styles.content.imgtext.maxWInText}
+ *   as = gallery
+ * }
+ *
+ * Output example:
+ *
+ * gallery {
+ *   position {
+ *     horizontal = center
+ *     vertical = above
+ *     noWrap = FALSE
+ *   }
+ *   width = 600
+ *   count {
+ *     files = 2
+ *     columns = 1
+ *     rows = 2
+ *   }
+ *   rows {
+ *     1 {
+ *       columns {
+ *         1 {
+ *           media = TYPO3\CMS\Core\Resource\FileReference
+ *           dimensions {
+ *             width = 600
+ *             height = 400
+ *           }
+ *         }
+ *       }
+ *     }
+ *     2 {
+ *       columns {
+ *         1 {
+ *           media = TYPO3\CMS\Core\Resource\FileReference
+ *           dimensions {
+ *             width = 600
+ *             height = 400
+ *           }
+ *         }
+ *       }
+ *     }
+ *   }
+ *   columnSpacing = 0
+ *   border {
+ *     enabled = FALSE
+ *     width = 0
+ *     padding = 0
+ *   }
+ * }
+ *
+ */
+class GalleryProcessor implements DataProcessorInterface {
+
+	/**
+	 * The content object renderer
+	 *
+	 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
+	 */
+	protected $contentObjectRenderer;
+
+	/**
+	 * The processor configuration
+	 *
+	 * @var array
+	 */
+	protected $processorConfiguration;
+
+	/**
+	 * Matching the tt_content field towards the imageOrient option
+	 *
+	 * @var array
+	 */
+	protected $availableGalleryPositions = [
+		'horizontal' => [
+			'center' => [0, 8],
+			'right' => [1, 9, 17, 25],
+			'left' => [2, 10, 18, 26]
+		],
+		'vertical' => [
+			'above' => [0, 1, 2],
+			'intext' => [17, 18, 25, 26],
+			'below' => [8, 9, 10]
+		]
+	];
+
+	/**
+	 * Storage for processed data
+	 *
+	 * @var array
+	 */
+	protected $galleryData = [
+		'position' => [
+			'horizontal' => '',
+			'vertical' => '',
+			'noWrap' => FALSE
+		],
+		'width' => 0,
+		'count' => [
+			'files' => 0,
+			'columns' => 0,
+			'rows' => 0,
+		],
+		'columnSpacing' => 0,
+		'border' => [
+			'enabled' => FALSE,
+			'width' => 0,
+			'padding' => 0,
+		],
+		'rows' => []
+	];
+
+	/**
+	 * @var int
+	 */
+	protected $numberOfColumns;
+
+	/**
+	 * @var int
+	 */
+	protected $mediaOrientation;
+
+	/**
+	 * @var int
+	 */
+	protected $maxGalleryWidth;
+
+	/**
+	 * @var int
+	 */
+	protected $maxGalleryWidthInText;
+
+	/**
+	 * @var int
+	 */
+	protected $equalMediaHeight;
+
+	/**
+	 * @var int
+	 */
+	protected $equalMediaWidth;
+
+	/**
+	 * @var int
+	 */
+	protected $columnSpacing;
+
+	/**
+	 * @var bool
+	 */
+	protected $borderEnabled;
+
+	/**
+	 * @var int
+	 */
+	protected $borderWidth;
+
+	/**
+	 * @var int
+	 */
+	protected $borderPadding;
+
+	/**
+	 * The (filtered) media files to be used in the gallery
+	 *
+	 * @var fileObjects[]
+	 */
+	protected $fileObjects = [];
+
+	/**
+	 * The calculated dimensions for each media element
+	 *
+	 * @var array
+	 */
+	protected $mediaDimensions = [];
+
+	/**
+	 * Process data for a gallery, for instance the CType "textmedia"
+	 *
+	 * @param ContentObjectRenderer $cObj The content object renderer, which contains data of the content element
+	 * @param array $contentObjectConfiguration The configuration of Content Object
+	 * @param array $processorConfiguration The configuration of this processor
+	 * @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
+	 * @return array the processed data as key/value store
+	 * @throws ContentRenderingException
+	 */
+	public function process(
+		ContentObjectRenderer $cObj,
+		array $contentObjectConfiguration,
+		array $processorConfiguration,
+		array $processedData
+	) {
+		if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
+			return $processedData;
+		}
+
+		$this->contentObjectRenderer = $cObj;
+		$this->processorConfiguration = $processorConfiguration;
+
+		$filesProcessedDataKey = (string)$cObj->stdWrapValue(
+			'filesProcessedDataKey',
+			$processorConfiguration,
+			'files'
+		);
+		if (isset($processedData[$filesProcessedDataKey]) && is_array($processedData[$filesProcessedDataKey])) {
+			$this->fileObjects = $processedData[$filesProcessedDataKey];
+			$this->galleryData['count']['files'] = count($this->fileObjects);
+		} else {
+			throw new ContentRenderingException('No files found for key ' . $filesProcessedDataKey . ' in $processedData.', 1436809789);
+		}
+
+		$this->numberOfColumns = (int)$this->getConfigurationValue('numberOfColumns', 'imagecols');
+		$this->mediaOrientation = (int)$this->getConfigurationValue('mediaOrientation', 'imageorient');
+		$this->maxGalleryWidth = (int)$this->getConfigurationValue('maxGalleryWidth') ?: 600;
+		$this->maxGalleryWidthInText = (int)$this->getConfigurationValue('maxGalleryWidthInText') ?: 300;
+		$this->equalMediaHeight = (int)$this->getConfigurationValue('equalMediaHeight', 'imageheight');
+		$this->equalMediaWidth = (int)$this->getConfigurationValue('equalMediaWidth', 'imagewidth');
+		$this->columnSpacing = (int)$this->getConfigurationValue('columnSpacing');
+		$this->borderEnabled = (bool)$this->getConfigurationValue('borderEnabled', 'imageborder');
+		$this->borderWidth = (int)$this->getConfigurationValue('borderWidth');
+		$this->borderPadding = (int)$this->getConfigurationValue('borderPadding');
+
+		$this->determineGalleryPosition();
+		$this->determineMaximumGalleryWidth();
+
+		$this->calculateRowsAndColumns();
+		$this->calculateMediaWidthsAndHeights();
+
+		$this->prepareGalleryData();
+
+		$targetFieldName = (string)$cObj->stdWrapValue(
+			'as',
+			$processorConfiguration,
+			'gallery'
+		);
+
+		$processedData[$targetFieldName] = $this->galleryData;
+
+		return $processedData;
+	}
+
+	/**
+	 * Get configuration value from processorConfiguration
+	 * with when $dataArrayKey fallback to value from cObj->data array
+	 *
+	 * @param string $key
+	 * @param string|NULL $dataArrayKey
+	 * @return string
+	 */
+	protected function getConfigurationValue($key, $dataArrayKey = NULL) {
+		$defaultValue = '';
+		if ($dataArrayKey && isset($this->contentObjectRenderer->data[$dataArrayKey])) {
+			$defaultValue = $this->contentObjectRenderer->data[$dataArrayKey];
+		}
+		return $this->contentObjectRenderer->stdWrapValue(
+			$key,
+			$this->processorConfiguration,
+			$defaultValue
+		);
+	}
+
+	/**
+	 * Define the gallery position
+	 *
+	 * Gallery has a horizontal and a vertical position towards the text
+	 * and a possible wrapping of the text around the gallery.
+	 *
+	 * @return void
+	 */
+	protected function determineGalleryPosition() {
+		foreach ($this->availableGalleryPositions as $positionDirectionKey => $positionDirectionValue) {
+			foreach ($positionDirectionValue as $positionKey => $positionArray) {
+				if (in_array($this->mediaOrientation, $positionArray, TRUE)) {
+					$this->galleryData['position'][$positionDirectionKey] = $positionKey;
+				}
+			}
+		}
+
+		if ($this->mediaOrientation === 25 || $this->mediaOrientation === 26) {
+			$this->galleryData['position']['noWrap'] = TRUE;
+		}
+	}
+
+	/**
+	 * Get the gallery width based on vertical position
+	 *
+	 * @return void
+	 */
+	protected function determineMaximumGalleryWidth() {
+		if ($this->galleryData['position']['vertical'] === 'intext') {
+			$this->galleryData['width'] = $this->maxGalleryWidthInText;
+		} else {
+			$this->galleryData['width'] = $this->maxGalleryWidth;
+		}
+	}
+
+	/**
+	 * Calculate the amount of rows and columns
+	 *
+	 * @return void
+	 */
+	protected function calculateRowsAndColumns() {
+
+		// If no columns defined, set it to 1
+		$columns = max((int)$this->numberOfColumns, 1);
+
+		// When more columns than media elements, set the columns to the amount of media elements
+		if ($columns > $this->galleryData['count']['files']) {
+			$columns = $this->galleryData['count']['files'];
+		}
+
+		if ($columns === 0) {
+			$columns = 1;
+		}
+
+		// Calculate the rows from the amount of files and the columns
+		$rows = ceil($this->galleryData['count']['files'] / $columns);
+
+		$this->galleryData['count']['columns'] = $columns;
+		$this->galleryData['count']['rows'] = (int)$rows;
+	}
+
+	/**
+	 * Calculate the width/height of the media elements
+	 *
+	 * Based on the width of the gallery, defined equal width or height by a user, the spacing between columns and
+	 * the use of a border, defined by user, where the border width and padding are taken into account
+	 *
+	 * File objects MUST already be filtered. They need a height and width to be shown in the gallery
+	 *
+	 * @return void
+	 */
+	protected function calculateMediaWidthsAndHeights() {
+
+		$columnSpacingTotal = ($this->galleryData['count']['columns'] - 1) * $this->columnSpacing;
+
+		$galleryWidthMinusBorderAndSpacing = max($this->galleryData['width'] - $columnSpacingTotal, 1);
+
+		if ($this->borderEnabled) {
+			$borderPaddingTotal = ($this->galleryData['count']['columns'] * 2) * $this->borderPadding;
+			$borderWidthTotal = ($this->galleryData['count']['columns'] * 2) * $this->borderWidth;
+			$galleryWidthMinusBorderAndSpacing = $galleryWidthMinusBorderAndSpacing - $borderPaddingTotal - $borderWidthTotal;
+		}
+
+		// User entered a predefined height
+		if ($this->equalMediaHeight) {
+			$mediaScalingCorrection = 1;
+			$maximumRowWidth = 0;
+
+			// Calculate the scaling correction when the total of media elements is wider than the gallery width
+			for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) {
+				$totalRowWidth = 0;
+				for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) {
+					$fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1;
+					if ($fileKey > $this->galleryData['count']['files'] - 1) {
+						break 2;
+					}
+					$currentMediaScaling = $this->equalMediaHeight / max($this->fileObjects[$fileKey]->getProperty('height'), 1);
+					$totalRowWidth += $this->fileObjects[$fileKey]->getProperty('width') * $currentMediaScaling;
+				}
+				$maximumRowWidth = max($totalRowWidth, $maximumRowWidth);
+				$mediaInRowScaling = $totalRowWidth / $galleryWidthMinusBorderAndSpacing;
+				$mediaScalingCorrection = max($mediaInRowScaling, $mediaScalingCorrection);
+			}
+
+			// Set the corrected dimensions for each media element
+			foreach ($this->fileObjects as $key => $fileObject) {
+				$mediaHeight = floor($this->equalMediaHeight / $mediaScalingCorrection);
+				$mediaWidth = floor(
+					$fileObject->getProperty('width') * ($mediaHeight / max($fileObject->getProperty('height'), 1))
+				);
+				$this->mediaDimensions[$key] = [
+					'width' => $mediaWidth,
+					'height' => $mediaHeight
+				];
+			}
+
+			// Recalculate gallery width
+			$this->galleryData['width'] = floor($maximumRowWidth / $mediaScalingCorrection);
+
+		// User entered a predefined width
+		} elseif ($this->equalMediaWidth) {
+			$mediaScalingCorrection = 1;
+
+			// Calculate the scaling correction when the total of media elements is wider than the gallery width
+			$totalRowWidth = $this->galleryData['count']['columns'] * $this->equalMediaWidth;
+			$mediaInRowScaling = $totalRowWidth / $galleryWidthMinusBorderAndSpacing;
+			$mediaScalingCorrection = max($mediaInRowScaling, $mediaScalingCorrection);
+
+			// Set the corrected dimensions for each media element
+			foreach ($this->fileObjects as $key => $fileObject) {
+				$mediaWidth = floor($this->equalMediaWidth / $mediaScalingCorrection);
+				$mediaHeight = floor(
+					$fileObject->getProperty('height') * ($mediaWidth / max($fileObject->getProperty('width'), 1))
+				);
+				$this->mediaDimensions[$key] = [
+					'width' => $mediaWidth,
+					'height' => $mediaHeight
+				];
+			}
+
+			// Recalculate gallery width
+			$this->galleryData['width'] = floor($totalRowWidth / $mediaScalingCorrection);
+
+		// Automatic setting of width and height
+		} else {
+			$maxMediaWidth = (int)($galleryWidthMinusBorderAndSpacing / $this->galleryData['count']['columns']);
+
+			foreach ($this->fileObjects as $key => $fileObject) {
+				$mediaWidth = min($maxMediaWidth, $fileObject->getProperty('width'));
+				$mediaHeight = floor(
+					$fileObject->getProperty('height') * ($mediaWidth / max($fileObject->getProperty('width'), 1))
+				);
+				$this->mediaDimensions[$key] = [
+					'width' => $mediaWidth,
+					'height' => $mediaHeight
+				];
+			}
+		}
+	}
+
+	/**
+	 * Prepare the gallery data
+	 *
+	 * Make an array for rows, columns and configuration
+	 *
+	 * @return void
+	 */
+	protected function prepareGalleryData() {
+		for ($row = 1; $row <= $this->galleryData['count']['rows']; $row++) {
+
+			for ($column = 1; $column <= $this->galleryData['count']['columns']; $column++) {
+
+				$fileKey = (($row - 1) * $this->galleryData['count']['columns']) + $column - 1;
+
+				$this->galleryData['rows'][$row]['columns'][$column] = [
+					'media' => $this->fileObjects[$fileKey],
+					'dimensions' => [
+						'width' => $this->mediaDimensions[$fileKey]['width'],
+						'height' => $this->mediaDimensions[$fileKey]['height']
+					]
+				];
+			}
+		}
+
+		$this->galleryData['columnSpacing'] = $this->columnSpacing;
+		$this->galleryData['border']['enabled'] = $this->borderEnabled;
+		$this->galleryData['border']['width'] = $this->borderWidth;
+		$this->galleryData['border']['padding'] = $this->borderPadding;
+	}
+}
diff --git a/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php b/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8d0184b818e96a6014f403f3a53fcf13ed2db585
--- /dev/null
+++ b/typo3/sysext/frontend/Tests/Unit/Processor/GalleryProcessorTest.php
@@ -0,0 +1,460 @@
+<?php
+namespace TYPO3\CMS\Frontend\Tests\Unit\Processor;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+use TYPO3\CMS\Core\Resource\FileReference;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
+use TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor;
+
+/**
+ * Tests for  GalleryProcessor
+ */
+class GalleryProcessorTest extends UnitTestCase {
+
+	/**
+	 * @var ContentObjectRenderer|\PHPUnit_Framework_MockObject_MockObject
+	 */
+	protected $contentObjectRenderer;
+
+	/**
+	 * Set up
+	 */
+	protected function setUp() {
+		$this->contentObjectRenderer = $this->getMock(
+			ContentObjectRenderer::class,
+			['dummy']
+		);
+	}
+
+	/**
+	 * @test
+	 * @expectedException \TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException
+	 */
+	public function processThrowsExceptionWhenFilesProcessedDataKeyIsNotFound() {
+		$processor = new GalleryProcessor();
+		$processor->process(
+			$this->contentObjectRenderer,
+			[],
+			[],
+			[]
+		);
+	}
+
+	/**
+	 * Gallery position test data provider
+	 */
+	public function galleryPositionDataProvider() {
+		return [
+			'Default: horizontal above' => [
+				[],
+				[
+					'horizontal' => 'center',
+					'vertical' => 'above',
+					'noWrap' => FALSE
+				]
+			],
+			'right above' => [
+				['mediaOrientation' => 1],
+				[
+					'horizontal' => 'right',
+					'vertical' => 'above',
+					'noWrap' => FALSE
+				]
+			],
+			'left above' => [
+				['mediaOrientation' => 2],
+				[
+					'horizontal' => 'left',
+					'vertical' => 'above',
+					'noWrap' => FALSE
+				]
+			],
+			'center below' => [
+				['mediaOrientation' => 8],
+				[
+					'horizontal' => 'center',
+					'vertical' => 'below',
+					'noWrap' => FALSE
+				]
+			],
+			'right below' => [
+				['mediaOrientation' => 9],
+				[
+					'horizontal' => 'right',
+					'vertical' => 'below',
+					'noWrap' => FALSE
+				]
+			],
+			'left below' => [
+				['mediaOrientation' => 10],
+				[
+					'horizontal' => 'left',
+					'vertical' => 'below',
+					'noWrap' => FALSE
+				]
+			],
+			'right intext' => [
+				['mediaOrientation' => 17],
+				[
+					'horizontal' => 'right',
+					'vertical' => 'intext',
+					'noWrap' => FALSE
+				]
+			],
+			'left intext' => [
+				['mediaOrientation' => 18],
+				[
+					'horizontal' => 'left',
+					'vertical' => 'intext',
+					'noWrap' => FALSE
+				]
+			],
+			'right intext no wrap' => [
+				['mediaOrientation' => 25],
+				[
+					'horizontal' => 'right',
+					'vertical' => 'intext',
+					'noWrap' => TRUE
+				]
+			],
+			'left intext no wrap' => [
+				['mediaOrientation' => 26],
+				[
+					'horizontal' => 'left',
+					'vertical' => 'intext',
+					'noWrap' => TRUE
+				]
+			],
+
+		];
+	}
+
+	/**
+	 * @test
+	 * @dataProvider galleryPositionDataProvider
+	 */
+	public function galleryPositionTest($processorConfiguration, $expected) {
+		$processor = new GalleryProcessor();
+		$processedData = $processor->process(
+			$this->contentObjectRenderer,
+			[],
+			$processorConfiguration,
+			['files' => []]
+		);
+
+		$this->assertEquals($expected, $processedData['gallery']['position']);
+	}
+
+	/**
+	 * @test
+	 */
+	public function maxGalleryWidthTest() {
+		$processor = new GalleryProcessor();
+		$processedData = $processor->process(
+			$this->contentObjectRenderer,
+			[],
+			['maxGalleryWidth' => 200, 'maxGalleryWidthInText' => 100],
+			['files' => []]
+		);
+
+		$this->assertEquals(200, $processedData['gallery']['width']);
+	}
+
+	/**
+	 * @test
+	 */
+	public function maxGalleryWidthWhenInTextTest() {
+		$processor = new GalleryProcessor();
+		$processedData = $processor->process(
+			$this->contentObjectRenderer,
+			[],
+			['maxGalleryWidth' => 200, 'maxGalleryWidthInText' => 100, 'mediaOrientation' => 26],
+			['files' => []]
+		);
+
+		$this->assertEquals(100, $processedData['gallery']['width']);
+	}
+
+	/**
+	 * Count test data provider
+	 * @return array
+	 */
+	public function countDataProvider() {
+		return [
+			'Default settings with 3 files' => [
+				3,
+				[],
+				[],
+				[
+					'files' => 3,
+					'columns' => 1,
+					'rows' => 3
+				]
+			],
+			'NumberOfColumns set by value' => [
+				3,
+				[],
+				['numberOfColumns' => 2],
+				[
+					'files' => 3,
+					'columns' => 2,
+					'rows' => 2
+				]
+			],
+			'NumberOfColumns set in data' => [
+				3,
+				['imagecols' => 3],
+				[],
+				[
+					'files' => 3,
+					'columns' => 3,
+					'rows' => 1
+				]
+			],
+			'NumberOfColumns set in custom data field' => [
+				6,
+				['my_imagecols' => 4],
+				['numberOfColumns.' => [
+					'field' => 'my_imagecols'
+				]],
+				[
+					'files' => 6,
+					'columns' => 4,
+					'rows' => 2
+				]
+			]
+		];
+	}
+
+	/**
+	 * @test
+	 * @dataProvider countDataProvider
+	 */
+	public function countResultTest($numberOfFiles, $data, $processorConfiguration, $expected) {
+		$files = [];
+		for ($i = 0; $i < $numberOfFiles; $i++) {
+			$files[] = $this->getMock(FileReference::class, array(), array(), '', FALSE);
+		}
+		$this->contentObjectRenderer->data = $data;
+		$processor = new GalleryProcessor();
+		$processedData = $processor->process(
+			$this->contentObjectRenderer,
+			[],
+			$processorConfiguration,
+			['files' => $files]
+		);
+
+		$this->assertEquals($expected, $processedData['gallery']['count']);
+	}
+
+	/**
+	 * Data provider for calculateMediaWidthsAndHeightsTest
+	 *
+	 * @return array
+	 */
+	public function calculateMediaWidthsAndHeightsDataProvider() {
+		return [
+			'Default settings' => [
+				[
+					[200, 100],
+					[200, 100],
+					[200, 100],
+				],
+				[],
+				[
+					1 => [
+						1 => ['width' => 200, 'height' => 100]
+					],
+					2 => [
+						1 => ['width' => 200, 'height' => 100]
+					],
+					3 => [
+						1 => ['width' => 200, 'height' => 100]
+					],
+				]
+			],
+			'Max width set + number of columns set' => [
+				[
+					[200, 100],
+					[200, 100],
+					[200, 100],
+				],
+				['maxGalleryWidth' => 200, 'numberOfColumns' => 2],
+				[
+					1 => [
+						1 => ['width' => 100, 'height' => 50],
+						2 => ['width' => 100, 'height' => 50]
+					],
+					2 => [
+						1 => ['width' => 100, 'height' => 50],
+						2 => ['width' => NULL, 'height' => NULL]
+					],
+				]
+			],
+			'Max width set, number of columns + border (padding) set' => [
+				[
+					[200, 100],
+					[200, 100],
+					[200, 100],
+				],
+				[
+					'maxGalleryWidth' => 200,
+					'numberOfColumns' => 2,
+					'borderEnabled' => TRUE,
+					'borderPadding' => 4,
+					'borderWidth' => 0,
+				],
+				[
+					1 => [
+						1 => ['width' => 92, 'height' => 46],
+						2 => ['width' => 92, 'height' => 46]
+					],
+					2 => [
+						1 => ['width' => 92, 'height' => 46],
+						2 => ['width' => NULL, 'height' => NULL]
+					],
+				]
+			],
+			'Max width set, number of columns + border (width) set' => [
+				[
+					[200, 100],
+					[200, 100],
+					[200, 100],
+				],
+				[
+					'maxGalleryWidth' => 200,
+					'numberOfColumns' => 2,
+					'borderEnabled' => TRUE,
+					'borderPadding' => 0,
+					'borderWidth' => 4,
+				],
+				[
+					1 => [
+						1 => ['width' => 92, 'height' => 46],
+						2 => ['width' => 92, 'height' => 46]
+					],
+					2 => [
+						1 => ['width' => 92, 'height' => 46],
+						2 => ['width' => NULL, 'height' => NULL]
+					],
+				]
+			],
+			'Max width set, number of columns + border (padding + width) set' => [
+				[
+					[200, 100],
+					[200, 100],
+					[200, 100],
+				],
+				[
+					'maxGalleryWidth' => 200,
+					'numberOfColumns' => 2,
+					'borderEnabled' => TRUE,
+					'borderPadding' => 1,
+					'borderWidth' => 4,
+				],
+				[
+					1 => [
+						1 => ['width' => 90, 'height' => 45],
+						2 => ['width' => 90, 'height' => 45]
+					],
+					2 => [
+						1 => ['width' => 90, 'height' => 45],
+						2 => ['width' => NULL, 'height' => NULL]
+					],
+				]
+			],
+			'Equal height set' => [
+				[
+					[200, 100],
+					[200, 300],
+					[100, 50],
+					[2020, 1000],
+					[1000, 1000],
+				],
+				[
+					'maxGalleryWidth' => 500,
+					'numberOfColumns' => 3,
+					'equalMediaHeight' => 75
+				],
+				[
+					1 => [
+						1 => ['width' => 150, 'height' => 75],
+						2 => ['width' => 50, 'height' => 75],
+						3 => ['width' => 150, 'height' => 75]
+					],
+					2 => [
+						1 => ['width' => 151, 'height' => 75],
+						2 => ['width' => 75, 'height' => 75],
+						3 => ['width' => NULL, 'height' => NULL]
+					],
+				]
+			],
+			'Equal width set' => [
+				[
+					[200, 100],
+					[200, 300],
+					[100, 50],
+				],
+				[
+					'maxGalleryWidth' => 200,
+					'numberOfColumns' => 3,
+					'equalMediaWidth' => 75
+				],
+				[
+					1 => [
+						1 => ['width' => 66, 'height' => 33],
+						2 => ['width' => 66, 'height' => 99],
+						3 => ['width' => 66, 'height' => 33]
+					],
+				]
+			]
+		];
+	}
+
+	/**
+	 * @test
+	 * @dataProvider calculateMediaWidthsAndHeightsDataProvider
+	 */
+	public function calculateMediaWidthsAndHeightsTest($testFiles, $processorConfiguration, $expected) {
+		$files = [];
+		foreach ($testFiles as $fileConfig) {
+			$fileReference = $this->getMock(FileReference::class, array(), array(), '', FALSE);
+			$fileReference->expects($this->any())
+				->method('getProperty')
+				->will($this->returnValueMap([
+					['width', $fileConfig[0]],
+					['height', $fileConfig[1]]
+				]));
+			$files[] = $fileReference;
+		}
+
+		$processor = new GalleryProcessor();
+		$processedData = $processor->process(
+			$this->contentObjectRenderer,
+			[],
+			$processorConfiguration,
+			['files' => $files]
+		);
+
+		foreach ($expected as $row => $columns) {
+			$this->assertArrayHasKey($row, $processedData['gallery']['rows'], 'Row exists');
+			foreach ($columns as $column => $dimensions) {
+				$this->assertArrayHasKey($column, $processedData['gallery']['rows'][$row]['columns'], 'Column exists');
+				$this->assertEquals($dimensions, $processedData['gallery']['rows'][$row]['columns'][$column]['dimensions'], 'Dimensions match');
+			}
+		}
+	}
+
+}
\ No newline at end of file