diff --git a/apps/theming/appinfo/routes.php b/apps/theming/appinfo/routes.php
index a69ddc1a6c92f7058b589d28c1ca7c8459e7fac7..f3483dbf99bd7aa25bb1be4b626e13a37a064047 100644
--- a/apps/theming/appinfo/routes.php
+++ b/apps/theming/appinfo/routes.php
@@ -39,8 +39,8 @@ return ['routes' => [
 		'verb' => 'POST'
 	],
 	[
-		'name' => 'Theming#updateLogo',
-		'url' => '/ajax/updateLogo',
+		'name' => 'Theming#uploadImage',
+		'url' => '/ajax/uploadImage',
 		'verb' => 'POST'
 	],
 	[
@@ -49,13 +49,8 @@ return ['routes' => [
 		'verb' => 'GET',
 	],
 	[
-		'name' => 'Theming#getLogo',
-		'url' => '/logo',
-		'verb' => 'GET',
-	],
-	[
-		'name' => 'Theming#getLoginBackground',
-		'url' => '/loginbackground',
+		'name' => 'Theming#getImage',
+		'url' => '/image/{key}',
 		'verb' => 'GET',
 	],
 	[
diff --git a/apps/theming/css/settings-admin.css b/apps/theming/css/settings-admin.css
deleted file mode 100644
index b0fdb79b291a4931e12d73b545722efd63befd28..0000000000000000000000000000000000000000
--- a/apps/theming/css/settings-admin.css
+++ /dev/null
@@ -1,107 +0,0 @@
-#theming input {
-    width: 230px;
-}
-
-#theming input:focus,
-#theming input:active {
-    padding-right: 30px;
-}
-
-#theming .upload-logo-field {
-    display: none;
-}
-
-#theming div > label {
-    position: relative;
-}
-
-#theming .theme-undo {
-    position: absolute;
-    top: -7px;
-    right: 7px;
-    cursor: pointer;
-    opacity: .3;
-    padding: 7px;
-    vertical-align: top;
-    display: inline-block;
-    visibility: hidden;
-}
-form.uploadButton {
-    width: 356px;
-}
-#theming form .theme-undo,
-#theming .theme-remove-bg {
-    cursor: pointer;
-    opacity: .3;
-    padding: 7px;
-    vertical-align: top;
-    display: inline-block;
-    float: right;
-    position: relative;
-    top: 4px;
-    right: 0px;
-    visibility: visible;
-}
-#theming input[type='text']:hover + .theme-undo,
-#theming input[type='text'] + .theme-undo:hover,
-#theming input[type='text']:focus + .theme-undo,
-#theming input[type='text']:active + .theme-undo {
-    visibility: visible;
-}
-
-#theming label span {
-    display: inline-block;
-    min-width: 120px;
-    padding: 8px 0px;
-    vertical-align: top;
-}
-
-#theming .icon-upload,
-#theming .uploadButton .icon-loading-small {
-    padding: 8px 20px;
-    width: 20px;
-    margin: 2px 0px;
-    min-height: 32px;
-    display: inline-block;
-}
-
-#theming_settings_status {
-    height: 26px;
-    margin: 10px;
-}
-
-#theming_settings_loading {
-    display: inline-block;
-    vertical-align: middle;
-    margin-right: 10px;
-}
-
-#theming_settings_msg {
-    vertical-align: middle;
-    border-radius: 3px;
-}
-
-#theming-preview-logo {
-    cursor: pointer;
-}
-
-#theming-preview {
-    width: 230px;
-    height: 140px;
-    background-size: cover;
-    background-position: center center;
-    text-align: center;
-    margin-left: 123px;
-    margin-top: 10px;
-    cursor: pointer;
-}
-
-#theming-preview img {
-    max-width: 20%;
-    max-height: 20%;
-    margin-top: 20px;
-}
-
-.theming-hints {
-    margin-top: 20px;
-}
\ No newline at end of file
diff --git a/apps/theming/css/settings-admin.scss b/apps/theming/css/settings-admin.scss
new file mode 100644
index 0000000000000000000000000000000000000000..ceb560f0f02fdefd4f1cf902348e88c82fbde7cf
--- /dev/null
+++ b/apps/theming/css/settings-admin.scss
@@ -0,0 +1,120 @@
+#theming {
+    input {
+        width: 230px;
+    }
+
+    input:focus,
+    input:active {
+        padding-right: 30px;
+    }
+
+    .fileupload {
+        display: none;
+    }
+
+    div > label {
+        position: relative;
+    }
+
+    .theme-undo {
+        position: absolute;
+        top: -7px;
+        right: 7px;
+        cursor: pointer;
+        opacity: .3;
+        padding: 7px;
+        vertical-align: top;
+        display: inline-block;
+        visibility: hidden;
+    }
+    form.uploadButton {
+        width: 356px;
+    }
+    form .theme-undo,
+    .theme-remove-bg {
+        cursor: pointer;
+        opacity: .3;
+        padding: 7px;
+        vertical-align: top;
+        display: inline-block;
+        float: right;
+        position: relative;
+        top: 4px;
+        right: 0px;
+        visibility: visible;
+    }
+    input[type='text']:hover + .theme-undo,
+    input[type='text'] + .theme-undo:hover,
+    input[type='text']:focus + .theme-undo,
+    input[type='text']:active + .theme-undo {
+        visibility: visible;
+    }
+
+    label span {
+        display: inline-block;
+        min-width: 120px;
+        padding: 8px 0px;
+        vertical-align: top;
+    }
+
+    .icon-upload,
+    .uploadButton .icon-loading-small {
+        padding: 8px 20px;
+        width: 20px;
+        margin: 2px 0px;
+        min-height: 32px;
+        display: inline-block;
+    }
+
+    #theming_settings_status {
+        height: 26px;
+        margin: 10px;
+    }
+
+    #theming_settings_loading {
+        display: inline-block;
+        vertical-align: middle;
+        margin-right: 10px;
+    }
+
+    #theming_settings_msg {
+        vertical-align: middle;
+        border-radius: 3px;
+    }
+
+    #theming-preview {
+        width: 230px;
+        height: 140px;
+        background-size: cover;
+        background-position: center center;
+        text-align: center;
+        margin-left: 123px;
+        margin-top: 10px;
+        margin-bottom: 20px;
+        cursor: pointer;
+
+        #theming-preview-logo {
+            cursor: pointer;
+            width: 20%;
+            height: 20%;
+            margin-top: 20px;
+            display: inline-block;
+            background-position: center;
+            background-repeat: no-repeat;
+            background-size: contain;
+        }
+    }
+
+    .theming-hints {
+        margin-top: 20px;
+    }
+
+    .image-preview {
+        display: inline-block;
+        width: 80px;
+        height: 36px;
+        background-position: center;
+        background-repeat: no-repeat;
+        background-size: contain;
+    }
+}
\ No newline at end of file
diff --git a/apps/theming/css/theming.scss b/apps/theming/css/theming.scss
index 3bb26a148141606da1bda9e4e330a7e6b85b5b9a..f65e20fa9b71e5818b086e568cd85d698da21bf4 100644
--- a/apps/theming/css/theming.scss
+++ b/apps/theming/css/theming.scss
@@ -92,6 +92,7 @@
 
 /* override styles for login screen in guest.css */
 @if variable_exists('theming-logo-mime') and $theming-logo-mime != '' {
+	#theming-preview-logo,
 	#header .logo {
 		background-image: url(#{$image-logo});
 		background-size: contain;
@@ -99,13 +100,45 @@
 	#body-login #header .logo {
 		margin-bottom: 22px;
 	}
+} @else {
+	#theming-preview-logo {
+		background-image: url(#{$image-logo});
+	}
 }
 
-#body-login,
-#firstrunwizard .firstrunwizard-header,
-#theming-preview {
-	background-image: url(#{$image-login-background});
-	background-color: $color-primary;
+@if variable_exists('theming-background-mime') and $theming-background-mime != ''  {
+	#body-login,
+	#firstrunwizard .firstrunwizard-header,
+	#theming-preview {
+		background-image: url(#{$image-login-background});
+		background-color: $color-primary;
+	}
+} @else {
+	  #theming-preview {
+		  background-image: url(#{$image-login-background});
+		  background-color: $color-primary;
+	  }
+}
+
+@if variable_exists('theming-logoheader-mime') and $theming-logoheader-mime != '' {
+	#theming .advanced-option-logoheader .image-preview,
+	body:not(#body-login) #header .logo {
+		background-image: url(#{$image-logoheader});
+	}
+} @else {
+	#theming .advanced-option-favicon .image-preview {
+		background-image: none;
+	}
+}
+
+@if variable_exists('theming-favicon-mime') and $theming-favicon-mime != '' {
+	#theming .advanced-option-favicon .image-preview {
+		background-image: url(#{$image-favicon});
+	}
+} @else {
+	#theming .advanced-option-favicon .image-preview {
+		background-image: none;
+	}
 }
 
 input.primary,
@@ -134,6 +167,10 @@ input.primary,
 		}
 
 	}
+} @else {
+	#body-login {
+		background-color: $color-primary;
+	}
 }
 
 @if ($color-primary == #ffffff) {
diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js
index 1f416bb29405c3b5746f4422d6bcda674a14eb7b..25ac092a964175dd33390fae69ce8d17260cade0 100644
--- a/apps/theming/js/settings-admin.js
+++ b/apps/theming/js/settings-admin.js
@@ -35,7 +35,6 @@ function setThemingValue(setting, value) {
 		OC.msg.finishedSaving('#theming_settings_msg', response);
 		$('#theming_settings_loading').hide();
 	});
-
 }
 
 function preview(setting, value, serverCssUrl) {
@@ -69,17 +68,6 @@ function preview(setting, value, serverCssUrl) {
 	}
 	reloadStylesheets(OC.generateUrl('/apps/theming/styles'));
 
-	// Preview images
-	var timestamp = new Date().getTime();
-	if (setting === 'logoMime') {
-		var previewImageLogo = document.getElementById('theming-preview-logo');
-		if (value !== '') {
-			previewImageLogo.src = OC.generateUrl('/apps/theming/logo') + "?v" + timestamp;
-		} else {
-			previewImageLogo.src = OC.getRootPath() + '/core/img/logo.svg?v' + timestamp;
-		}
-	}
-
 	if (setting === 'name') {
 		window.document.title = t('core', 'Admin') + " - " + value;
 	}
@@ -119,53 +107,36 @@ $(document).ready(function () {
 	$('#theming .theme-undo').each(function() {
 		var setting = $(this).data('setting');
 		var value = $('#theming-'+setting).val();
-		if(setting === 'logoMime' || setting === 'backgroundMime') {
-			var value = $('#current-'+setting).val();
-		}
 		hideUndoButton(setting, value);
 	});
 
-	var uploadParamsLogo = {
-		pasteZone: null,
-		dropZone: null,
-		done: function (e, response) {
-			preview('logoMime', response.result.data.name);
-			OC.msg.finishedSaving('#theming_settings_msg', response.result);
-			$('label#uploadlogo').addClass('icon-upload').removeClass('icon-loading-small');
-			$('.theme-undo[data-setting=logoMime]').show();
-		},
-		submit: function(e, response) {
-			startLoading();
-			$('label#uploadlogo').removeClass('icon-upload').addClass('icon-loading-small');
-		},
-		fail: function (e, response){
-			OC.msg.finishedError('#theming_settings_msg', response._response.jqXHR.responseJSON.data.message);
-			$('label#uploadlogo').addClass('icon-upload').removeClass('icon-loading-small');
-			$('#theming_settings_loading').hide();
-		}
-	};
-	var uploadParamsLogin = {
+	$('.fileupload').fileupload({
 		pasteZone: null,
 		dropZone: null,
 		done: function (e, response) {
-			preview('backgroundMime', response.result.data.name);
+			var $form = $(e.target).closest('form');
+			var key = $form.data('image-key');
+
+			preview(key + 'Mime', response.result.data.name, response.result.data.serverCssUrl);
+			$form.find('.image-preview').css('backgroundImage', response.result.data.url + '?v=' + new Date().getTime());
 			OC.msg.finishedSaving('#theming_settings_msg', response.result);
-			$('label#upload-login-background').addClass('icon-upload').removeClass('icon-loading-small');
-			$('.theme-undo[data-setting=backgroundMime]').show();
+			$form.find('label.button').addClass('icon-upload').removeClass('icon-loading-small');
+			$form.find('.theme-undo').show();
 		},
 		submit: function(e, response) {
+			var $form = $(e.target).closest('form');
+			var key = $form.data('image-key');
 			startLoading();
-			$('label#upload-login-background').removeClass('icon-upload').addClass('icon-loading-small');
+			$form.find('label.button').removeClass('icon-upload').addClass('icon-loading-small');
 		},
 		fail: function (e, response){
-			$('label#upload-login-background').removeClass('icon-loading-small').addClass('icon-upload');
+			var $form = $(e.target).closest('form');
 			OC.msg.finishedError('#theming_settings_msg', response._response.jqXHR.responseJSON.data.message);
+			$form.find('label.button').addClass('icon-upload').removeClass('icon-loading-small');
 			$('#theming_settings_loading').hide();
 		}
-	};
+	});
 
-	$('#uploadlogo').fileupload(uploadParamsLogo);
-	$('#upload-login-background').fileupload(uploadParamsLogin);
 	// clicking preview should also trigger file upload dialog
 	$('#theming-preview-logo').on('click', function(e) {
 		e.stopPropagation();
@@ -202,46 +173,42 @@ $(document).ready(function () {
 
 	$('#theming-name').change(function(e) {
 		var el = $(this);
-		if(checkName()){
-			$.when(el.focusout()).then(function() {
-				setThemingValue('name', $(this).val());
-			});
-			if (e.keyCode == 13) {
-				setThemingValue('name', $(this).val());
-			} 
-		}
 	});
 
-	$('#theming-url').change(function(e) {
+	$('#theming input[type=text]').change(function(e) {
 		var el = $(this);
-		$.when(el.focusout()).then(function() {
-			setThemingValue('url', $(this).val());
-		});
-		if (e.keyCode == 13) {
-			setThemingValue('url', $(this).val());
+		var setting = el.parent().find('div[data-setting]').data('setting');
+		var value = $(this).val();
+
+		if(setting === 'color') {
+			if (value.indexOf('#') !== 0) {
+				value = '#' + value;
+			}
+		}
+		if(setting === 'name') {
+      if(checkName()){
+        $.when(el.focusout()).then(function() {
+          setThemingValue('name', value);
+        });
+        if (e.keyCode == 13) {
+          setThemingValue('name', value);
+        } 
+      }
 		}
-	});
 
-	$('#theming-slogan').change(function(e) {
-		var el = $(this);
 		$.when(el.focusout()).then(function() {
-			setThemingValue('slogan', $(this).val());
+			setThemingValue(setting, value);
 		});
 		if (e.keyCode == 13) {
-			setThemingValue('slogan', $(this).val());
+			setThemingValue(setting, value);
 		}
 	});
 
-	$('#theming-color').change(function (e) {
-		var color = $(this).val();
-		if (color.indexOf('#') !== 0) {
-			color = '#' + color;
-		}
-		setThemingValue('color', color);
-	});
-
 	$('.theme-undo').click(function (e) {
 		var setting = $(this).data('setting');
+		var $form = $(this).closest('form');
+		var image = $form.data('image-key');
+
 		startLoading();
 		$('.theme-undo[data-setting=' + setting + ']').hide();
 		$.post(
@@ -251,7 +218,7 @@ $(document).ready(function () {
 				var colorPicker = document.getElementById('theming-color');
 				colorPicker.style.backgroundColor = response.data.value;
 				colorPicker.value = response.data.value.slice(1).toUpperCase();
-			} else if (setting !== 'logoMime' && setting !== 'backgroundMime') {
+			} else if (!image) {
 				var input = document.getElementById('theming-'+setting);
 				input.value = response.data.value;
 			}
@@ -262,11 +229,12 @@ $(document).ready(function () {
 	$('.theme-remove-bg').click(function() {
 		startLoading();
 		$.post(
-			OC.generateUrl('/apps/theming/ajax/updateLogo'), {'backgroundColor' : true}
+			OC.generateUrl('/apps/theming/ajax/updateStylesheet'), {'setting' : 'backgroundMime', 'value' : 'backgroundColor'}
 		).done(function(response) {
-			preview('backgroundMime', 'backgroundColor');
+			preview('backgroundMime', 'backgroundColor', response.data.serverCssUrl);
 		}).fail(function(response) {
 			OC.msg.finishedSaving('#theming_settings_msg', response);
+			$('#theming_settings_loading').hide();
 		});
 	});
 
diff --git a/apps/theming/lib/Controller/IconController.php b/apps/theming/lib/Controller/IconController.php
index 7a5f76de6b652142396e870f9f998819de8b4586..61df7b0b35314bad4c7524cb287ee1b2c77c97ce 100644
--- a/apps/theming/lib/Controller/IconController.php
+++ b/apps/theming/lib/Controller/IconController.php
@@ -33,21 +33,16 @@ use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\NotFoundResponse;
 use OCP\AppFramework\Http\FileDisplayResponse;
 use OCP\AppFramework\Http\DataDisplayResponse;
+use OCP\AppFramework\Http\Response;
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\Files\NotFoundException;
 use OCP\IRequest;
-use OCA\Theming\Util;
-use OCP\IConfig;
 
 class IconController extends Controller {
 	/** @var ThemingDefaults */
 	private $themingDefaults;
-	/** @var Util */
-	private $util;
 	/** @var ITimeFactory */
 	private $timeFactory;
-	/** @var IConfig */
-	private $config;
 	/** @var IconBuilder */
 	private $iconBuilder;
 	/** @var ImageManager */
@@ -61,19 +56,16 @@ class IconController extends Controller {
 	 * @param string $appName
 	 * @param IRequest $request
 	 * @param ThemingDefaults $themingDefaults
-	 * @param Util $util
 	 * @param ITimeFactory $timeFactory
-	 * @param IConfig $config
 	 * @param IconBuilder $iconBuilder
 	 * @param ImageManager $imageManager
+	 * @param FileAccessHelper $fileAccessHelper
 	 */
 	public function __construct(
 		$appName,
 		IRequest $request,
 		ThemingDefaults $themingDefaults,
-		Util $util,
 		ITimeFactory $timeFactory,
-		IConfig $config,
 		IconBuilder $iconBuilder,
 		ImageManager $imageManager,
 		FileAccessHelper $fileAccessHelper
@@ -81,9 +73,7 @@ class IconController extends Controller {
 		parent::__construct($appName, $request);
 
 		$this->themingDefaults = $themingDefaults;
-		$this->util = $util;
 		$this->timeFactory = $timeFactory;
-		$this->config = $config;
 		$this->iconBuilder = $iconBuilder;
 		$this->imageManager = $imageManager;
 		$this->fileAccessHelper = $fileAccessHelper;
@@ -96,16 +86,17 @@ class IconController extends Controller {
 	 * @param $app string app name
 	 * @param $image string image file name (svg required)
 	 * @return FileDisplayResponse|NotFoundResponse
+	 * @throws \Exception
 	 */
-	public function getThemedIcon($app, $image) {
+	public function getThemedIcon(string $app, string $image): Response {
 		try {
-			$iconFile = $this->imageManager->getCachedImage("icon-" . $app . '-' . str_replace("/","_",$image));
+			$iconFile = $this->imageManager->getCachedImage('icon-' . $app . '-' . str_replace('/', '_',$image));
 		} catch (NotFoundException $exception) {
 			$icon = $this->iconBuilder->colorSvg($app, $image);
-			if ($icon === false || $icon === "") {
+			if ($icon === false || $icon === '') {
 				return new NotFoundResponse();
 			}
-			$iconFile = $this->imageManager->setCachedImage("icon-" . $app . '-' . str_replace("/","_",$image), $icon);
+			$iconFile = $this->imageManager->setCachedImage('icon-' . $app . '-' . str_replace('/', '_',$image), $icon);
 		}
 		if ($iconFile !== false) {
 			$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']);
@@ -116,9 +107,9 @@ class IconController extends Controller {
 			$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
 			$response->addHeader('Pragma', 'cache');
 			return $response;
-		} else {
-			return new NotFoundResponse();
 		}
+
+		return new NotFoundResponse();
 	}
 
 	/**
@@ -129,10 +120,17 @@ class IconController extends Controller {
 	 *
 	 * @param $app string app name
 	 * @return FileDisplayResponse|DataDisplayResponse
+	 * @throws \Exception
 	 */
-	public function getFavicon($app = "core") {
+	public function getFavicon(string $app = 'core'): Response {
 		$response = null;
-		if ($this->themingDefaults->shouldReplaceIcons()) {
+		$iconFile = null;
+		try {
+			$iconFile = $this->imageManager->getImage('favicon');
+			$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
+		} catch (NotFoundException $e) {
+		}
+		if ($iconFile === null && $this->themingDefaults->shouldReplaceIcons()) {
 			try {
 				$iconFile = $this->imageManager->getCachedImage('favIcon-' . $app);
 			} catch (NotFoundException $exception) {
@@ -164,9 +162,15 @@ class IconController extends Controller {
 	 *
 	 * @param $app string app name
 	 * @return FileDisplayResponse|NotFoundResponse
+	 * @throws \Exception
 	 */
-	public function getTouchIcon($app = "core") {
+	public function getTouchIcon(string $app = 'core'): Response {
 		$response = null;
+		try {
+			$iconFile = $this->imageManager->getImage('favicon');
+			$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
+		} catch (NotFoundException $e) {
+		}
 		if ($this->themingDefaults->shouldReplaceIcons()) {
 			try {
 				$iconFile = $this->imageManager->getCachedImage('touchIcon-' . $app);
diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php
index 47f806d16f919cf53d7bfd31f99066ccfeb7b05f..421af05199842b265c0a8fcc50ef285df757fb1f 100644
--- a/apps/theming/lib/Controller/ThemingController.php
+++ b/apps/theming/lib/Controller/ThemingController.php
@@ -33,6 +33,7 @@
 namespace OCA\Theming\Controller;
 
 use OC\Template\SCSSCacher;
+use OCA\Theming\ImageManager;
 use OCA\Theming\ThemingDefaults;
 use OCP\AppFramework\Controller;
 use OCP\AppFramework\Http;
@@ -81,6 +82,8 @@ class ThemingController extends Controller {
 	private $urlGenerator;
 	/** @var IAppManager */
 	private $appManager;
+	/** @var ImageManager */
+	private $imageManager;
 
 	/**
 	 * ThemingController constructor.
@@ -97,6 +100,7 @@ class ThemingController extends Controller {
 	 * @param SCSSCacher $scssCacher
 	 * @param IURLGenerator $urlGenerator
 	 * @param IAppManager $appManager
+	 * @param ImageManager $imageManager
 	 */
 	public function __construct(
 		$appName,
@@ -110,7 +114,8 @@ class ThemingController extends Controller {
 		IAppData $appData,
 		SCSSCacher $scssCacher,
 		IURLGenerator $urlGenerator,
-		IAppManager $appManager
+		IAppManager $appManager,
+		ImageManager $imageManager
 	) {
 		parent::__construct($appName, $request);
 
@@ -124,13 +129,14 @@ class ThemingController extends Controller {
 		$this->scssCacher = $scssCacher;
 		$this->urlGenerator = $urlGenerator;
 		$this->appManager = $appManager;
+		$this->imageManager = $imageManager;
 	}
 
 	/**
 	 * @param string $setting
 	 * @param string $value
 	 * @return DataResponse
-	 * @internal param string $color
+	 * @throws NotPermittedException
 	 */
 	public function updateStylesheet($setting, $value) {
 		$value = trim($value);
@@ -195,27 +201,15 @@ class ThemingController extends Controller {
 	}
 
 	/**
-	 * Update the logos and background image
-	 *
 	 * @return DataResponse
+	 * @throws NotPermittedException
 	 */
-	public function updateLogo() {
-		$backgroundColor = $this->request->getParam('backgroundColor', false);
-		if($backgroundColor) {
-			$this->themingDefaults->set('backgroundMime', 'backgroundColor');
-			return new DataResponse(
-				[
-					'data' =>
-						[
-							'name' => 'backgroundColor',
-							'message' => $this->l10n->t('Saved')
-						],
-					'status' => 'success'
-				]
-			);
-		}
-		$newLogo = $this->request->getUploadedFile('uploadlogo');
-		$newBackgroundLogo = $this->request->getUploadedFile('upload-login-background');
+	public function uploadImage(): DataResponse {
+		// logo / background
+		// new: favicon logo-header
+		//
+		$key = $this->request->getParam('key');
+		$image = $this->request->getUploadedFile('image');
 		$error = null;
 		$phpFileUploadErrors = [
 			UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'),
@@ -227,14 +221,11 @@ class ThemingController extends Controller {
 			UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'),
 			UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'),
 		];
-		if (empty($newLogo) && empty($newBackgroundLogo)) {
+		if (empty($image)) {
 			$error = $this->l10n->t('No file uploaded');
 		}
-		if (!empty($newLogo) && array_key_exists('error', $newLogo) && $newLogo['error'] !== UPLOAD_ERR_OK) {
-			$error = $phpFileUploadErrors[$newLogo['error']];
-		}
-		if (!empty($newBackgroundLogo) && array_key_exists('error', $newBackgroundLogo) && $newBackgroundLogo['error'] !== UPLOAD_ERR_OK) {
-			$error = $phpFileUploadErrors[$newBackgroundLogo['error']];
+		if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) {
+			$error = $phpFileUploadErrors[$image['error']];
 		}
 
 		if ($error !== null) {
@@ -256,61 +247,53 @@ class ThemingController extends Controller {
 			$folder = $this->appData->newFolder('images');
 		}
 
-		if (!empty($newLogo)) {
-			$target = $folder->newFile('logo');
-			$supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg'];
-			if (!in_array($newLogo['type'], $supportedFormats)) {
-				return new DataResponse(
-					[
-						'data' => [
-							'message' => $this->l10n->t('Unsupported image type'),
-						],
-						'status' => 'failure',
+		$target = $folder->newFile($key);
+		$supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg'];
+		if (!in_array($image['type'], $supportedFormats)) {
+			return new DataResponse(
+				[
+					'data' => [
+						'message' => $this->l10n->t('Unsupported image type'),
 					],
-					Http::STATUS_UNPROCESSABLE_ENTITY
-				);
-			}
-			$target->putContent(file_get_contents($newLogo['tmp_name'], 'r'));
-			$this->themingDefaults->set('logoMime', $newLogo['type']);
-			$name = $newLogo['name'];
+					'status' => 'failure',
+				],
+				Http::STATUS_UNPROCESSABLE_ENTITY
+			);
 		}
-		if (!empty($newBackgroundLogo)) {
-			$target = $folder->newFile('background');
-			$image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r'));
-			if ($image === false) {
-				return new DataResponse(
-					[
-						'data' => [
-							'message' => $this->l10n->t('Unsupported image type'),
-						],
-						'status' => 'failure',
-					],
-					Http::STATUS_UNPROCESSABLE_ENTITY
-				);
-			}
 
+		$resizeKeys = ['background'];
+		if (in_array($key, $resizeKeys, true)) {
 			// Optimize the image since some people may upload images that will be
 			// either to big or are not progressive rendering.
+			$newImage = @imagecreatefromstring(file_get_contents($image['tmp_name'], 'r'));
+
 			$tmpFile = $this->tempManager->getTemporaryFile();
-			$newWidth = imagesx($image) < 4096 ? imagesx($image) : 4096;
-			$newHeight = imagesy($image) / (imagesx($image) / $newWidth);
-			$image = imagescale($image, $newWidth, $newHeight);
+			$newWidth = imagesx($newImage) < 4096 ? imagesx($newImage) : 4096;
+			$newHeight = imagesy($newImage) / (imagesx($newImage) / $newWidth);
+			$outputImage = imagescale($newImage, $newWidth, $newHeight);
 
-			imageinterlace($image, 1);
-			imagejpeg($image, $tmpFile, 75);
-			imagedestroy($image);
+			imageinterlace($outputImage, 1);
+			imagejpeg($outputImage, $tmpFile, 75);
+			imagedestroy($outputImage);
 
 			$target->putContent(file_get_contents($tmpFile, 'r'));
-			$this->themingDefaults->set('backgroundMime', $newBackgroundLogo['type']);
-			$name = $newBackgroundLogo['name'];
+		} else {
+			$target->putContent(file_get_contents($image['tmp_name'], 'r'));
 		}
+		$name = $image['name'];
+
+		$this->themingDefaults->set($key.'Mime', $image['type']);
+
+		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core');
 
 		return new DataResponse(
 			[
 				'data' =>
 					[
 						'name' => $name,
-						'message' => $this->l10n->t('Saved')
+						'url' => $this->imageManager->getImageUrl($key),
+						'message' => $this->l10n->t('Saved'),
+						'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss'))
 					],
 				'status' => 'success'
 			]
@@ -322,27 +305,16 @@ class ThemingController extends Controller {
 	 *
 	 * @param string $setting setting which should be reverted
 	 * @return DataResponse
+	 * @throws NotPermittedException
 	 */
-	public function undo($setting) {
+	public function undo(string $setting): DataResponse {
 		$value = $this->themingDefaults->undo($setting);
 		// reprocess server scss for preview
 		$cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core');
 
-		if($setting === 'logoMime') {
-			try {
-				$file = $this->appData->getFolder('images')->getFile('logo');
-				$file->delete();
-			} catch (NotFoundException $e) {
-			} catch (NotPermittedException $e) {
-			}
-		}
-		if($setting === 'backgroundMime') {
-			try {
-				$file = $this->appData->getFolder('images')->getFile('background');
-				$file->delete();
-			} catch (NotFoundException $e) {
-			} catch (NotPermittedException $e) {
-			}
+		if (strpos($setting, 'Mime') !== -1) {
+			$imageKey = str_replace('Mime', '', $setting);
+			$this->imageManager->delete($imageKey);
 		}
 
 		return new DataResponse(
@@ -362,37 +334,13 @@ class ThemingController extends Controller {
 	 * @PublicPage
 	 * @NoCSRFRequired
 	 *
+	 * @param string $key
 	 * @return FileDisplayResponse|NotFoundResponse
+	 * @throws \Exception
 	 */
-	public function getLogo() {
-		try {
-			/** @var File $file */
-			$file = $this->appData->getFolder('images')->getFile('logo');
-		} catch (NotFoundException $e) {
-			return new NotFoundResponse();
-		}
-
-		$response = new FileDisplayResponse($file);
-		$response->cacheFor(3600);
-		$expires = new \DateTime();
-		$expires->setTimestamp($this->timeFactory->getTime());
-		$expires->add(new \DateInterval('PT24H'));
-		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
-		$response->addHeader('Pragma', 'cache');
-		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', ''));
-		return $response;
-	}
-
-	/**
-	 * @PublicPage
-	 * @NoCSRFRequired
-	 *
-	 * @return FileDisplayResponse|NotFoundResponse
-	 */
-	public function getLoginBackground() {
+	public function getImage(string $key) {
 		try {
-			/** @var File $file */
-			$file = $this->appData->getFolder('images')->getFile('background');
+			$file = $this->imageManager->getImage($key);
 		} catch (NotFoundException $e) {
 			return new NotFoundResponse();
 		}
@@ -404,7 +352,7 @@ class ThemingController extends Controller {
 		$expires->add(new \DateInterval('PT24H'));
 		$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
 		$response->addHeader('Pragma', 'cache');
-		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', ''));
+		$response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', ''));
 		return $response;
 	}
 
@@ -413,6 +361,9 @@ class ThemingController extends Controller {
 	 * @PublicPage
 	 *
 	 * @return FileDisplayResponse|NotFoundResponse
+	 * @throws NotPermittedException
+	 * @throws \Exception
+	 * @throws \OCP\App\AppPathNotFoundException
 	 */
 	public function getStylesheet() {
 		$appPath = $this->appManager->getAppPath('theming');
diff --git a/apps/theming/lib/ImageManager.php b/apps/theming/lib/ImageManager.php
index 14dba0d0742645688802e167896057a254f662df..830ed7f34a96ffdaddc277f8cfa2cb6b2003f729 100644
--- a/apps/theming/lib/ImageManager.php
+++ b/apps/theming/lib/ImageManager.php
@@ -24,11 +24,17 @@
 
 namespace OCA\Theming;
 
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
 use OCP\IConfig;
 use OCP\Files\IAppData;
 use OCP\Files\NotFoundException;
 use OCP\Files\NotPermittedException;
+use OCP\IURLGenerator;
 
+/**
+ * @property IURLGenerator urlGenerator
+ */
 class ImageManager {
 
 	/** @var IConfig */
@@ -36,27 +42,79 @@ class ImageManager {
 	/** @var IAppData */
 	private $appData;
 
+	/** @var array */
+	private $supportedImageKeys = ['background', 'logo', 'logoheader', 'favicon'];
+
 	/**
 	 * ImageManager constructor.
 	 *
 	 * @param IConfig $config
 	 * @param IAppData $appData
+	 * @param IURLGenerator $urlGenerator
 	 */
 	public function __construct(IConfig $config,
-								IAppData $appData
+								IAppData $appData,
+								IURLGenerator $urlGenerator
 	) {
 		$this->config = $config;
 		$this->appData = $appData;
+		$this->urlGenerator = $urlGenerator;
+	}
+
+	public function getImageUrl(string $key): string {
+		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
+		try {
+			$this->getImage($key);
+			return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => $key ]) . '?v=' . $cacheBusterCounter;
+		} catch (NotFoundException $e) {
+		}
+
+		switch ($key) {
+			case 'logo':
+			case 'logoheader':
+			case 'favicon':
+				return $this->urlGenerator->imagePath('core', 'logo.png') . '?v=' . $cacheBusterCounter;
+			case 'background':
+				return $this->urlGenerator->imagePath('core', 'background.png') . '?v=' . $cacheBusterCounter;
+		}
+	}
+
+	public function getImageUrlAbsolute(string $key): string {
+		return $this->urlGenerator->getAbsoluteURL($this->getImageUrl($key));
+	}
+
+	/**
+	 * @param $key
+	 * @return ISimpleFile
+	 * @throws NotFoundException
+	 */
+	public function getImage(string $key): ISimpleFile {
+		$logo = $this->config->getAppValue('theming', $key . 'Mime', false);
+		if ($logo === false) {
+			throw new NotFoundException();
+		}
+		$folder = $this->appData->getFolder('images');
+		return $folder->getFile($key);
+	}
+
+	public function getCustomImages(): array {
+		$images = [];
+		foreach ($this->supportedImageKeys as $key) {
+			$images[$key] = [
+				'mime' => $this->config->getAppValue('theming', $key . 'Mime', ''),
+				'url' => $this->getImageUrl($key),
+			];
+		}
+		return $images;
 	}
 
 	/**
 	 * Get folder for current theming files
 	 *
-	 * @return \OCP\Files\SimpleFS\ISimpleFolder
+	 * @return ISimpleFolder
 	 * @throws NotPermittedException
-	 * @throws \RuntimeException
 	 */
-	public function getCacheFolder() {
+	public function getCacheFolder(): ISimpleFolder {
 		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
 		try {
 			$folder = $this->appData->getFolder($cacheBusterValue);
@@ -73,8 +131,9 @@ class ImageManager {
 	 * @param string $filename
 	 * @throws NotFoundException
 	 * @return \OCP\Files\SimpleFS\ISimpleFile
+	 * @throws NotPermittedException
 	 */
-	public function getCachedImage($filename) {
+	public function getCachedImage(string $filename): ISimpleFile {
 		$currentFolder = $this->getCacheFolder();
 		return $currentFolder->getFile($filename);
 	}
@@ -85,8 +144,10 @@ class ImageManager {
 	 * @param string $filename
 	 * @param string $data
 	 * @return \OCP\Files\SimpleFS\ISimpleFile
+	 * @throws NotFoundException
+	 * @throws NotPermittedException
 	 */
-	public function setCachedImage($filename, $data) {
+	public function setCachedImage(string $filename, string $data): ISimpleFile {
 		$currentFolder = $this->getCacheFolder();
 		if ($currentFolder->fileExists($filename)) {
 			$file = $currentFolder->getFile($filename);
@@ -97,8 +158,20 @@ class ImageManager {
 		return $file;
 	}
 
+	public function delete(string $key) {
+		try {
+			$file = $this->appData->getFolder('images')->getFile($key);
+			$file->delete();
+		} catch (NotFoundException $e) {
+		} catch (NotPermittedException $e) {
+		}
+	}
+
 	/**
 	 * remove cached files that are not required any longer
+	 *
+	 * @throws NotPermittedException
+	 * @throws NotFoundException
 	 */
 	public function cleanup() {
 		$currentFolder = $this->getCacheFolder();
diff --git a/apps/theming/lib/Settings/Admin.php b/apps/theming/lib/Settings/Admin.php
index d26a56806373c22a7fa5c2802619ca8f1cb263bc..7c937f1979090bc5c079aaf6825760b4634a4a2c 100644
--- a/apps/theming/lib/Settings/Admin.php
+++ b/apps/theming/lib/Settings/Admin.php
@@ -29,6 +29,7 @@
 
 namespace OCA\Theming\Settings;
 
+use OCA\Theming\ImageManager;
 use OCA\Theming\ThemingDefaults;
 use OCP\AppFramework\Http\TemplateResponse;
 use OCP\IConfig;
@@ -45,23 +46,25 @@ class Admin implements ISettings {
 	private $themingDefaults;
 	/** @var IURLGenerator */
 	private $urlGenerator;
+	/** @var ImageManager */
+	private $imageManager;
 
 	public function __construct(IConfig $config,
 								IL10N $l,
 								ThemingDefaults $themingDefaults,
-								IURLGenerator $urlGenerator) {
+								IURLGenerator $urlGenerator,
+								ImageManager $imageManager) {
 		$this->config = $config;
 		$this->l = $l;
 		$this->themingDefaults = $themingDefaults;
 		$this->urlGenerator = $urlGenerator;
+		$this->imageManager = $imageManager;
 	}
 
 	/**
 	 * @return TemplateResponse
 	 */
-	public function getForm() {
-		$path = $this->urlGenerator->linkToRoute('theming.Theming.updateLogo');
-
+	public function getForm(): TemplateResponse {
 		$themable = true;
 		$errorMessage = '';
 		$theme = $this->config->getSystemValue('theme', '');
@@ -77,13 +80,10 @@ class Admin implements ISettings {
 			'url'             => $this->themingDefaults->getBaseUrl(),
 			'slogan'          => $this->themingDefaults->getSlogan(),
 			'color'           => $this->themingDefaults->getColorPrimary(),
-			'logo'            => $this->themingDefaults->getLogo(),
-			'logoMime'        => $this->config->getAppValue('theming', 'logoMime', ''),
-			'background'      => $this->themingDefaults->getBackground(),
-			'backgroundMime'  => $this->config->getAppValue('theming', 'backgroundMime', ''),
-			'uploadLogoRoute' => $path,
+			'uploadLogoRoute' => $this->urlGenerator->linkToRoute('theming.Theming.uploadImage'),
 			'canThemeIcons'   => $this->themingDefaults->shouldReplaceIcons(),
-			'iconDocs'        => $this->urlGenerator->linkToDocs('admin-theming-icons')
+			'iconDocs'        => $this->urlGenerator->linkToDocs('admin-theming-icons'),
+			'images'		  => $this->imageManager->getCustomImages(),
 		];
 
 		return new TemplateResponse('theming', 'settings-admin', $parameters, '');
@@ -92,7 +92,7 @@ class Admin implements ISettings {
 	/**
 	 * @return string the section ID, e.g. 'sharing'
 	 */
-	public function getSection() {
+	public function getSection(): string {
 		return 'theming';
 	}
 
@@ -103,7 +103,7 @@ class Admin implements ISettings {
 	 *
 	 * E.g.: 70
 	 */
-	public function getPriority() {
+	public function getPriority(): int {
 		return 5;
 	}
 
diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php
index ce4ab0abb55405c4b72c9541cac0bcd645debd01..2e6b667b1f66f5354a24d7985975f8b659c880a5 100644
--- a/apps/theming/lib/ThemingDefaults.php
+++ b/apps/theming/lib/ThemingDefaults.php
@@ -36,7 +36,7 @@ namespace OCA\Theming;
 
 use OCP\App\AppPathNotFoundException;
 use OCP\App\IAppManager;
-use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
 use OCP\ICacheFactory;
 use OCP\IConfig;
 use OCP\IL10N;
@@ -48,10 +48,10 @@ class ThemingDefaults extends \OC_Defaults {
 	private $config;
 	/** @var IL10N */
 	private $l;
+	/** @var ImageManager */
+	private $imageManager;
 	/** @var IURLGenerator */
 	private $urlGenerator;
-	/** @var IAppData */
-	private $appData;
 	/** @var ICacheFactory */
 	private $cacheFactory;
 	/** @var Util */
@@ -83,9 +83,8 @@ class ThemingDefaults extends \OC_Defaults {
 	 *
 	 * @param IConfig $config
 	 * @param IL10N $l
+	 * @param ImageManager $imageManager
 	 * @param IURLGenerator $urlGenerator
-	 * @param \OC_Defaults $defaults
-	 * @param IAppData $appData
 	 * @param ICacheFactory $cacheFactory
 	 * @param Util $util
 	 * @param IAppManager $appManager
@@ -93,16 +92,16 @@ class ThemingDefaults extends \OC_Defaults {
 	public function __construct(IConfig $config,
 								IL10N $l,
 								IURLGenerator $urlGenerator,
-								IAppData $appData,
 								ICacheFactory $cacheFactory,
 								Util $util,
+								ImageManager $imageManager,
 								IAppManager $appManager
 	) {
 		parent::__construct();
 		$this->config = $config;
 		$this->l = $l;
+		$this->imageManager = $imageManager;
 		$this->urlGenerator = $urlGenerator;
-		$this->appData = $appData;
 		$this->cacheFactory = $cacheFactory;
 		$this->util = $util;
 		$this->appManager = $appManager;
@@ -166,12 +165,12 @@ class ThemingDefaults extends \OC_Defaults {
 	 * @param bool $useSvg Whether to point to the SVG image or a fallback
 	 * @return string
 	 */
-	public function getLogo($useSvg = true) {
+	public function getLogo($useSvg = true): string {
 		$logo = $this->config->getAppValue('theming', 'logoMime', false);
 
 		$logoExists = true;
 		try {
-			$this->appData->getFolder('images')->getFile('logo');
+			$this->imageManager->getImage('logo');
 		} catch (\Exception $e) {
 			$logoExists = false;
 		}
@@ -187,7 +186,7 @@ class ThemingDefaults extends \OC_Defaults {
 			return $logo . '?v=' . $cacheBusterCounter;
 		}
 
-		return $this->urlGenerator->linkToRoute('theming.Theming.getLogo') . '?v=' . $cacheBusterCounter;
+		return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo' ]) . '?v=' . $cacheBusterCounter;
 	}
 
 	/**
@@ -195,14 +194,8 @@ class ThemingDefaults extends \OC_Defaults {
 	 *
 	 * @return string
 	 */
-	public function getBackground() {
-		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
-
-		if($this->util->isBackgroundThemed()) {
-			return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter;
-		}
-
-		return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter;
+	public function getBackground(): string {
+		return $this->imageManager->getImageUrl('background');
 	}
 
 	/**
@@ -238,12 +231,16 @@ class ThemingDefaults extends \OC_Defaults {
 
 		$variables = [
 			'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'",
-			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime', '') . "'",
-			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime', '') . "'"
+			'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'",
+			'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'",
+			'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'",
+			'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'"
 		];
 
-		$variables['image-logo'] = "'".$this->getLogo()."'";
-		$variables['image-login-background'] = "'".$this->getBackground()."'";
+		$variables['image-logo'] = "'".$this->imageManager->getImageUrl('logo')."'";
+		$variables['image-logoheader'] = "'".$this->imageManager->getImageUrl('logoheader')."'";
+		$variables['image-favicon'] = "'".$this->imageManager->getImageUrl('favicon')."'";
+		$variables['image-login-background'] = "'".$this->imageManager->getImageUrl('background')."'";
 		$variables['image-login-plain'] = 'false';
 
 		if ($this->config->getAppValue('theming', 'color', null) !== null) {
@@ -273,10 +270,16 @@ class ThemingDefaults extends \OC_Defaults {
 		}
 		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
 
-		if ($image === 'favicon.ico' && $this->shouldReplaceIcons()) {
+		try {
+			$customFavicon = $this->imageManager->getImage('favicon');
+		} catch (NotFoundException $e) {
+			$customFavicon = null;
+		}
+
+		if ($image === 'favicon.ico' && ($customFavicon !== null || $this->shouldReplaceIcons())) {
 			return $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]) . '?v=' . $cacheBusterValue;
 		}
-		if ($image === 'favicon-touch.png' && $this->shouldReplaceIcons()) {
+		if ($image === 'favicon-touch.png' && ($customFavicon !== null || $this->shouldReplaceIcons())) {
 			return $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]) . '?v=' . $cacheBusterValue;
 		}
 		if ($image === 'manifest.json') {
@@ -321,6 +324,8 @@ class ThemingDefaults extends \OC_Defaults {
 		$cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0');
 		$this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1);
 		$this->cacheFactory->createDistributed('theming-')->clear();
+		$this->cacheFactory->createDistributed('imagePath')->clear();
+
 	}
 
 	/**
diff --git a/apps/theming/templates/settings-admin.php b/apps/theming/templates/settings-admin.php
index 7e489199927a684c6a643ad2ebb1262261bcb72e..cb117c72a2b6d23476b440408a6591f017f21f6f 100644
--- a/apps/theming/templates/settings-admin.php
+++ b/apps/theming/templates/settings-admin.php
@@ -67,27 +67,57 @@ style('theming', 'settings-admin');
 		</label>
 	</div>
 	<div>
-		<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>">
-			<input type="hidden" id="current-logoMime" name="current-logoMime" value="<?php p($_['logoMime']); ?>" />
+		<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="logo">
+			<input type="hidden" id="theming-logoMime" value="<?php p($_['images']['logo']['mime']); ?>" />
+			<input type="hidden" name="key" value="logo" />
 			<label for="uploadlogo"><span><?php p($l->t('Logo')) ?></span></label>
-			<input id="uploadlogo" class="upload-logo-field" name="uploadlogo" type="file" />
+			<input id="uploadlogo" class="fileupload" name="image" type="file" />
 			<label for="uploadlogo" class="button icon-upload svg" id="uploadlogo" title="<?php p($l->t('Upload new logo')) ?>"></label>
 			<div data-setting="logoMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div>
 		</form>
 	</div>
 	<div>
-		<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>">
-			<input type="hidden" id="current-backgroundMime" name="current-backgroundMime" value="<?php p($_['backgroundMime']); ?>" />
+		<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="background">
+			<input type="hidden" id="theming-backgroundMime" value="<?php p($_['images']['background']['mime']); ?>" />
+			<input type="hidden" name="key" value="background" />
 			<label for="upload-login-background"><span><?php p($l->t('Login image')) ?></span></label>
-			<input id="upload-login-background" class="upload-logo-field" name="upload-login-background" type="file">
+			<input id="upload-login-background" class="fileupload" name="image" type="file">
 			<label for="upload-login-background" class="button icon-upload svg" id="upload-login-background" title="<?php p($l->t("Upload new login background")) ?>"></label>
 			<div data-setting="backgroundMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div>
 			<div class="theme-remove-bg icon icon-delete" data-toggle="tooltip" data-original-title="<?php p($l->t('Remove background image')); ?>"></div>
 		</form>
 	</div>
 	<div id="theming-preview">
-		<img src="<?php p($_['logo']); ?>" id="theming-preview-logo" />
+		<div id="theming-preview-logo"></div>
 	</div>
+
+	<h2 class="inlineblock"><?php p($l->t('Advanced options')); ?></h2>
+
+	<div class="advanced-options">
+		<div class="advanced-option-logoheader">
+			<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="logoheader">
+				<input type="hidden" id="theming-logoheaderMime" value="<?php p($_['images']['logoheader']['mime']); ?>" />
+				<input type="hidden" name="key" value="logoheader" />
+				<label for="upload-login-logoheader"><span><?php p($l->t('Header logo')) ?></span></label>
+				<input id="upload-login-logoheader" class="fileupload" name="image" type="file">
+				<label for="upload-login-logoheader" class="button icon-upload svg" id="upload-login-logoheader" title="<?php p($l->t("Upload new header logo")) ?>"></label>
+				<div class="image-preview"></div>
+				<div data-setting="logoheaderMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div>
+			</form>
+		</div>
+		<div class="advanced-option-favicon">
+			<form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="favicon">
+				<input type="hidden" id="theming-faviconMime" value="<?php p($_['images']['favicon']['mime']); ?>" />
+				<input type="hidden" name="key" value="favicon" />
+				<label for="upload-login-favicon"><span><?php p($l->t('Favicon')) ?></span></label>
+				<input id="upload-login-favicon" class="fileupload" name="image" type="file">
+				<label for="upload-login-favicon" class="button icon-upload svg" id="upload-login-favicon" title="<?php p($l->t("Upload new favion")) ?>"></label>
+				<div class="image-preview"></div>
+				<div data-setting="faviconMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div>
+			</form>
+		</div>
+	</div>
+
 	<div class="theming-hints">
 		<?php if (!$_['canThemeIcons']) { ?>
 			<p class="info">
diff --git a/apps/theming/tests/Controller/IconControllerTest.php b/apps/theming/tests/Controller/IconControllerTest.php
index d92677e1f84a8c5af5cac6b94aad4f8e43dc41c2..6539c6e02099da1fdb602e369367804100519aa1 100644
--- a/apps/theming/tests/Controller/IconControllerTest.php
+++ b/apps/theming/tests/Controller/IconControllerTest.php
@@ -33,7 +33,6 @@ use OCA\Theming\ImageManager;
 use OCA\Theming\ThemingDefaults;
 use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataDisplayResponse;
-use OCP\AppFramework\Http\NotFoundResponse;
 use OCP\Files\NotFoundException;
 use OCP\IConfig;
 use OCP\IRequest;
@@ -41,6 +40,7 @@ use Test\TestCase;
 use OCA\Theming\Util;
 use OCA\Theming\Controller\IconController;
 use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\AppFramework\Utility\ITimeFactory;
 
 
 class IconControllerTest extends TestCase {
@@ -48,8 +48,6 @@ class IconControllerTest extends TestCase {
 	private $request;
 	/** @var ThemingDefaults|\PHPUnit_Framework_MockObject_MockObject */
 	private $themingDefaults;
-	/** @var Util */
-	private $util;
 	/** @var \OCP\AppFramework\Utility\ITimeFactory */
 	private $timeFactory;
 	/** @var IconController|\PHPUnit_Framework_MockObject_MockObject */
@@ -64,18 +62,11 @@ class IconControllerTest extends TestCase {
 	private $imageManager;
 
 	public function setUp() {
-		$this->request = $this->getMockBuilder(IRequest::class)->getMock();
-		$this->themingDefaults = $this->getMockBuilder('OCA\Theming\ThemingDefaults')
-			->disableOriginalConstructor()->getMock();
-		$this->util = $this->getMockBuilder('\OCA\Theming\Util')->disableOriginalConstructor()
-			->setMethods(['getAppImage', 'getAppIcon', 'elementColor'])->getMock();
-		$this->timeFactory = $this->getMockBuilder('OCP\AppFramework\Utility\ITimeFactory')
-			->disableOriginalConstructor()
-			->getMock();
-		$this->config = $this->getMockBuilder(IConfig::class)->getMock();
-		$this->iconBuilder = $this->getMockBuilder('OCA\Theming\IconBuilder')
-			->disableOriginalConstructor()->getMock();
-		$this->imageManager = $this->getMockBuilder('OCA\Theming\ImageManager')->disableOriginalConstructor()->getMock();
+		$this->request = $this->createMock(IRequest::class);
+		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
+		$this->timeFactory = $this->createMock(ITimeFactory::class);
+		$this->iconBuilder = $this->createMock(IconBuilder::class);
+		$this->imageManager = $this->createMock(ImageManager::class);
 		$this->fileAccessHelper = $this->createMock(FileAccessHelper::class);
 		$this->timeFactory->expects($this->any())
 			->method('getTime')
@@ -85,9 +76,7 @@ class IconControllerTest extends TestCase {
 			'theming',
 			$this->request,
 			$this->themingDefaults,
-			$this->util,
 			$this->timeFactory,
-			$this->config,
 			$this->iconBuilder,
 			$this->imageManager,
 			$this->fileAccessHelper
@@ -129,18 +118,21 @@ class IconControllerTest extends TestCase {
 		if (count($checkImagick->queryFormats('SVG')) < 1) {
 			$this->markTestSkipped('No SVG provider present.');
 		}
+		$file = $this->iconFileMock('filename', 'filecontent');
+		$this->imageManager->expects($this->once())
+			->method('getImage')
+			->with('favicon')
+			->will($this->throwException(new NotFoundException()));
 		$this->themingDefaults->expects($this->any())
 			->method('shouldReplaceIcons')
 			->willReturn(true);
-
+		$this->imageManager->expects($this->once())
+			->method('getCachedImage')
+			->will($this->throwException(new NotFoundException()));
 		$this->iconBuilder->expects($this->once())
 			->method('getFavicon')
 			->with('core')
 			->willReturn('filecontent');
-		$file = $this->iconFileMock('filename', 'filecontent');
-		$this->imageManager->expects($this->once())
-			->method('getCachedImage')
-			->will($this->throwException(new NotFoundException()));
 		$this->imageManager->expects($this->once())
 			->method('setCachedImage')
 			->willReturn($file);
@@ -156,6 +148,10 @@ class IconControllerTest extends TestCase {
 	}
 
 	public function testGetFaviconFail() {
+		$this->imageManager->expects($this->once())
+			->method('getImage')
+			->with('favicon')
+			->will($this->throwException(new NotFoundException()));
 		$this->themingDefaults->expects($this->any())
 			->method('shouldReplaceIcons')
 			->willReturn(false);
@@ -209,6 +205,10 @@ class IconControllerTest extends TestCase {
 	}
 
 	public function testGetTouchIconFail() {
+		$this->imageManager->expects($this->once())
+			->method('getImage')
+			->with('favicon')
+			->will($this->throwException(new NotFoundException()));
 		$this->themingDefaults->expects($this->any())
 			->method('shouldReplaceIcons')
 			->willReturn(false);
diff --git a/apps/theming/tests/Controller/ThemingControllerTest.php b/apps/theming/tests/Controller/ThemingControllerTest.php
index 08af13f994b34bc2b08c6d3f5aa2095ca802f8fe..dda881525f0ca5d5225c9780f3244f50714babed 100644
--- a/apps/theming/tests/Controller/ThemingControllerTest.php
+++ b/apps/theming/tests/Controller/ThemingControllerTest.php
@@ -34,6 +34,7 @@ use OC\Files\AppData\Factory;
 use OC\L10N\L10N;
 use OC\Template\SCSSCacher;
 use OCA\Theming\Controller\ThemingController;
+use OCA\Theming\ImageManager;
 use OCA\Theming\Util;
 use OCP\App\IAppManager;
 use OCP\AppFramework\Http;
@@ -74,6 +75,8 @@ class ThemingControllerTest extends TestCase {
 	private $appManager;
 	/** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
 	private $appData;
+	/** @var ImageManager|\PHPUnit_Framework_MockObject_MockObject */
+	private $imageManager;
 	/** @var SCSSCacher */
 	private $scssCacher;
 	/** @var IURLGenerator */
@@ -94,6 +97,7 @@ class ThemingControllerTest extends TestCase {
 		$this->tempManager = \OC::$server->getTempManager();
 		$this->scssCacher = $this->createMock(SCSSCacher::class);
 		$this->urlGenerator = $this->createMock(IURLGenerator::class);
+		$this->imageManager = $this->createMock(ImageManager::class);
 
 		$this->themingController = new ThemingController(
 			'theming',
@@ -107,7 +111,8 @@ class ThemingControllerTest extends TestCase {
 			$this->appData,
 			$this->scssCacher,
 			$this->urlGenerator,
-			$this->appManager
+			$this->appManager,
+			$this->imageManager
 		);
 
 		return parent::setUp();
@@ -211,17 +216,12 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('logo');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
-			->willReturn(null);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
+			->with('image')
 			->willReturn(null);
 		$this->l10n
 			->expects($this->any())
@@ -241,30 +241,25 @@ class ThemingControllerTest extends TestCase {
 			Http::STATUS_UNPROCESSABLE_ENTITY
 		);
 
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	public function testUpdateLogoInvalidMimeType() {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('logo');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
+			->with('image')
 			->willReturn([
 				'tmp_name' => 'logo.pdf',
 				'type' => 'application/pdf',
 				'name' => 'logo.pdf',
 				'error' => 0,
 			]);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
-			->willReturn(null);
 		$this->l10n
 			->expects($this->any())
 			->method('t')
@@ -290,30 +285,7 @@ class ThemingControllerTest extends TestCase {
 			Http::STATUS_UNPROCESSABLE_ENTITY
 		);
 
-		$this->assertEquals($expected, $this->themingController->updateLogo());
-	}
-
-	public function testUpdateBackgroundColor() {
-		$this->request
-			->expects($this->at(0))
-			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(true);
-		$this->themingDefaults
-			->expects($this->once())
-			->method('set')
-			->with('backgroundMime', 'backgroundColor');
-		$expected = new DataResponse(
-			[
-				'data' =>
-					[
-						'name' => 'backgroundColor',
-						'message' => $this->l10n->t('Saved')
-					],
-				'status' => 'success'
-			]
-		);
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	public function dataUpdateImages() {
@@ -336,23 +308,18 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('logo');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
+			->with('image')
 			->willReturn([
 				'tmp_name' => $tmpLogo,
 				'type' => $mimeType,
 				'name' => 'logo.svg',
 				'error' => 0,
 			]);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
-			->willReturn(null);
 		$this->l10n
 			->expects($this->any())
 			->method('t')
@@ -385,18 +352,27 @@ class ThemingControllerTest extends TestCase {
 			->method('newFile')
 			->with('logo')
 			->willReturn($file);
+		$this->urlGenerator->expects($this->once())
+			->method('linkTo')
+			->willReturn('serverCss');
+		$this->imageManager->expects($this->once())
+			->method('getImageUrl')
+			->with('logo')
+			->willReturn('imageUrl');
 		$expected = new DataResponse(
 			[
 				'data' =>
 					[
 						'name' => 'logo.svg',
 						'message' => 'Saved',
+						'url' => 'imageUrl',
+						'serverCssUrl' => 'serverCss'
 					],
 				'status' => 'success'
 			]
 		);
 
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	/** @dataProvider dataUpdateImages */
@@ -408,17 +384,12 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('background');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
-			->willReturn(null);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
+			->with('image')
 			->willReturn([
 				'tmp_name' => $tmpLogo,
 				'type' => 'text/svg',
@@ -457,17 +428,26 @@ class ThemingControllerTest extends TestCase {
 			->with('background')
 			->willReturn($file);
 
+		$this->urlGenerator->expects($this->once())
+			->method('linkTo')
+			->willReturn('serverCss');
+		$this->imageManager->expects($this->once())
+			->method('getImageUrl')
+			->with('background')
+			->willReturn('imageUrl');
 		$expected = new DataResponse(
 			[
 				'data' =>
 					[
 						'name' => 'logo.svg',
 						'message' => 'Saved',
+						'url' => 'imageUrl',
+						'serverCssUrl' => 'serverCss'
 					],
 				'status' => 'success'
 			]
 		);
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	public function testUpdateLogoLoginScreenUploadWithInvalidImage() {
@@ -478,20 +458,15 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('logo');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
-			->willReturn(null);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
+			->with('image')
 			->willReturn([
 				'tmp_name' => $tmpLogo,
-				'type' => 'text/svg',
+				'type' => 'foobar',
 				'name' => 'logo.svg',
 				'error' => 0,
 			]);
@@ -519,7 +494,7 @@ class ThemingControllerTest extends TestCase {
 			],
 			Http::STATUS_UNPROCESSABLE_ENTITY
 		);
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	public function dataPhpUploadErrors() {
@@ -541,17 +516,12 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('background');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
-			->willReturn(null);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
+			->with('image')
 			->willReturn([
 				'tmp_name' => '',
 				'type' => 'text/svg',
@@ -575,7 +545,7 @@ class ThemingControllerTest extends TestCase {
 			],
 			Http::STATUS_UNPROCESSABLE_ENTITY
 		);
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	/**
@@ -585,23 +555,18 @@ class ThemingControllerTest extends TestCase {
 		$this->request
 			->expects($this->at(0))
 			->method('getParam')
-			->with('backgroundColor')
-			->willReturn(false);
+			->with('key')
+			->willReturn('background');
 		$this->request
 			->expects($this->at(1))
 			->method('getUploadedFile')
-			->with('uploadlogo')
+			->with('image')
 			->willReturn([
 				'tmp_name' => '',
 				'type' => 'text/svg',
 				'name' => 'logo.svg',
 				'error' => $error,
 			]);
-		$this->request
-			->expects($this->at(2))
-			->method('getUploadedFile')
-			->with('upload-login-background')
-			->willReturn(null);
 		$this->l10n
 			->expects($this->any())
 			->method('t')
@@ -619,7 +584,7 @@ class ThemingControllerTest extends TestCase {
 			],
 			Http::STATUS_UNPROCESSABLE_ENTITY
 		);
-		$this->assertEquals($expected, $this->themingController->updateLogo());
+		$this->assertEquals($expected, $this->themingController->uploadImage());
 	}
 
 	public function testUndo() {
@@ -687,21 +652,9 @@ class ThemingControllerTest extends TestCase {
 			->method('linkTo')
 			->with('', '/core/css/someHash-server.scss')
 			->willReturn('/nextcloudWebroot/core/css/someHash-server.scss');
-		$folder = $this->createMock(ISimpleFolder::class);
-		$file = $this->createMock(ISimpleFile::class);
-		$this->appData
-			->expects($this->once())
-			->method('getFolder')
-			->with('images')
-			->willReturn($folder);
-		$folder
-			->expects($this->once())
-			->method('getFile')
-			->with($filename)
-			->willReturn($file);
-		$file
-			->expects($this->once())
-			->method('delete');
+		$this->imageManager->expects($this->once())
+			->method('delete')
+			->with($filename);
 
 		$expected = new DataResponse(
 			[
@@ -720,27 +673,19 @@ class ThemingControllerTest extends TestCase {
 
 
 	public function testGetLogoNotExistent() {
-		$this->appData->method('getFolder')
-			->with($this->equalTo('images'))
+		$this->imageManager->method('getImage')
+			->with($this->equalTo('logo'))
 			->willThrowException(new NotFoundException());
 
 		$expected = new Http\NotFoundResponse();
-		$this->assertEquals($expected, $this->themingController->getLogo());
+		$this->assertEquals($expected, $this->themingController->getImage('logo'));
 	}
 
 	public function testGetLogo() {
 		$file = $this->createMock(ISimpleFile::class);
-		$folder = $this->createMock(ISimpleFolder::class);
-		$this->appData
-			->expects($this->once())
-			->method('getFolder')
-			->with('images')
-			->willReturn($folder);
-		$folder->expects($this->once())
-			->method('getFile')
-			->with('logo')
+		$this->imageManager->expects($this->once())
+			->method('getImage')
 			->willReturn($file);
-
 		$this->config
 			->expects($this->once())
 			->method('getAppValue')
@@ -755,29 +700,22 @@ class ThemingControllerTest extends TestCase {
 		$expected->addHeader('Expires', $expires->format(\DateTime::RFC2822));
 		$expected->addHeader('Pragma', 'cache');
 		$expected->addHeader('Content-Type', 'text/svg');
-		@$this->assertEquals($expected, $this->themingController->getLogo());
+		@$this->assertEquals($expected, $this->themingController->getImage('logo'));
 	}
 
 
 	public function testGetLoginBackgroundNotExistent() {
-		$this->appData->method('getFolder')
-			->with($this->equalTo('images'))
+		$this->imageManager->method('getImage')
+			->with($this->equalTo('background'))
 			->willThrowException(new NotFoundException());
 		$expected = new Http\NotFoundResponse();
-		$this->assertEquals($expected, $this->themingController->getLoginBackground());
+		$this->assertEquals($expected, $this->themingController->getImage('background'));
 	}
 
 	public function testGetLoginBackground() {
 		$file = $this->createMock(ISimpleFile::class);
-		$folder = $this->createMock(ISimpleFolder::class);
-		$this->appData
-			->expects($this->once())
-			->method('getFolder')
-			->with('images')
-			->willReturn($folder);
-		$folder->expects($this->once())
-			->method('getFile')
-			->with('background')
+		$this->imageManager->expects($this->once())
+			->method('getImage')
 			->willReturn($file);
 
 		$this->config
@@ -794,7 +732,7 @@ class ThemingControllerTest extends TestCase {
 		$expected->addHeader('Expires', $expires->format(\DateTime::RFC2822));
 		$expected->addHeader('Pragma', 'cache');
 		$expected->addHeader('Content-Type', 'image/png');
-		@$this->assertEquals($expected, $this->themingController->getLoginBackground());
+		@$this->assertEquals($expected, $this->themingController->getImage('background'));
 	}
 
 
diff --git a/apps/theming/tests/ImageManagerTest.php b/apps/theming/tests/ImageManagerTest.php
index 6c0b31528fce93c3bc02e7bbb5c331cfdfc09f39..4e258ce7162ce1effe4bef93b93e5541ea7b38d3 100644
--- a/apps/theming/tests/ImageManagerTest.php
+++ b/apps/theming/tests/ImageManagerTest.php
@@ -23,14 +23,16 @@
  */
 namespace OCA\Theming\Tests;
 
+use OCA\Theming\ImageManager;
 use OCP\Files\SimpleFS\ISimpleFile;
 use OCP\IConfig;
+use OCP\IURLGenerator;
 use Test\TestCase;
 use OCP\Files\SimpleFS\ISimpleFolder;
 use OCP\Files\IAppData;
 use OCP\Files\NotFoundException;
 
-class ImageManager extends TestCase {
+class ImageManagerTest extends TestCase {
 
 	/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
 	protected $config;
@@ -38,17 +40,112 @@ class ImageManager extends TestCase {
 	protected $appData;
 	/** @var ImageManager */
 	protected $imageManager;
+	/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
+	private $urlGenerator;
 
 	protected function setUp() {
 		parent::setUp();
-		$this->config = $this->getMockBuilder(IConfig::class)->getMock();
-		$this->appData = $this->getMockBuilder('OCP\Files\IAppData')->getMock();
-		$this->imageManager = new \OCA\Theming\ImageManager(
+		$this->config = $this->createMock(IConfig::class);
+		$this->appData = $this->createMock(IAppData::class);
+		$this->urlGenerator = $this->createMock(IURLGenerator::class);
+		$this->imageManager = new ImageManager(
 			$this->config,
-			$this->appData
+			$this->appData,
+			$this->urlGenerator
 		);
 	}
 
+	public function mockGetImage($key, $file) {
+		/** @var \PHPUnit_Framework_MockObject_MockObject $folder */
+		$folder = $this->createMock(ISimpleFolder::class);
+		if ($file === null) {
+			$folder->expects($this->once())
+				->method('getFile')
+				->with('logo')
+				->willThrowException(new NotFoundException());
+		} else {
+			$folder->expects($this->once())
+				->method('getFile')
+				->with('logo')
+				->willReturn($file);
+			$this->appData->expects($this->once())
+				->method('getFolder')
+				->with('images')
+				->willReturn($folder);
+		}
+	}
+
+	public function testGetImageUrl() {
+		$file = $this->createMock(ISimpleFile::class);
+		$this->config->expects($this->exactly(2))
+			->method('getAppValue')
+			->withConsecutive(
+				['theming', 'cachebuster', '0'],
+				['theming', 'logoMime', false]
+				)
+			->willReturn(0);
+		$this->mockGetImage('logo', $file);
+		$this->urlGenerator->expects($this->once())
+			->method('linkToRoute')
+			->willReturn('url-to-image');
+		$this->assertEquals('url-to-image?v=0', $this->imageManager->getImageUrl('logo'));
+	}
+
+	public function testGetImageUrlDefault() {
+		$this->config->expects($this->exactly(2))
+			->method('getAppValue')
+			->withConsecutive(
+				['theming', 'cachebuster', '0'],
+				['theming', 'logoMime', false]
+			)
+			->willReturnOnConsecutiveCalls(0, false);
+		$this->urlGenerator->expects($this->once())
+			->method('imagePath')
+			->with('core', 'logo.png')
+			->willReturn('logo.png');
+		$this->assertEquals('logo.png?v=0', $this->imageManager->getImageUrl('logo'));
+	}
+
+	public function testGetImageUrlAbsolute() {
+		$file = $this->createMock(ISimpleFile::class);
+		$this->config->expects($this->exactly(2))
+			->method('getAppValue')
+			->withConsecutive(
+				['theming', 'cachebuster', '0'],
+				['theming', 'logoMime', false]
+			)
+			->willReturn(0);
+		$this->mockGetImage('logo', $file);
+		$this->urlGenerator->expects($this->at(0))
+			->method('linkToRoute')
+			->willReturn('url-to-image');
+		$this->urlGenerator->expects($this->at(1))
+			->method('getAbsoluteUrl')
+			->with('url-to-image?v=0')
+			->willReturn('url-to-image-absolute?v=0');
+		$this->assertEquals('url-to-image-absolute?v=0', $this->imageManager->getImageUrlAbsolute('logo'));
+
+	}
+
+	public function testGetImage() {
+		$this->config->expects($this->once())
+			->method('getAppValue')->with('theming', 'logoMime', false)
+			->willReturn('png');
+		$file = $this->createMock(ISimpleFile::class);
+		$this->mockGetImage('logo', $file);
+		$this->assertEquals($file, $this->imageManager->getImage('logo'));
+	}
+
+	/**
+	 * @expectedException OCP\Files\NotFoundException
+	 */
+	public function testGetImageUnset() {
+		$this->config->expects($this->once())
+			->method('getAppValue')->with('theming', 'logoMime', false)
+			->willReturn(false);
+		$this->imageManager->getImage('logo');
+	}
+
 	public function testGetCacheFolder() {
 		$folder = $this->createMock(ISimpleFolder::class);
 		$this->config->expects($this->once())
@@ -85,12 +182,12 @@ class ImageManager extends TestCase {
 	}
 
 	public function testGetCachedImage() {
+		$expected = $this->createMock(ISimpleFile::class);
 		$folder = $this->setupCacheFolder();
 		$folder->expects($this->once())
 			->method('getFile')
 			->with('filename')
-			->willReturn('filecontent');
-		$expected = 'filecontent';
+			->willReturn($expected);
 		$this->assertEquals($expected, $this->imageManager->getCachedImage('filename'));
 	}
 
diff --git a/apps/theming/tests/Settings/AdminTest.php b/apps/theming/tests/Settings/AdminTest.php
index ee49cf0f1f67d7421e68c833817de59eac830ebf..4eac689fb3ff86f48eccd93a732c48e0435496f1 100644
--- a/apps/theming/tests/Settings/AdminTest.php
+++ b/apps/theming/tests/Settings/AdminTest.php
@@ -27,6 +27,7 @@
 
 namespace OCA\Theming\Tests\Settings;
 
+use OCA\Theming\ImageManager;
 use OCA\Theming\Settings\Admin;
 use OCA\Theming\ThemingDefaults;
 use OCP\AppFramework\Http\TemplateResponse;
@@ -44,21 +45,25 @@ class AdminTest extends TestCase {
 	private $themingDefaults;
 	/** @var IURLGenerator */
 	private $urlGenerator;
+	/** @var ImageManager */
+	private $imageManager;
 	/** @var IL10N */
 	private $l10n;
 
 	public function setUp() {
 		parent::setUp();
-		$this->config = $this->getMockBuilder(IConfig::class)->getMock();
-		$this->l10n = $this->getMockBuilder(IL10N::class)->getMock();
-		$this->themingDefaults = $this->getMockBuilder('\OCA\Theming\ThemingDefaults')->disableOriginalConstructor()->getMock();
-		$this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock();
+		$this->config = $this->createMock(IConfig::class);
+		$this->l10n = $this->createMock(IL10N::class);
+		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
+		$this->urlGenerator = $this->createMock(IURLGenerator::class);
+		$this->imageManager = $this->createMock(ImageManager::class);
 
 		$this->admin = new Admin(
 			$this->config,
 			$this->l10n,
 			$this->themingDefaults,
-			$this->urlGenerator
+			$this->urlGenerator,
+			$this->imageManager
 		);
 	}
 
@@ -87,7 +92,7 @@ class AdminTest extends TestCase {
 		$this->urlGenerator
 			->expects($this->once())
 			->method('linkToRoute')
-			->with('theming.Theming.updateLogo')
+			->with('theming.Theming.uploadImage')
 			->willReturn('/my/route');
 		$params = [
 			'themable' => true,
@@ -97,12 +102,9 @@ class AdminTest extends TestCase {
 			'slogan' => 'MySlogan',
 			'color' => '#fff',
 			'uploadLogoRoute' => '/my/route',
-			'logo' => null,
-			'logoMime' => null,
-			'background' => null,
-			'backgroundMime' => null,
 			'canThemeIcons' => null,
 			'iconDocs' => null,
+			'images' => [],
 		];
 
 		$expected = new TemplateResponse('theming', 'settings-admin', $params, '');
@@ -139,7 +141,7 @@ class AdminTest extends TestCase {
 		$this->urlGenerator
 			->expects($this->once())
 			->method('linkToRoute')
-			->with('theming.Theming.updateLogo')
+			->with('theming.Theming.uploadImage')
 			->willReturn('/my/route');
 		$params = [
 			'themable' => false,
@@ -149,12 +151,9 @@ class AdminTest extends TestCase {
 			'slogan' => 'MySlogan',
 			'color' => '#fff',
 			'uploadLogoRoute' => '/my/route',
-			'logo' => null,
-			'logoMime' => null,
-			'background' => null,
-			'backgroundMime' => null,
 			'canThemeIcons' => null,
-			'iconDocs' => null,
+			'iconDocs' => '',
+			'images' => [],
 		];
 
 		$expected = new TemplateResponse('theming', 'settings-admin', $params, '');
diff --git a/apps/theming/tests/ThemingDefaultsTest.php b/apps/theming/tests/ThemingDefaultsTest.php
index 2485a471bf46e84d34193d42dfef1816cb09ddf3..c943af01c6c514e1bff51f503183c93dc6fdfecd 100644
--- a/apps/theming/tests/ThemingDefaultsTest.php
+++ b/apps/theming/tests/ThemingDefaultsTest.php
@@ -29,6 +29,7 @@
  */
 namespace OCA\Theming\Tests;
 
+use OCA\Theming\ImageManager;
 use OCA\Theming\ThemingDefaults;
 use OCP\App\IAppManager;
 use OCP\Files\IAppData;
@@ -64,30 +65,31 @@ class ThemingDefaultsTest extends TestCase {
 	private $cache;
 	/** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */
 	private $appManager;
+	/** @var ImageManager|\PHPUnit_Framework_MockObject_MockObject */
+	private $imageManager;
 
 	public function setUp() {
 		parent::setUp();
 		$this->config = $this->createMock(IConfig::class);
 		$this->l10n = $this->createMock(IL10N::class);
 		$this->urlGenerator = $this->createMock(IURLGenerator::class);
-		$this->appData = $this->createMock(IAppData::class);
 		$this->cacheFactory = $this->createMock(ICacheFactory::class);
 		$this->cache = $this->createMock(ICache::class);
 		$this->util = $this->createMock(Util::class);
+		$this->imageManager = $this->createMock(ImageManager::class);
 		$this->appManager = $this->createMock(IAppManager::class);
 		$this->defaults = new \OC_Defaults();
-		$this->cacheFactory
+		$this->urlGenerator
 			->expects($this->any())
-			->method('createDistributed')
-			->with('theming-')
-			->willReturn($this->cache);
+			->method('getBaseUrl')
+			->willReturn('');
 		$this->template = new ThemingDefaults(
 			$this->config,
 			$this->l10n,
 			$this->urlGenerator,
-			$this->appData,
 			$this->cacheFactory,
 			$this->util,
+			$this->imageManager,
 			$this->appManager
 		);
 	}
@@ -273,8 +275,18 @@ class ThemingDefaultsTest extends TestCase {
 			->expects($this->at(2))
 			->method('setAppValue')
 			->with('theming', 'cachebuster', 16);
+		$this->cacheFactory
+			->expects($this->at(0))
+			->method('createDistributed')
+			->with('theming-')
+			->willReturn($this->cache);
+		$this->cacheFactory
+			->expects($this->at(1))
+			->method('createDistributed')
+			->with('imagePath')
+			->willReturn($this->cache);
 		$this->cache
-			->expects($this->once())
+			->expects($this->any())
 			->method('clear')
 			->with('');
 		$this->template->set('MySetting', 'MyValue');
@@ -390,41 +402,19 @@ class ThemingDefaultsTest extends TestCase {
 		$this->assertSame('', $this->template->undo('defaultitem'));
 	}
 
-	public function testGetBackgroundDefault() {
-		$this->config
+	public function testGetBackground() {
+		$this->imageManager
 			->expects($this->once())
-			->method('getAppValue')
-			->with('theming', 'cachebuster', '0')
-			->willReturn('0');
-		$this->util->expects($this->once())
-			->method('isBackgroundThemed')
-			->willReturn(false);
-		$this->urlGenerator->expects($this->once())
-			->method('imagePath')
-			->with('core', 'background.png')
-			->willReturn('core-background');
-		$this->assertEquals('core-background?v=0', $this->template->getBackground());
-	}
-
-	public function testGetBackgroundCustom() {
-		$this->config
-			->expects($this->once())
-			->method('getAppValue')
-			->with('theming', 'cachebuster', '0')
-			->willReturn('0');
-		$this->util->expects($this->once())
-			->method('isBackgroundThemed')
-			->willReturn(true);
-		$this->urlGenerator->expects($this->once())
-			->method('linkToRoute')
-			->with('theming.Theming.getLoginBackground')
-			->willReturn('custom-background');
+			->method('getImageUrl')
+			->with('background')
+			->willReturn('custom-background?v=0');
 		$this->assertEquals('custom-background?v=0', $this->template->getBackground());
 	}
 
 	private function getLogoHelper($withName, $useSvg) {
-		$this->appData->expects($this->once())
-			->method('getFolder')
+		$this->imageManager->expects($this->any())
+			->method('getImage')
+			->with('logo')
 			->willThrowException(new NotFoundException());
 		$this->config
 			->expects($this->at(0))
@@ -436,11 +426,6 @@ class ThemingDefaultsTest extends TestCase {
 			->method('getAppValue')
 			->with('theming', 'cachebuster', '0')
 			->willReturn('0');
-		$this->appData
-			->expects($this->once())
-			->method('getFolder')
-			->with('images')
-			->willThrowException(new \Exception());
 		$this->urlGenerator->expects($this->once())
 			->method('imagePath')
 			->with('core', $withName)
@@ -457,14 +442,11 @@ class ThemingDefaultsTest extends TestCase {
 	}
 
 	public function testGetLogoCustom() {
-		$folder = $this->createMock(ISimpleFolder::class);
 		$file = $this->createMock(ISimpleFile::class);
-		$folder->expects($this->once())
-			->method('getFile')
+		$this->imageManager->expects($this->once())
+			->method('getImage')
+			->with('logo')
 			->willReturn($file);
-		$this->appData->expects($this->once())
-			->method('getFolder')
-			->willReturn($folder);
 		$this->config
 			->expects($this->at(0))
 			->method('getAppValue')
@@ -477,12 +459,16 @@ class ThemingDefaultsTest extends TestCase {
 			->willReturn('0');
 		$this->urlGenerator->expects($this->once())
 			->method('linkToRoute')
-			->with('theming.Theming.getLogo')
+			->with('theming.Theming.getImage')
 			->willReturn('custom-logo');
 		$this->assertEquals('custom-logo' . '?v=0', $this->template->getLogo());
 	}
 
 	public function testGetScssVariablesCached() {
+		$this->cacheFactory->expects($this->once())
+			->method('createDistributed')
+			->with('theming-')
+			->willReturn($this->cache);
 		$this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(['foo'=>'bar']);
 		$this->assertEquals(['foo'=>'bar'], $this->template->getScssVariables());
 	}
@@ -491,31 +477,25 @@ class ThemingDefaultsTest extends TestCase {
 		$this->config->expects($this->at(0))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0');
 		$this->config->expects($this->at(1))->method('getAppValue')->with('theming', 'logoMime', false)->willReturn('jpeg');
 		$this->config->expects($this->at(2))->method('getAppValue')->with('theming', 'backgroundMime', false)->willReturn('jpeg');
-		$this->config->expects($this->at(3))->method('getAppValue')->with('theming', 'logoMime', false)->willReturn('jpeg');
-		$this->config->expects($this->at(4))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0');
-		$this->util->expects($this->once())->method('isBackgroundThemed')->willReturn(true);
-		$this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0');
-		$this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary());
+		$this->config->expects($this->at(3))->method('getAppValue')->with('theming', 'logoheaderMime', false)->willReturn('jpeg');
+		$this->config->expects($this->at(4))->method('getAppValue')->with('theming', 'faviconMime', false)->willReturn('jpeg');
+
+		$this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary());
+		$this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary());
 		$this->config->expects($this->at(7))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary());
 		$this->config->expects($this->at(8))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary());
-		$this->config->expects($this->at(9))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary());
 
 		$this->util->expects($this->any())->method('invertTextColor')->with($this->defaults->getColorPrimary())->willReturn(false);
 		$this->util->expects($this->any())->method('elementColor')->with($this->defaults->getColorPrimary())->willReturn('#aaaaaa');
+		$this->cacheFactory->expects($this->once())
+			->method('createDistributed')
+			->with('theming-')
+			->willReturn($this->cache);
 		$this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(null);
-		$folder = $this->createMock(ISimpleFolder::class);
-		$file = $this->createMock(ISimpleFile::class);
-		$folder->expects($this->any())->method('getFile')->willReturn($file);
-		$this->appData->expects($this->any())
-			->method('getFolder')
-			->willReturn($folder);
-
-		$this->urlGenerator->expects($this->exactly(2))
-			->method('linkToRoute')
-			->willReturnMap([
-				['theming.Theming.getLogo', [], 'custom-logo'],
-				['theming.Theming.getLoginBackground', [], 'custom-background'],
-			]);
+		$this->imageManager->expects($this->at(0))->method('getImageUrl')->with('logo')->willReturn('custom-logo?v=0');
+		$this->imageManager->expects($this->at(1))->method('getImageUrl')->with('logoheader')->willReturn('custom-logoheader?v=0');
+		$this->imageManager->expects($this->at(2))->method('getImageUrl')->with('favicon')->willReturn('custom-favicon?v=0');
+		$this->imageManager->expects($this->at(3))->method('getImageUrl')->with('background')->willReturn('custom-background?v=0');
 
 		$expected = [
 			'theming-cachebuster' => '\'0\'',
@@ -526,8 +506,11 @@ class ThemingDefaultsTest extends TestCase {
 			'color-primary' => $this->defaults->getColorPrimary(),
 			'color-primary-text' => '#ffffff',
 			'image-login-plain' => 'false',
-			'color-primary-element' => '#aaaaaa'
-
+			'color-primary-element' => '#aaaaaa',
+			'theming-logoheader-mime' => '\'jpeg\'',
+			'theming-favicon-mime' => '\'jpeg\'',
+			'image-logoheader' => '\'custom-logoheader?v=0\'',
+			'image-favicon' => '\'custom-favicon?v=0\''
 		];
 		$this->assertEquals($expected, $this->template->getScssVariables());
 	}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index fd32b09033eb978857a66aab873384c6d68179ad..3786486c2b240c90804fde93ef476e83de40c667 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -114,6 +114,7 @@ use OC\SystemTag\ManagerFactory as SystemTagManagerFactory;
 use OC\Tagging\TagMapper;
 use OC\Template\JSCombiner;
 use OC\Template\SCSSCacher;
+use OCA\Theming\ImageManager;
 use OCA\Theming\ThemingDefaults;
 
 use OCP\App\IAppManager;
@@ -943,10 +944,10 @@ class Server extends ServerContainer implements IServerContainer {
 					$c->getConfig(),
 					$c->getL10N('theming'),
 					$c->getURLGenerator(),
-					$c->getAppDataDir('theming'),
 					$c->getMemCacheFactory(),
-					new Util($c->getConfig(), $this->getAppManager(), $this->getAppDataDir('theming')),
-					$this->getAppManager()
+					new Util($c->getConfig(), $this->getAppManager(), $c->getAppDataDir('theming')),
+					new ImageManager($c->getConfig(), $c->getAppDataDir('theming'), $c->getURLGenerator()),
+					$c->getAppManager()
 				);
 			}
 			return new \OC_Defaults();