diff --git a/.gitignore b/.gitignore
index 97ab31d0b7c4ad9a0fc1efc9a4c86de3b475f7f8..81dec99469db91c4cfcaaee295928299d1e03e8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,10 +31,10 @@ public/pictures/banner/*.gif
 public/pictures/banner/*.jpeg
 public/pictures/banner/*.jpg
 public/pictures/banner/*.png
-public/pictures/course/[0-9a-f]*.png
-public/pictures/institute/[0-9a-f]*.png
 public/pictures/stock-images/*
-public/pictures/user/[0-9a-f]*.png
+public/pictures/course/*/*.webp
+public/pictures/institute/*/*.webp
+public/pictures/user/*/*.webp
 public/plugins_packages/*
 
 tests/_log
diff --git a/app/controllers/avatar.php b/app/controllers/avatar.php
index 992c06e1fa2641a5666179f28045939ab7392004..c549cf097593c000a7060cdbbd28f026321dcfa4 100644
--- a/app/controllers/avatar.php
+++ b/app/controllers/avatar.php
@@ -29,13 +29,13 @@ class AvatarController extends AuthenticatedController
             PageLayout::setTitle(_('Profilbild ändern'));
 
             $has_perm = $GLOBALS['perm']->have_profile_perm('user', $id);
-            $class = 'Avatar';
+            $class = Avatar::class;
             $this->cancel_link = $this->url_for('profile', ['username' => User::find($id)->username]);
         } else if ($type == 'institute') {
             PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Einrichtungsbild ändern'));
 
             $has_perm = $GLOBALS['perm']->have_studip_perm('admin', $id);
-            $class = 'InstituteAvatar';
+            $class = InstituteAvatar::class;
             $this->cancel_link = $this->url_for('institute/basicdata/index', ['cid' => $id]);
         } else {
             PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Veranstaltungsbild ändern'));
@@ -44,10 +44,10 @@ class AvatarController extends AuthenticatedController
             $sem = Seminar::getInstance($id);
             $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode');
             if ($studygroup_mode) {
-                $class = 'StudygroupAvatar';
+                $class = StudygroupAvatar::class;
                 $this->cancel_link = $this->url_for('course/studygroup/edit?cid=' . $id);
             } else {
-                $class = 'CourseAvatar';
+                $class = CourseAvatar::class;
                 $this->cancel_link = $this->url_for('course/management?cid=' . $id);
             }
         }
@@ -56,20 +56,17 @@ class AvatarController extends AuthenticatedController
             throw new AccessDeniedException(_('Sie haben keine Berechtigung, das Bild zu ändern.'));
         }
 
-        if ($type == 'user') {
+        if ($type === 'user') {
             Navigation::activateItem('/profile/index');
-        } else if ($type == 'institute') {
+        } else if ($type === 'institute') {
             Navigation::activateItem('/admin/institute/details');
         } else {
             Navigation::activateItem('/course/admin/avatar');
         }
 
-        $this->customized = false;
         $avatar = $class::getAvatar($id);
         $this->avatar = $avatar->getURL($class::NORMAL);
-        if ($avatar->is_customized()) {
-            $this->customized = true;
-        }
+        $this->customized = $avatar->is_customized();
 
         $this->type = $type;
         $this->id = $id;
@@ -88,21 +85,21 @@ class AvatarController extends AuthenticatedController
         // Check for permission to save a new avatar.
         if ($type == 'user') {
             $has_perm = $GLOBALS['perm']->have_profile_perm('user', $id);
-            $class = 'Avatar';
+            $class = Avatar::class;
             $redirect = 'profile?username=' . User::find($id)->username;
         } else if ($type == 'institute') {
             $has_perm = $GLOBALS['perm']->have_studip_perm('admin', $id);
-            $class = 'InstituteAvatar';
+            $class = InstituteAvatar::class;
             $redirect = 'institute/basicdata/index';
         } else {
             $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id);
             $sem = Seminar::getInstance($id);
             $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode');
             if ($studygroup_mode) {
-                $class = 'StudygroupAvatar';
+                $class = StudygroupAvatar::class;
                 $redirect = 'course/studygroup/edit/?cid=' . $id;
             } else {
-                $class = 'CourseAvatar';
+                $class = CourseAvatar::class;
                 $redirect = 'course/management';
             }
         }
diff --git a/app/controllers/privacy.php b/app/controllers/privacy.php
index ee1f1574293b6b8ada0736f6e91c871ea0afbec9..ba8e6f1a004fe2338ec54180ad5f26d6c81aee0b 100644
--- a/app/controllers/privacy.php
+++ b/app/controllers/privacy.php
@@ -298,7 +298,7 @@ class PrivacyController extends AuthenticatedController
 
         $avatar = Avatar::getAvatar($user_id);
         if ($avatar->is_customized()) {
-            $zip->addFile($avatar->getCustomAvatarPath('normal'), $user_id . '.png');
+            $zip->addFile($avatar->getCustomAvatarPath('normal'), $user_id . '.webp');
         }
 
         foreach (FileRef::findByUser_id($user_id) as $fileref) {
diff --git a/app/routes/User.php b/app/routes/User.php
index 16de204f5fa5a6273d617c161242b11539f430bb..d3cce266c2014558739f1568dda015b1b43ef008 100644
--- a/app/routes/User.php
+++ b/app/routes/User.php
@@ -26,7 +26,7 @@ class User extends \RESTAPI\RouteMap
             'avatar_small'    => $avatar->getURL(\Avatar::SMALL),
             'avatar_medium'   => $avatar->getURL(\Avatar::MEDIUM),
             'avatar_normal'   => $avatar->getURL(\Avatar::NORMAL),
-            'avatar_original' => $avatar->getURL(\Avatar::ORIGINAL)
+            'avatar_original' => $avatar->getURL(\Avatar::NORMAL)
         ];
     }
 
@@ -118,7 +118,7 @@ class User extends \RESTAPI\RouteMap
             'avatar_small'    => $avatar->getURL(\Avatar::SMALL),
             'avatar_medium'   => $avatar->getURL(\Avatar::MEDIUM),
             'avatar_normal'   => $avatar->getURL(\Avatar::NORMAL),
-            'avatar_original' => $avatar->getURL(\Avatar::ORIGINAL),
+            'avatar_original' => $avatar->getURL(\Avatar::NORMAL),
             'phone'           => $get_field('privatnr', 'private_phone'),
             'homepage'        => $get_field('Home', 'homepage'),
             'privadr'         => strip_tags($get_field('privadr', 'privadr')),
diff --git a/app/views/admin/licenses/edit.php b/app/views/admin/licenses/edit.php
index ce722c26e01381e060864dabdd28276841ab65b0..63ac391edaf4600cf0d80d41ea9ce25cab561dd0 100644
--- a/app/views/admin/licenses/edit.php
+++ b/app/views/admin/licenses/edit.php
@@ -36,8 +36,8 @@
     </label>
 
     <label class="file-upload">
-        <?= _('Bild hochladen (PNG, JPG, GIF)') ?>
-        <input type="file" name="avatar" accept=".jpg,.png,.jpeg,.gif">
+        <?= _('Bild hochladen (PNG, JPG, GIF, WebP)') ?>
+        <input type="file" name="avatar" accept=".jpg,.png,.jpeg,.gif,.webp">
     </label>
 
     <label>
diff --git a/app/views/avatar/update.php b/app/views/avatar/update.php
index 777c0c7a9cd92148f57079800f03e182f24d2cd9..f995702536e256e4bae2e2f30cf0abfbe45f4fc1 100644
--- a/app/views/avatar/update.php
+++ b/app/views/avatar/update.php
@@ -1,5 +1,15 @@
+<?php
+/**
+ * @var AvatarController $controller
+ * @var string $type
+ * @var string $id
+ * @var string $avatar
+ * @var bool $customized
+ * @var string $cancel_link
+ */
+?>
 <form class="default settings-avatar" enctype="multipart/form-data"
-        action="<?= $controller->url_for('avatar/upload', $type, $id) ?>" method="post">
+        action="<?= $controller->link_for('avatar/upload', $type, $id) ?>" method="post">
     <fieldset>
         <legend>
             <?= $type == 'user' ? _('Profilbild bearbeiten und zuschneiden') :
@@ -8,20 +18,20 @@
         </legend>
         <div class="form-group">
             <div id="avatar-preview">
-                <img class="avatar-normal" id="new-avatar" src="<?= $avatar ?>"
+                <img class="avatar-normal" id="new-avatar" src="<?= htmlReady($avatar) ?>"
                      data-message-too-small="<?= _('Das Bild ist kleiner als 250 x 250 Pixel. Wollen Sie wirklich fortfahren?') ?>">
             </div>
 
             <label class="file-upload">
                 <?= _('Wählen Sie ein Bild von Ihrer Festplatte aus.') ?>
-                <input type="file" id="avatar-upload" accept="image/gif,image/png,image/jpeg"
+                <input type="file" id="avatar-upload" accept="image/gif,image/png,image/jpeg,image/webp"
                        capture="camera"
                        data-max-size="<?= Avatar::MAX_FILE_SIZE ?>"
                        data-message-too-large="<?= _('Die hochgeladene Datei ist zu groß. Bitte wählen Sie ein anderes Bild.') ?>">
 
                 <p class="form-text">
                     <?= sprintf(
-                        _('Die Bilddatei darf max. %s groß sein, es sind nur Dateien mit den Endungen .jpg, .png oder .gif erlaubt!'),
+                        _('Die Bilddatei darf max. %s groß sein, es sind nur Dateien mit den Endungen .jpg, .png, .gif und .webp erlaubt!'),
                         relsize(Avatar::MAX_FILE_SIZE)
                     ) ?>
                 </p>
diff --git a/db/migrations/5.5.10_convert_avatars_to_webp.php b/db/migrations/5.5.10_convert_avatars_to_webp.php
new file mode 100644
index 0000000000000000000000000000000000000000..cf120a03c4d81a9ce26e1f3e7f81405595098309
--- /dev/null
+++ b/db/migrations/5.5.10_convert_avatars_to_webp.php
@@ -0,0 +1,116 @@
+<?php
+final class ConvertAvatarsToWebp extends Migration
+{
+    const SIZES = [
+        'small'  => [
+            'default' => [25 * 2, 25 * 2],
+            'license' => [60 * 2, 20 * 2],
+        ],
+        'medium' => [
+            'default' => [100 * 2, 100 * 2],
+            'license' => [120 * 2, 40 * 2],
+        ],
+        'normal' => [
+            'default' => [250 * 2, 250 * 2],
+            'license' => [300 * 2, 100 * 2],
+        ],
+    ];
+
+    protected function up()
+    {
+        foreach (['user', 'course', 'institute', 'licenses'] as $type) {
+            $source_directory = $GLOBALS['DYNAMIC_CONTENT_PATH'] . '/' . $type;
+
+            // Convert original images
+            $iterator = new RegexIterator(
+                new FilesystemIterator($source_directory),
+                '/_original\.png$/i'
+            );
+            foreach ($iterator as $file) {
+                $this->convert($file, $type);
+            }
+
+            // Convert leftover images
+            $iterator = new RegexIterator(
+                new FilesystemIterator($source_directory),
+                '/_normal\.png$/i'
+            );
+            foreach ($iterator as $file) {
+                $this->convert($file, $type);
+            }
+        }
+    }
+
+    private function convert(
+        SplFileInfo $input_file,
+        string $type
+    ): void {
+        $input_image = imagecreatefromstring(file_get_contents($input_file->getPathname()));
+
+        if ($input_image === false) {
+            unlink($input_file->getPathname());
+            return;
+        }
+
+        $user_id = explode('_', $input_file->getBasename('.png'))[0];
+        $output_path = $input_file->getPath();
+        if ($type !== 'licenses') {
+            $output_path .= '/' . substr($user_id, 0, 2);
+        }
+        if (!is_dir($output_path)) {
+            mkdir($output_path);
+        }
+
+        imagepalettetotruecolor($input_image);
+        imagealphablending($input_image, false);
+        imagesavealpha($input_image, true);
+
+        $image_width = imagesx($input_image);
+        $image_height = imagesy($input_image);
+
+        foreach (array_keys(self::SIZES) as $size) {
+            [$width, $height] = self::SIZES[$size][$type] ?? self::SIZES[$size]['default'];
+            $output_file = "{$output_path}/{$user_id}_{$size}.webp";
+
+            $factor = min($width / $image_width, $height / $image_height);
+            $resized_width  = round($image_width * $factor);
+            $resized_height = round($image_height * $factor);
+
+            $xpos = intval($width - $resized_width) >> 1;
+            $ypos = intval($height - $resized_height) >> 1;
+
+            $output_image = $this->createNewImage($width, $height);
+
+            imagecopyresampled(
+                $output_image, $input_image,
+                $xpos, $ypos,
+                0, 0,
+                $resized_width, $resized_height,
+                $image_width, $image_height
+            );
+
+            imagewebp($output_image, $output_file, 90);
+            imagedestroy($output_image);
+        }
+
+        imagedestroy($input_image);
+
+        unlink($input_file->getPath() . '/' . $user_id . '_original.png');
+        foreach (array_keys(self::SIZES) as $size) {
+            unlink($input_file->getPath() . '/' . $user_id . '_' . $size . '.png');
+            unlink($input_file->getPath() . '/' . $user_id . '_' . $size . '@2x.png');
+        }
+    }
+
+    private function createNewImage(int $width, int $height)
+    {
+        $image = imagecreatetruecolor($width, $height);
+        imagealphablending($image, false);
+        imagesavealpha($image, false); // Otherwise, WebP won't store the alpha information
+
+        $transparent_color = imagecolorallocatealpha($image, 0, 0, 0, 127);
+        imagefill($image, 0, 0, $transparent_color);
+
+        return $image;
+    }
+}
diff --git a/lib/bootstrap.php b/lib/bootstrap.php
index e286e933ec315667a43c0011855f8cc3e02a0f2b..5690a60bd3f54a88e1db05ed9c8d886c91c9e80f 100644
--- a/lib/bootstrap.php
+++ b/lib/bootstrap.php
@@ -61,8 +61,9 @@ if (isset($_SERVER['SERVER_NAME'])) {
     $ABSOLUTE_URI_STUDIP .= $CANONICAL_RELATIVE_PATH_STUDIP;
 }
 
-// default ASSETS_URL, customize if required
+// default ASSETS_URL and ASSETS_PATH, customize if required
 $GLOBALS['ASSETS_URL'] = $ABSOLUTE_URI_STUDIP . 'assets/';
+$GLOBALS['ASSETS_PATH'] = $ABSOLUTE_PATH_STUDIP . 'assets/';
 
 require __DIR__ . '/classes/StudipFileloader.php';
 
@@ -107,6 +108,7 @@ require_once 'lib/visual.inc.php';
 
 // set assets url
 Assets::set_assets_url($GLOBALS['ASSETS_URL']);
+Assets::set_assets_path($GLOBALS['ASSETS_PATH']);
 
 // globale template factory anlegen
 require_once 'vendor/flexi/lib/flexi.php';
diff --git a/lib/classes/Assets.class.php b/lib/classes/Assets.class.php
index b5adfcfc4862ea7182ec132b4abedecf59264335..928c47c3e369eb55eb4e1f88628e91e8f8002477 100644
--- a/lib/classes/Assets.class.php
+++ b/lib/classes/Assets.class.php
@@ -41,8 +41,20 @@ class Assets
     /**
      * @ignore
      */
-    private static $assets_url, $dynamic, $counter_cache;
+    private static $assets_url;
+    private static $assets_path;
+    private static $dynamic;
+    private static $counter_cache;
 
+    /**
+     * This method sets the URL to your assets.
+     *
+     * @param string $path the path to the assets
+     */
+    public static function set_assets_path(string $path): void
+    {
+        self::$assets_path = $path;
+    }
 
     /**
      * This method sets the URL to your assets.
@@ -51,14 +63,13 @@ class Assets
      *
      * @return void
      */
-    static function set_assets_url($url)
+    public static function set_assets_url($url)
     {
-        Assets::$assets_url = $url;
-        Assets::$counter_cache = NULL;
-        Assets::$dynamic = mb_strpos($url, '%d') !== FALSE;
+        self::$assets_url = $url;
+        self::$counter_cache = NULL;
+        self::$dynamic = mb_strpos($url, '%d') !== FALSE;
     }
 
-
     /**
      * This class method is an accessor to the URL "prefix" for all things "asset"
      * Prepend the return value of this method to the relative path of the wanted
@@ -104,23 +115,31 @@ class Assets
      *
      * @return string the URL "prefix"
      */
-    static function url($to = '')
+    public static function url($to = '')
     {
-
-        if (!Assets::$dynamic)
-            return Assets::$assets_url . $to;
+        if (!self::$dynamic) {
+            return self::$assets_url . $to;
+        }
 
         # dynamic ASSETS_URL
-        return sprintf(Assets::$assets_url,
+        return sprintf(self::$assets_url,
             $to == ''
-                ? Assets::$counter_cache++ % Assets::NUMBER_OF_ALIASES
+                ? self::$counter_cache++ % self::NUMBER_OF_ALIASES
                 # alternative implementation
                 # : hexdec(mb_substr(sha1($to),-1)) & 3)
-                : ord($to[1]) & (Assets::NUMBER_OF_ALIASES - 1))
+                : ord($to[1]) & (self::NUMBER_OF_ALIASES - 1))
 
         . $to;
     }
 
+    /**
+     * This class method is an accessor to the path "prefix" for all things "asset"
+     */
+    public static function path($to = ''): string
+    {
+        return self::$assets_path . $to;
+    }
+
     /**
      * Returns an image tag using options as html attributes on the
      * tag, but with these special cases:
@@ -137,7 +156,7 @@ class Assets
      * Do not use this to render icons. Use the more appropiate class
      * Icon for this.
      */
-    static function img($source, $opt = [])
+    public static function img($source, $opt = [])
     {
         if (!$source) {
             return '';
@@ -145,9 +164,9 @@ class Assets
 
         $size = $opt['size'] ?? null;
 
-        $opt = Assets::parse_attributes($opt);
+        $opt = self::parse_attributes($opt);
 
-        $opt['src'] = Assets::image_path($source);
+        $opt['src'] = self::image_path($source);
 
         if (!isset($opt['alt'])) {
             $opt['alt'] = ucfirst(current(explode('.', basename($opt['src']))));
@@ -161,7 +180,7 @@ class Assets
             unset($opt['size']);
         }
 
-        return Assets::tag('img', $opt);
+        return self::tag('img', $opt);
     }
 
 
@@ -179,7 +198,7 @@ class Assets
      * Do not use this to render icons. Use the more appropiate class
      * Icon for this.
      */
-    static function input($source, $opt = [])
+    public static function input($source, $opt = [])
     {
 
         if (!$source) {
@@ -190,9 +209,9 @@ class Assets
 
         $size = $opt['size'];
 
-        $opt = Assets::parse_attributes($opt);
+        $opt = self::parse_attributes($opt);
 
-        $opt['src'] = Assets::image_path($source);
+        $opt['src'] = self::image_path($source);
         $opt['type'] = 'image';
 
         if (isset($size) && !isset($opt['width'])) {
@@ -200,7 +219,7 @@ class Assets
             unset($opt['size']);
         }
 
-        return Assets::tag('input', $opt);
+        return self::tag('input', $opt);
     }
 
     /**
@@ -223,9 +242,9 @@ class Assets
      * scripts, as we would like to always generate the complete <image> oder
      * <input> tag. Please use Assets::img or Assets::input instead.
      */
-    static function image_path($source, $respect_retina = false)
+    public static function image_path($source, $respect_retina = false)
     {
-        $path = Assets::compute_public_path($source, 'images', 'png');
+        $path = self::compute_public_path($source, 'images', 'png');
 
         return $path;
     }
@@ -242,12 +261,12 @@ class Assets
      *     <script src="/js/common.javascript"></script>
      *     <script src="/elsewhere/cools.js"></script>
      */
-    static function script($atLeastOneArgument)
+    public static function script($atLeastOneArgument)
     {
         $html = '';
         foreach (func_get_args() as $source) {
-            $source = Assets::javascript_path($source);
-            $html .= Assets::content_tag('script', '',
+            $source = self::javascript_path($source);
+            $html .= self::content_tag('script', '',
                 ['src' => $source]);
             $html .= "\n";
         }
@@ -263,9 +282,9 @@ class Assets
      *
      *   Assets::javascript_path('ajax') => /javascripts/ajax.js
      */
-    static function javascript_path($source)
+    public static function javascript_path($source)
     {
-        return Assets::compute_public_path($source, 'javascripts', 'js');
+        return self::compute_public_path($source, 'javascripts', 'js');
     }
 
 
@@ -284,7 +303,7 @@ class Assets
      *     <link href="/stylesheets/random.styles" media="screen" rel="stylesheet">
      *     <link href="/css/stylish.css" media="screen" rel="stylesheet">
      */
-    static function stylesheet($atLeastOneArgument)
+    public static function stylesheet($atLeastOneArgument)
     {
         $sources = func_get_args();
         $sourceOptions = (func_num_args() > 1 &&
@@ -294,12 +313,12 @@ class Assets
 
         $html = '';
         foreach ($sources as $source) {
-            $source = Assets::stylesheet_path($source);
+            $source = self::stylesheet_path($source);
             $opt = array_merge(['rel' => 'stylesheet',
                     'media' => 'screen',
                     'href' => $source],
                 $sourceOptions);
-            $html .= Assets::tag('link', $opt) . "\n";
+            $html .= self::tag('link', $opt) . "\n";
         }
 
         return $html;
@@ -313,9 +332,9 @@ class Assets
      *
      *   stylesheet_path('style') => /stylesheets/style.css
      */
-    static function stylesheet_path($source)
+    public static function stylesheet_path($source)
     {
-        return Assets::compute_public_path($source, 'stylesheets', 'css');
+        return self::compute_public_path($source, 'stylesheets', 'css');
     }
 
 
@@ -341,7 +360,7 @@ class Assets
                 $source = "$dir/$source";
 
             # consider asset host
-            $source = Assets::url(ltrim($source, '/'));
+            $source = self::url(ltrim($source, '/'));
         }
 
         return $source;
@@ -373,15 +392,17 @@ class Assets
     /**
      * Helper function for content tags.
      *
-     * @param name    tag name
-     * @param content tag content
-     * @param options tag options
+     * @param string $name    tag name
+     * @param string $content tag content
+     * @param array $options tag options
      *
-     * @return type <description>
+     * @return string
      */
     private static function content_tag($name, $content = '', $options = [])
     {
-        if (!$name) return '';
+        if (!$name) {
+            return '';
+        }
         return '<' . $name . ' ' . arrayToHtmlAttributes($options) . '>' .
         $content .
         '</' . $name . '>';
diff --git a/lib/classes/Avatar.class.php b/lib/classes/Avatar.class.php
index b6165bd89befe8945f7cc54e2e13a8b8fe16c07f..959523f2ea178b41468e95b8b69342049e0896c0 100644
--- a/lib/classes/Avatar.class.php
+++ b/lib/classes/Avatar.class.php
@@ -1,62 +1,53 @@
 <?php
-# Lifter007: TODO
-# Lifter003: TODO
-# Lifter010: TODO
-
-/*
- * Copyright (C) 2007 - André Klaßen (aklassen@uos.de)
- * Copyright (C) 2008 - Marcus Lunzenauer (mlunzena@uos)
- *
+/**
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-
-/**
- * TODO
- *
- * @package        studip
- * @subpackage lib
+ * the License, or (at your option) any later version. *
  *
- * @author        André Klaßen (aklassen@uos)
- * @author        Marcus Lunzenauer (mlunzena@uos)
- * @copyright (c) Authors
- * @since         1.7
+ * @author  André Klaßen (aklassen@uos)
+ * @author  Marcus Lunzenauer (mlunzena@uos)
+ * @author  Jan-Hendirk Willms <tleilax+studip@gmail.com>
+ * @license GPL2 or any later version
+ * @since   1.7
  */
-class Avatar {
+class Avatar
+{
+    public const AVATAR_TYPE = 'user';
+    protected const CREATE_CHUNKED_FOLDERS = true;
+
+    public const EXTENSION = 'webp';
+    public const IMAGE_QUALITY = 90;
 
     /**
      * This constant stands for the maximal size of a user picture.
      */
-    const ORIGINAL = 'original';
+    public const ORIGINAL = 'original';
 
     /**
      * This constant stands for the maximal size of a user picture.
      */
-    const NORMAL = 'normal';
+    public const NORMAL = 'normal';
 
     /**
      * This constant stands for a medium size of a user picture.
      */
-    const MEDIUM = 'medium';
+    public const MEDIUM = 'medium';
 
     /**
      * This constant stands for an icon size of a user picture.
      */
-    const SMALL    = 'small';
-
+    public const SMALL    = 'small';
 
     /**
      * This constant represents the maximal size of a user picture in bytes.
      */
-    const MAX_FILE_SIZE = 10485760;
+    public const MAX_FILE_SIZE = 10485760;
 
     /**
      * This constant holds the username and ID of the "nobody" avatar.
      */
-    const NOBODY = 'nobody';
+    protected const NOBODY = 'nobody';
 
     /**
      * Holds the user's id
@@ -65,7 +56,6 @@ class Avatar {
      */
     protected $user_id;
 
-
     /**
      * Holds the user's username
      *
@@ -73,24 +63,23 @@ class Avatar {
      */
     protected $username;
 
-
     /**
      * Returns an avatar object of the appropriate class.
      *
-     * @param string    the user's id
-     * @param string    the user's username (optional)
+     * @param string $id the user's id
+     * @param string $username the user's username (optional)
      *
-     * @return Avatar the user's avatar.
+     * @return static the user's avatar.
      */
     public static function getAvatar($id)
     {
         $username = null;
 
-        if (func_num_args() == 2) {
+        if (func_num_args() === 2) {
             $username = func_get_arg(1);
         }
 
-        return new Avatar($id, $username);
+        return new static($id, $username);
     }
 
     /**
@@ -100,60 +89,113 @@ class Avatar {
      */
     public static function getNobody()
     {
-        return new Avatar(Avatar::NOBODY, Avatar::NOBODY);
+        return new static(static::NOBODY, static::NOBODY);
     }
 
-
+    /**
+     * Returns the url to the customized avatars
+     *
+     * @return string
+     */
     public function getAvatarDirectoryUrl()
     {
-        return $GLOBALS['DYNAMIC_CONTENT_URL'] . "/user";
+        return sprintf(
+            '%s/%s%s',
+            $GLOBALS['DYNAMIC_CONTENT_URL'],
+            static::AVATAR_TYPE,
+            static::CREATE_CHUNKED_FOLDERS ? '/' . substr($this->user_id, 0, 2) : ''
+        );
     }
 
-
+    /**
+     * Returns the path to the customized avatars
+     *
+     * @return string
+     */
     public function getAvatarDirectoryPath()
     {
-        return $GLOBALS['DYNAMIC_CONTENT_PATH'] . "/user";
+        return sprintf(
+            '%s/%s%s',
+            $GLOBALS['DYNAMIC_CONTENT_PATH'],
+            static::AVATAR_TYPE,
+            static::CREATE_CHUNKED_FOLDERS ? '/' . substr($this->user_id, 0, 2) : ''
+        );
+    }
+
+    /**
+     * Returns the url to the default avatars
+     */
+    public function getDefaultAvatarDirectoryUrl(): string
+    {
+        return Assets::url('images/avatars/' . static::AVATAR_TYPE);
     }
 
+    /**
+     * Returns the path to the default avatars
+     */
+    public function getDefaultAvatarDirectoryPath(): string
+    {
+        return Assets::path('images/avatars/' . static::AVATAR_TYPE);
+    }
 
-    public function getCustomAvatarUrl($size, $ext = 'png')
+    /**
+     * Returns the url to a customized avatar
+     *
+     * @return string
+     */
+    public function getCustomAvatarUrl($size)
     {
-        $retina = isset($GLOBALS['auth']->auth['devicePixelRatio'])
-                ? $GLOBALS['auth']->auth['devicePixelRatio'] > 1.2
-                : false;
-        $size = $retina && file_exists($this->getCustomAvatarPath($size, 'png', true))
-              ? $size."@2x"
-              : $size;
+        if ($this->isNobody()) {
+            return sprintf(
+                '%s/%s_%s.%s',
+                $this->getDefaultAvatarDirectoryUrl(),
+                $this->user_id,
+                $size,
+                self::EXTENSION
+            );
+        }
+
         return sprintf(
             '%s/%s_%s.%s?d=%s',
             $this->getAvatarDirectoryUrl(),
             $this->user_id,
             $size,
-            $ext,
+            self::EXTENSION,
             @filemtime($this->getCustomAvatarPath($size)) ?: "0"
         );
     }
 
-
-    public function getCustomAvatarPath($size, $ext = 'png', $retina = false)
+    /**
+     * Returns the path to a customized avatar
+     *
+     * @return string
+     */
+    public function getCustomAvatarPath($size)
     {
+        if ($this->isNobody()) {
+            return sprintf(
+                '%s/%s_%s.%s',
+                $this->getDefaultAvatarDirectoryPath(),
+                $this->user_id,
+                $size,
+                self::EXTENSION
+            );
+        }
+
         return sprintf(
             '%s/%s_%s.%s',
             $this->getAvatarDirectoryPath(),
             $this->user_id,
-            $retina ? $size."@2x" : $size,
-            $ext
+            $size,
+            self::EXTENSION
         );
     }
 
-
     /**
      * Constructs a new Avatar object belonging to a user with the given id.
      *
-     * @param    string    the user's id
-     * @param    string    the user's username (optional)
-     *
-     * @return void
+     * @param string $user_id  the user's id
+     * @param string $username the user's username (optional)
      */
     protected function __construct($user_id, $username = null)
     {
@@ -163,39 +205,50 @@ class Avatar {
         $this->checkAvatarVisibility();
     }
 
-
     /**
      * Returns the file name of a user's avatar.
      *
-     * @param    string    one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
-     * @param    string    an optional extension of the avatar
+     * @param string $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
      *
      * @return string    the absolute file path to the avatar
      */
-    public function getFilename($size, $ext = 'png')
+    public function getFilename($size)
     {
         return $this->is_customized()
-            ? $this->getCustomAvatarPath($size, $ext)
-            : $this->getNobody()->getCustomAvatarPath($size, $ext);
+            ? $this->getCustomAvatarPath($size)
+            : $this->getNobody()->getCustomAvatarPath($size);
     }
 
-
     /**
      * Returns the URL of a user's picture.
      *
-     * @param    string    one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
-     * @param    string    an optional extension of the user's picture
+     * @param string $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
      *
      * @return string    the URL to the user's picture
      */
     # TODO (mlunzena) in Url umbenennen
-    public function getURL($size, $ext = 'png')
+    public function getURL($size)
     {
         return $this->is_customized()
-            ? $this->getCustomAvatarUrl($size, $ext)
-            : $this->getNobody()->getCustomAvatarUrl($size, $ext);
+            ? $this->getCustomAvatarUrl($size)
+            : $this->getNobody()->getCustomAvatarUrl($size);
+    }
+
+    /**
+     * Returns whether this avatar is a default/"nobody" avatar.
+     */
+    public function isNobody(): bool
+    {
+        return $this->user_id === static::NOBODY;
     }
 
+    /**
+     * Returns whether a customized file exists
+     */
+    public function customizedFileExists(): bool
+    {
+        return file_exists($this->getCustomAvatarPath(static::MEDIUM));
+    }
 
     /**
      * Returns whether a user has uploaded a custom picture.
@@ -205,38 +258,40 @@ class Avatar {
      */
     public function is_customized()
     {
-        return $this->user_id !== Avatar::NOBODY
-            && file_exists($this->getCustomAvatarPath(Avatar::MEDIUM));
+        return !$this->isNobody()
+            && $this->customizedFileExists();
     }
 
-
     /**
      * Returns the CSS class to use for this avatar image.
      *
-     * @param string    one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
+     * @param string $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
      *
      * @return string CSS class to use for the avatar
      */
     protected function getCssClass($size)
     {
         if (!isset($this->username)) {
-            $this->username = htmlReady(get_username($this->user_id));
+            $this->username = get_username($this->user_id);
         }
 
-        return sprintf('avatar-%s user-%s'.($this->is_customized() ? '' : ' recolor'), $size, $this->username);
+        return sprintf(
+            'avatar-%s user-%s' . ($this->is_customized() ? '' : ' recolor'),
+            $size,
+            htmlReady($this->username)
+        );
     }
 
-
     /**
      * Constructs a desired HTML image tag for an Avatar. Additional
      * html attributes may also be specified using the $opt parameter.
      *
-     * @param string    one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
-     * @param array     array of attributes to add to the HTML image tag
+     * @param string $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
+     * @param array  $opt  array of attributes to add to the HTML image tag
      *
      * @return string returns the HTML image tag
      */
-    public function getImageTag($size = Avatar::MEDIUM, $opt = [])
+    public function getImageTag($size = self::MEDIUM, $opt = [])
     {
         $opt['src'] = $this->getURL($size);
 
@@ -277,31 +332,34 @@ class Avatar {
         return '<img ' . arrayToHtmlAttributes($opt) . '>';
     }
 
-
     /**
      * Creates all the different sized thumbnails for an uploaded file.
      *
-     * @param    string    the key of the uploaded file,
-     *                                 see documentation about $_FILES
+     * @param string $userfile the key of the uploaded file, see documentation about $_FILES
      *
      * @return void
-     *
-     * @throws several Exceptions if the uploaded file does not satisfy the
-     *                 requirements
      */
     public function createFromUpload($userfile)
     {
         try {
-            // Bilddatei ist zu groß
-            if ($_FILES[$userfile]['size'] > self::MAX_FILE_SIZE) {
-                throw new Exception(sprintf(_("Die hochgeladene Bilddatei ist %s KB groß. Die maximale Dateigröße beträgt %s KB!"),
-                                                                        round($_FILES[$userfile]['size'] / 1024),
-                                                                        self::MAX_FILE_SIZE / 1024));
-            }
-
             // keine Datei ausgewählt!
             if (!$_FILES[$userfile]['name']) {
-                throw new Exception(_("Sie haben keine Datei zum Hochladen ausgewählt!"));
+                throw new Exception(_('Sie haben keine Datei zum Hochladen ausgewählt!'));
+            }
+
+            // Fehler beim Hochladen
+            if ($_FILES[$userfile]['error'] !== UPLOAD_ERR_OK) {
+                throw new Exception(_('Es gab einen Fehler beim Hochladen der Datei!'));
+            }
+
+
+            // Bilddatei ist zu groß
+            if ($_FILES[$userfile]['size'] > self::MAX_FILE_SIZE) {
+                throw new Exception(sprintf(
+                    _('Die hochgeladene Bilddatei ist %s KB groß. Die maximale Dateigröße beträgt %s KB!'),
+                    round($_FILES[$userfile]['size'] / 1024),
+                    self::MAX_FILE_SIZE / 1024)
+                );
             }
 
             // get extension
@@ -309,14 +367,15 @@ class Avatar {
             $ext = mb_strtolower($pathinfo['extension']);
 
             // passende Endung ?
-            if (!in_array($ext, words('jpg jpeg gif png'))) {
-                throw new Exception(sprintf(_("Der Dateityp der Bilddatei ist falsch (%s). Es sind nur die Dateiendungen .gif, .png, .jpeg und .jpg erlaubt!"), htmlReady($ext)));
+            if (!in_array($ext, words('jpg jpeg gif png webp'))) {
+                throw new Exception(sprintf(
+                    _('Der Dateityp der Bilddatei ist falsch (%s). Es sind nur die Dateiendungen .gif, .png, .jpeg, .jpg oder .webp erlaubt!'),
+                    $ext
+                ));
             }
 
             // na dann kopieren wir mal...
-            $filename = sprintf('%s/%s.%s',
-                                                    $this->getAvatarDirectoryPath(),
-                                                    $this->user_id, $ext);
+            $filename = tempnam($GLOBALS['TMP_PATH'], 'avatar-upload');
 
             if (!@move_uploaded_file($_FILES[$userfile]['tmp_name'], $filename)) {
                 throw new Exception(_("Es ist ein Fehler beim Kopieren der Datei aufgetreten. Das Bild wurde nicht hochgeladen!"));
@@ -327,20 +386,17 @@ class Avatar {
 
             $this->sanitizeOrientation($filename);
             $this->createFrom($filename);
-
-            @unlink($filename);
-
-        // eigentlich braucht man hier "finally"
-        } catch (Exception $e) {
-            @unlink($filename);
-            throw $e;
+        } finally {
+            if (isset($filename)) {
+                @unlink($filename);
+            }
         }
     }
 
     /**
      * Creates thumbnails from an image.
      *
-     * @param string    filename of the image to create thumbnails from
+     * @param string $filename filename of the image to create thumbnails from
      *
      * @return void
      */
@@ -353,13 +409,9 @@ class Avatar {
         set_error_handler([__CLASS__, 'error_handler']);
 
         NotificationCenter::postNotification('AvatarWillCreate', $this->user_id);
-        copy($filename, $this->getCustomAvatarPath(Avatar::ORIGINAL));
-        $this->resize(Avatar::NORMAL, $filename);
-        $this->resize(Avatar::NORMAL, $filename, true);
-        $this->resize(Avatar::MEDIUM, $filename);
-        $this->resize(Avatar::MEDIUM, $filename, true);
-        $this->resize(Avatar::SMALL,  $filename);
-        $this->resize(Avatar::SMALL,  $filename, true);
+        $this->resize(static::NORMAL, $filename);
+        $this->resize(static::MEDIUM, $filename);
+        $this->resize(static::SMALL,  $filename);
         NotificationCenter::postNotification('AvatarDidCreate', $this->user_id);
 
         restore_error_handler();
@@ -372,55 +424,50 @@ class Avatar {
     {
         if ($this->is_customized()) {
             NotificationCenter::postNotification('AvatarWillDelete', $this->user_id);
-            @unlink($this->getCustomAvatarPath(Avatar::ORIGINAL));
-            @unlink($this->getCustomAvatarPath(Avatar::NORMAL));
-            @unlink($this->getCustomAvatarPath(Avatar::SMALL));
-            @unlink($this->getCustomAvatarPath(Avatar::MEDIUM));
-            @unlink($this->getCustomAvatarPath(Avatar::NORMAL, 'png', true));
-            @unlink($this->getCustomAvatarPath(Avatar::SMALL, 'png', true));
-            @unlink($this->getCustomAvatarPath(Avatar::MEDIUM, 'png', true));
+            @unlink($this->getCustomAvatarPath(static::NORMAL));
+            @unlink($this->getCustomAvatarPath(static::SMALL));
+            @unlink($this->getCustomAvatarPath(static::MEDIUM));
             NotificationCenter::postNotification('AvatarDidDelete', $this->user_id);
         }
     }
 
-
     /**
      * Return the dimension of a size
      *
-     * @param    string         the dimension of a size
-     * @return array            a tupel of integers [width, height]
+     * @param string $size the dimension of a size
+     * @return array{0: int, 1: int} a tupel of integers [width, height]
      */
-    public static function getDimension($size) {
+    public static function getDimension($size)
+    {
         $dimensions = [
-            Avatar::NORMAL => [250, 250],
-            Avatar::MEDIUM => [100, 100],
-            Avatar::SMALL  => [25, 25]
+            static::NORMAL => [250, 250],
+            static::MEDIUM => [100, 100],
+            static::SMALL  => [25, 25]
         ];
         return $dimensions[$size];
     }
 
-
     /**
      * Create from an image thumbnails of a specified size.
      *
-     * @param string    the size of the thumbnail to create
-     * @param string    the filename of the image to make thumbnail of
-     *
-     * @return void
+     * @param string $size     the size of the thumbnail to create
+     * @param string $filename the filename of the image to make thumbnail of
      */
-    private function resize($size, $filename, $retina = false)
+    private function resize(string $size, string $filename)
     {
-        list($thumb_width, $thumb_height) = static::getDimension($size);
-        $thumb_width = $retina ? $thumb_width * 2 : $thumb_width;
-        $thumb_height = $retina ? $thumb_height * 2 : $thumb_height;
+        [$thumb_width, $thumb_height] = static::getDimension($size);
+
+        $thumb_width = $thumb_width * 2;
+        $thumb_height = $thumb_height * 2;
 
-        list($width, $height, $type) = getimagesize($filename);
+        [$width, $height, $type] = getimagesize($filename);
 
         # create image resource from filename
         $lookup = [
             IMAGETYPE_GIF  => 'imagecreatefromgif',
             IMAGETYPE_JPEG => 'imagecreatefromjpeg',
             IMAGETYPE_PNG  => 'imagecreatefrompng',
+            IMAGETYPE_WEBP => 'imagecreatefromwebp',
         ];
         if (!isset($lookup[$type])) {
             throw new Exception(_("Der Typ des Bilds wird nicht unterstützt."));
@@ -460,9 +507,14 @@ class Avatar {
             $resized_width, $resized_height
         );
 
-        imagepng($dst, $this->getCustomAvatarPath($size, 'png', $retina));
-    }
+        $output_file = $this->getCustomAvatarPath($size);
+        $directory = dirname($output_file);
+        if (!is_dir($directory) && !mkdir($directory)) {
+            throw new Exception(_('Das Verzeichnis zum Speichern der Datei konnte nicht angelegt werden.'));
+        }
 
+        imagewebp($dst, $output_file, self::IMAGE_QUALITY);
+    }
 
     private function imageresize($image, $current_width, $current_height, $width, $height)
     {
@@ -481,7 +533,6 @@ class Avatar {
         return $image_resized;
     }
 
-
     public static function error_handler($errno, $errstr, $errfile, $errline)
     {
         if (defined('E_RECOVERABLE_ERROR')
@@ -506,8 +557,8 @@ class Avatar {
      */
     public function getDefaultTitle()
     {
-        if ($this->user_id === Avatar::NOBODY) {
-            return Avatar::NOBODY;
+        if ($this->isNobody()) {
+            return static::NOBODY;
         }
 
         require_once 'lib/functions.php';
@@ -523,7 +574,7 @@ class Avatar {
     {
         $visible = Visibility::verify('picture', $this->user_id);
         if (!$visible) {
-            $this->user_id = 'nobody';
+            $this->user_id = self::NOBODY;
         }
         return $visible;
     }
@@ -568,12 +619,14 @@ class Avatar {
             $img = imagerotate($img, $degree, 0);
 
             $extension = pathinfo($filename, PATHINFO_EXTENSION);
-            if ($extension === 'jpg' || $extension === 'jpg') {
+            if ($extension === 'jpg' || $extension === 'jpeg') {
                 imagejpeg($img, $filename, 95);
             } elseif ($extension === 'gif') {
                 imagegif($img, $filename);
-            } else {
+            } elseif ($extension === 'png') {
                 imagepng($img, $filename, 9);
+            } else {
+                imagewebp($img, $filename, self::IMAGE_QUALITY);
             }
 
             imagedestroy($img);
diff --git a/lib/classes/CourseAvatar.class.php b/lib/classes/CourseAvatar.class.php
index 3edc9e1ecaed71f4f7ce1e485a35aeda8a63e2e7..8c153a800c00168531757c76454533e00b3d99d8 100644
--- a/lib/classes/CourseAvatar.class.php
+++ b/lib/classes/CourseAvatar.class.php
@@ -1,71 +1,15 @@
 <?php
-# Lifter010: TODO
-
-/*
- * Copyright (C) 2009 - Marcus Lunzenauer (mlunzena@uos)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-
 /**
  * This class represents the avatar of a course.
  *
- * @package    studip
- * @subpackage lib
- *
  * @author    Marcus Lunzenauer (mlunzena@uos)
  * @copyright (c) Authors
+ * @license GPL2 or any later version
  * @since     1.10
  */
 class CourseAvatar extends Avatar
 {
-
-    /**
-     * Returns an avatar object of the appropriate class.
-     *
-     * @param  string  the course's id
-     *
-     * @return mixed   the course's avatar.
-     */
-    static function getAvatar($id)
-    {
-        return new CourseAvatar($id);
-    }
-
-    /**
-     * Returns an avatar object for "nobody".
-     *
-     * @return mixed   the course's avatar.
-     */
-    static function getNobody()
-    {
-        return new CourseAvatar('nobody');
-    }
-
-    /**
-     * Returns the URL to the courses' avatars.
-     *
-     * @return string     the URL to the avatars
-     */
-    function getAvatarDirectoryUrl()
-    {
-        return $GLOBALS['DYNAMIC_CONTENT_URL'] . "/course";
-    }
-
-
-    /**
-     * Returns the file system path to the courses' avatars
-     *
-     * @return string      the file system path to the avatars
-     */
-    function getAvatarDirectoryPath()
-    {
-        return $GLOBALS['DYNAMIC_CONTENT_PATH'] . "/course";
-    }
+    public const AVATAR_TYPE = 'course';
 
     /**
      * Returns the CSS class to use for this avatar image.
@@ -74,15 +18,16 @@ class CourseAvatar extends Avatar
      *
      * @return string CSS class to use for the avatar
      */
-    protected function getCssClass($size) {
-        return sprintf('course-avatar-%s course-%s', $size, $this->user_id);
+    protected function getCssClass($size)
+    {
+        return "course-avatar-{$size} course-{$this->user_id}";
     }
 
     /**
      * Return the default title of the avatar.
      * @return string the default title
      */
-    function getDefaultTitle()
+    public function getDefaultTitle()
     {
         return Seminar::GetInstance($this->user_id)->name;
     }
@@ -91,7 +36,8 @@ class CourseAvatar extends Avatar
      * Return if avatar is visible to the current user.
      * @return boolean: true if visible
      */
-    protected function checkAvatarVisibility() {
+    protected function checkAvatarVisibility()
+    {
         //no special conditions for visibility of course-avatars yet
         return true;
     }
diff --git a/lib/classes/InstituteAvatar.class.php b/lib/classes/InstituteAvatar.class.php
index e05c3450062258d93e4f5f0403eb6bec153aa450..8adbfba569692b7b1642ec5e7a3255dc989cf57a 100644
--- a/lib/classes/InstituteAvatar.class.php
+++ b/lib/classes/InstituteAvatar.class.php
@@ -1,89 +1,44 @@
 <?php
-# Lifter010: TODO
-
-/*
- * Copyright (C) 2009 - Marcus Lunzenauer (mlunzena@uos)
- * André Noack <noack@data-quest.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
 /**
  * This class represents the avatar of a institute.
  *
- * @package    studip
- * @subpackage lib
- *
  * @author    André Noack <noack@data-quest.de>
+ * @author    Marcus Lunzenauer <mlunzena@uos>
  * @copyright (c) Authors
+ * @license   GPL2 or any later version
  * @since     1.10
  */
 class InstituteAvatar extends CourseAvatar
 {
+    public const AVATAR_TYPE = 'institute';
 
     /**
-     * Returns an avatar object of the appropriate class.
-     *
-     * @param  string  the course's id
-     *
-     * @return mixed   the course's avatar.
-     */
-    static function getAvatar($id)
-    {
-        return new InstituteAvatar($id);
-    }
-
-    /**
-     * Returns an avatar object for "nobody".
-     *
-     * @return mixed   the course's avatar.
-     */
-    static function getNobody()
-    {
-        return new InstituteAvatar('nobody');
-    }
-
-    /**
-     * Returns the URL to the institute' avatars.
+     * Returns the CSS class to use for this avatar image.
      *
-     * @return string     the URL to the avatars
+     * @param string  $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
+     * @return string CSS class to use for the avatar
      */
-    function getAvatarDirectoryUrl()
+    protected function getCssClass($size)
     {
-        return $GLOBALS['DYNAMIC_CONTENT_URL'] . "/institute";
-    }
-
-
-    /**
-     * Returns the file system path to the institute' avatars
-     *
-     * @return string      the file system path to the avatars
-     */
-    function getAvatarDirectoryPath()
-    {
-        return $GLOBALS['DYNAMIC_CONTENT_PATH'] . "/institute";
+        return "institute-avatar-{$size} institute-{$this->user_id}";
     }
 
     /**
      * Return the default title of the avatar.
      * @return string the default title
      */
-    function getDefaultTitle()
+    public function getDefaultTitle()
     {
         $institute = Institute::find($this->user_id);
-        return $institute
-               ? $institute->name
-               : Avatar::NOBODY;
+        return $institute ? (string) $institute->name : self::NOBODY;
     }
     
     /**
      * Return if avatar is visible to the current user.
      * @return boolean: true if visible
      */
-    protected function checkAvatarVisibility() {
+    protected function checkAvatarVisibility()
+    {
         //no special conditions for visibility of course-avatars yet
         return true;
     }
diff --git a/lib/classes/JsonApi/Schemas/User.php b/lib/classes/JsonApi/Schemas/User.php
index beaeecb7b77778dde3c95b952694c92764eb69b8..9a172ebd42f0c41e5d7344aa7e7f10260f467c63 100644
--- a/lib/classes/JsonApi/Schemas/User.php
+++ b/lib/classes/JsonApi/Schemas/User.php
@@ -109,7 +109,7 @@ class User extends SchemaProvider
                 'small' => $avatar->getURL(\Avatar::SMALL),
                 'medium' => $avatar->getURL(\Avatar::MEDIUM),
                 'normal' => $avatar->getURL(\Avatar::NORMAL),
-                'original' => $avatar->getURL(\Avatar::ORIGINAL),
+                'original' => $avatar->getURL(\Avatar::NORMAL),
             ],
         ];
     }
diff --git a/lib/classes/LicenseAvatar.php b/lib/classes/LicenseAvatar.php
index 27072abcbfe72c513617b232467d491e1d670559..c0a429d38e143cb132f08e7859ae6567f1393538 100644
--- a/lib/classes/LicenseAvatar.php
+++ b/lib/classes/LicenseAvatar.php
@@ -15,69 +15,31 @@
  */
 class LicenseAvatar extends Avatar
 {
-
-    /**
-     * Returns an avatar object of the appropriate class.
-     *
-     * @param  string  the course's id
-     *
-     * @return mixed   the course's avatar.
-     */
-    public static function getAvatar($id)
-    {
-        return new self($id);
-    }
-
-    /**
-     * Returns an avatar object for "nobody".
-     *
-     * @return mixed   the course's avatar.
-     */
-    public static function getNobody()
-    {
-        return new self('nobody');
-    }
-
-    /**
-     * Returns the URL to the courses' avatars.
-     *
-     * @return string     the URL to the avatars
-     */
-    public function getAvatarDirectoryUrl()
-    {
-        return $GLOBALS['DYNAMIC_CONTENT_URL'] . "/licenses";
-    }
-
-
-    /**
-     * Returns the file system path to the courses' avatars
-     *
-     * @return string      the file system path to the avatars
-     */
-    public function getAvatarDirectoryPath()
-    {
-        return $GLOBALS['DYNAMIC_CONTENT_PATH'] . "/licenses";
-    }
+    public const AVATAR_TYPE = 'licenses';
+    protected const CREATE_CHUNKED_FOLDERS = false;
 
     public function getImageTag($size = Avatar::MEDIUM, $opt = [])
     {
         if (!$this->is_customized()) {
             return "";
-        } else {
-            return parent::getImageTag($size, $opt);
         }
+
+        return parent::getImageTag($size, $opt);
     }
 
     /**
      * Returns the CSS class to use for this avatar image.
      *
-     * @param string  one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
-     *
+     * @param string  $size one of the constants Avatar::(NORMAL|MEDIUM|SMALL)
      * @return string CSS class to use for the avatar
      */
     protected function getCssClass($size)
     {
-        return sprintf('license-avatar-%s license-%s', $size, $this->user_id);
+        return sprintf(
+            'license-avatar-%s license-%s',
+            $size,
+            $this->user_id
+        );
     }
 
     /**
@@ -101,8 +63,8 @@ class LicenseAvatar extends Avatar
     /**
      * Return the dimension of a size
      *
-     * @param    string         the dimension of a size
-     * @return array            a tupel of integers [width, height]
+     * @param  string $size the dimension of a size
+     * @return array a tupel of integers [width, height]
      */
     public static function getDimension($size)
     {
diff --git a/lib/classes/StudygroupAvatar.class.php b/lib/classes/StudygroupAvatar.class.php
index 5121c904c4aecb6fa48ffe7702ae0516e6728de9..8e27f8e9b3d2a7bae22edca7f60ed554abcadc53 100644
--- a/lib/classes/StudygroupAvatar.class.php
+++ b/lib/classes/StudygroupAvatar.class.php
@@ -1,49 +1,16 @@
 <?php
-# Lifter010: TODO
-
-/*
- * Copyright (C) 2009 - Marcus Lunzenauer (mlunzena@uos)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-
 /**
  * This class represents the avatar of a course.
  *
- * @package    studip
- * @subpackage lib
- *
  * @author    Marcus Lunzenauer (mlunzena@uos), Till Glöggler (tgloeggl@uos)
+ * @license GPL2 or any later version
  * @copyright (c) Authors
  * @since     1.10
  */
 class StudygroupAvatar extends CourseAvatar
 {
     /**
-     * Returns an avatar object of the appropriate class.
-     *
-     * @param  string  the studygroup's id
-     *
-     * @return mixed   the studygroup's avatar.
-     */
-    static function getAvatar($course_id)
-    {
-        return new StudygroupAvatar($course_id);
-    }
-
-
-    /**
-     * Returns an avatar object for "nobody".
-     *
-     * @return mixed   the studygroup's avatar.
+     * This constant holds the username and ID of the "studygroup" avatar.
      */
-    static function getNobody()
-    {
-        return new StudygroupAvatar('studygroup');
-    }
-
+    protected const NOBODY = 'studygroup';
 }
diff --git a/lib/models/User.class.php b/lib/models/User.class.php
index 4f9ccb7b0b848d86435bca24436413a25fa85e0f..dd3ccd72309c1abfb89f433b08b9fc0027857a8c 100644
--- a/lib/models/User.class.php
+++ b/lib/models/User.class.php
@@ -1161,10 +1161,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject
             $new_avatar = Avatar::getAvatar($new_id);
             if ($old_avatar->is_customized()) {
                 if (!$new_avatar->is_customized()) {
-                    $avatar_file = $old_avatar->getFilename(Avatar::ORIGINAL);
-                    if (!file_exists($avatar_file)) {
-                        $avatar_file = $old_avatar->getFilename(Avatar::NORMAL);
-                    }
+                    $avatar_file = $old_avatar->getFilename(Avatar::NORMAL);
                     $new_avatar->createFrom($avatar_file);
                 }
                 $old_avatar->reset();
diff --git a/lib/phplib/Seminar_Auth.class.php b/lib/phplib/Seminar_Auth.class.php
index e4f9e36495bba43deadd3748b963dd42dc709a23..30a6d4677198c82d83e5ecfa46a6fa1d443d61da 100644
--- a/lib/phplib/Seminar_Auth.class.php
+++ b/lib/phplib/Seminar_Auth.class.php
@@ -349,7 +349,6 @@ class Seminar_Auth
 
         $this->auth["uname"] = Request::get('loginname'); // This provides access for "loginform.ihtml"
         $this->auth["jscript"] = Request::get('resolution') != "";
-        $this->auth['devicePixelRatio'] = Request::float('device_pixel_ratio');
 
         $check_auth = StudipAuthAbstract::CheckAuthentication(Request::get('loginname'), Request::get('password'));
 
diff --git a/public/assets/images/avatars/course/nobody_medium.webp b/public/assets/images/avatars/course/nobody_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..fe3c3316323f3171964590b4b60e498b02583d5b
Binary files /dev/null and b/public/assets/images/avatars/course/nobody_medium.webp differ
diff --git a/public/assets/images/avatars/course/nobody_normal.webp b/public/assets/images/avatars/course/nobody_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..6bc35356fbdc44078987d1aa3d78d78ea81ee0eb
Binary files /dev/null and b/public/assets/images/avatars/course/nobody_normal.webp differ
diff --git a/public/assets/images/avatars/course/nobody_small.webp b/public/assets/images/avatars/course/nobody_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..2cd05a2c5fa608880053961d0bda9e3403485f9e
Binary files /dev/null and b/public/assets/images/avatars/course/nobody_small.webp differ
diff --git a/public/assets/images/avatars/course/studygroup_medium.webp b/public/assets/images/avatars/course/studygroup_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..36ac4121a18fb5ff69fe9223bcbb31b24dca1870
Binary files /dev/null and b/public/assets/images/avatars/course/studygroup_medium.webp differ
diff --git a/public/assets/images/avatars/course/studygroup_normal.webp b/public/assets/images/avatars/course/studygroup_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..25ce033495d934ba3d301cef62b7e2597eec5934
Binary files /dev/null and b/public/assets/images/avatars/course/studygroup_normal.webp differ
diff --git a/public/assets/images/avatars/course/studygroup_small.webp b/public/assets/images/avatars/course/studygroup_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..e2c2fa9b514fae49be459cc81696de6d2c9ff13d
Binary files /dev/null and b/public/assets/images/avatars/course/studygroup_small.webp differ
diff --git a/public/assets/images/avatars/institute/nobody_medium.webp b/public/assets/images/avatars/institute/nobody_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..af74dc840b11eb7378555aadac3268b0681eeba2
Binary files /dev/null and b/public/assets/images/avatars/institute/nobody_medium.webp differ
diff --git a/public/assets/images/avatars/institute/nobody_normal.webp b/public/assets/images/avatars/institute/nobody_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..2394779eca51a3a19a3eaca82584857997e272d4
Binary files /dev/null and b/public/assets/images/avatars/institute/nobody_normal.webp differ
diff --git a/public/assets/images/avatars/institute/nobody_small.webp b/public/assets/images/avatars/institute/nobody_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..5d2af37ac1c738f72eb2bc177cf7c68c7b11410a
Binary files /dev/null and b/public/assets/images/avatars/institute/nobody_small.webp differ
diff --git a/public/assets/images/avatars/user/nobody_medium.webp b/public/assets/images/avatars/user/nobody_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..e941ee125b4ca95d5e79b4562b7abb5194783577
Binary files /dev/null and b/public/assets/images/avatars/user/nobody_medium.webp differ
diff --git a/public/assets/images/avatars/user/nobody_normal.webp b/public/assets/images/avatars/user/nobody_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05bea6dbb2fed6dfdd3f6861b36b1e9c54a4c0ab
Binary files /dev/null and b/public/assets/images/avatars/user/nobody_normal.webp differ
diff --git a/public/assets/images/avatars/user/nobody_small.webp b/public/assets/images/avatars/user/nobody_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..c16bd4c0ddcc0025d63f95cc51a54d8aa7c0e121
Binary files /dev/null and b/public/assets/images/avatars/user/nobody_small.webp differ
diff --git a/public/pictures/course/.gitkeep b/public/pictures/course/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/public/pictures/course/nobody_medium.png b/public/pictures/course/nobody_medium.png
deleted file mode 100644
index 78718268ae9e1bdbef5e3e4205cafadbd15c47e0..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_medium.png and /dev/null differ
diff --git a/public/pictures/course/nobody_medium@2x.png b/public/pictures/course/nobody_medium@2x.png
deleted file mode 100644
index fb29b5c931c48fab107936daf5904c61c0dc03c7..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_medium@2x.png and /dev/null differ
diff --git a/public/pictures/course/nobody_normal.png b/public/pictures/course/nobody_normal.png
deleted file mode 100644
index c325a726100cdc58bdd29435d3bae58f96d2ca9f..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_normal.png and /dev/null differ
diff --git a/public/pictures/course/nobody_normal@2x.png b/public/pictures/course/nobody_normal@2x.png
deleted file mode 100644
index 11ee358a799e32a44e88e8cd86d4bdc1bcf3df66..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_normal@2x.png and /dev/null differ
diff --git a/public/pictures/course/nobody_small.png b/public/pictures/course/nobody_small.png
deleted file mode 100644
index 2188f01113e7e1059e1b4d2871bb71f691b0b5ec..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_small.png and /dev/null differ
diff --git a/public/pictures/course/nobody_small@2x.png b/public/pictures/course/nobody_small@2x.png
deleted file mode 100644
index a4b8750424265926647a7b57f676e99ef5256ca2..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/nobody_small@2x.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_medium.png b/public/pictures/course/studygroup_medium.png
deleted file mode 100644
index ed5c723f39fbcd2ea55accdcdc4dab2859b00549..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_medium.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_medium2x.png b/public/pictures/course/studygroup_medium2x.png
deleted file mode 100644
index 68c757935364a618591d7ab3e312a5cd4609b9e3..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_medium2x.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_normal.png b/public/pictures/course/studygroup_normal.png
deleted file mode 100644
index 6d09371473a923db02cd81062aea58828107b0e8..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_normal.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_normal@2x.png b/public/pictures/course/studygroup_normal@2x.png
deleted file mode 100644
index 6a8d4a002dca5597f558cdfc525bce6c3626c2aa..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_normal@2x.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_small.png b/public/pictures/course/studygroup_small.png
deleted file mode 100644
index f9f05ac88ad395423dbacc933abeb8c884a5df6d..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_small.png and /dev/null differ
diff --git a/public/pictures/course/studygroup_small@2x.png b/public/pictures/course/studygroup_small@2x.png
deleted file mode 100644
index 54b9a51c972e4376389d39ee9553bcc037dfad63..0000000000000000000000000000000000000000
Binary files a/public/pictures/course/studygroup_small@2x.png and /dev/null differ
diff --git a/public/pictures/institute/.gitkeep b/public/pictures/institute/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/public/pictures/institute/nobody_medium.png b/public/pictures/institute/nobody_medium.png
deleted file mode 100644
index 10db88bcecb94b558aa5c4f186eb3ec3f69945e9..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_medium.png and /dev/null differ
diff --git a/public/pictures/institute/nobody_medium@2x.png b/public/pictures/institute/nobody_medium@2x.png
deleted file mode 100644
index c1bda520c943c720781ad03224fbfc16b954bb31..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_medium@2x.png and /dev/null differ
diff --git a/public/pictures/institute/nobody_normal.png b/public/pictures/institute/nobody_normal.png
deleted file mode 100644
index 592499be57469d9a90953565d0c38cbf26bf0147..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_normal.png and /dev/null differ
diff --git a/public/pictures/institute/nobody_normal@2x.png b/public/pictures/institute/nobody_normal@2x.png
deleted file mode 100644
index ff951ff69648b2ad9f5156cdfafe965d45a92b47..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_normal@2x.png and /dev/null differ
diff --git a/public/pictures/institute/nobody_small.png b/public/pictures/institute/nobody_small.png
deleted file mode 100644
index 0f81f2f80490c843479aa9e6180ed417a2b0f779..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_small.png and /dev/null differ
diff --git a/public/pictures/institute/nobody_small@2x.png b/public/pictures/institute/nobody_small@2x.png
deleted file mode 100644
index a778413d6c27221f31d412908a3f579e9af18281..0000000000000000000000000000000000000000
Binary files a/public/pictures/institute/nobody_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_medium.png b/public/pictures/licenses/CC-BY-1.0_medium.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_medium.webp b/public/pictures/licenses/CC-BY-1.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..cee6dc8226b38051d35f35fe368c8f7ff3a9dd37
Binary files /dev/null and b/public/pictures/licenses/CC-BY-1.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-1.0_medium@2x.png b/public/pictures/licenses/CC-BY-1.0_medium@2x.png
deleted file mode 100644
index 3bfad3d380fbfe0dba1bfcc9965e16f7c3617e34..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_normal.png b/public/pictures/licenses/CC-BY-1.0_normal.png
deleted file mode 100644
index 9ebbfff9343a18420e009f441cd80fd9a6a630aa..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_normal.webp b/public/pictures/licenses/CC-BY-1.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..16d7b88a4a9d1da777944ae69c69ff2b9938a106
Binary files /dev/null and b/public/pictures/licenses/CC-BY-1.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-1.0_normal@2x.png b/public/pictures/licenses/CC-BY-1.0_normal@2x.png
deleted file mode 100644
index 12a845007054147867c1940385494b65a64bfd8c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_small.png b/public/pictures/licenses/CC-BY-1.0_small.png
deleted file mode 100644
index fee6acf49289a04f748e72c4bce965157d7a7217..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-1.0_small.webp b/public/pictures/licenses/CC-BY-1.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05d0e9addab86059d437a5ed057b6e68ef874591
Binary files /dev/null and b/public/pictures/licenses/CC-BY-1.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-1.0_small@2x.png b/public/pictures/licenses/CC-BY-1.0_small@2x.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-1.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_medium.png b/public/pictures/licenses/CC-BY-2.0_medium.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_medium.webp b/public/pictures/licenses/CC-BY-2.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..cee6dc8226b38051d35f35fe368c8f7ff3a9dd37
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.0_medium@2x.png b/public/pictures/licenses/CC-BY-2.0_medium@2x.png
deleted file mode 100644
index 3bfad3d380fbfe0dba1bfcc9965e16f7c3617e34..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_normal.png b/public/pictures/licenses/CC-BY-2.0_normal.png
deleted file mode 100644
index 47090d33075b34285ec0b21a6d2f3e60c9aec7da..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_normal.webp b/public/pictures/licenses/CC-BY-2.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..16d7b88a4a9d1da777944ae69c69ff2b9938a106
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.0_normal@2x.png b/public/pictures/licenses/CC-BY-2.0_normal@2x.png
deleted file mode 100644
index 12a845007054147867c1940385494b65a64bfd8c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_small.png b/public/pictures/licenses/CC-BY-2.0_small.png
deleted file mode 100644
index 4b3e4ade0c853563f79a618d76ca5209387e2424..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.0_small.webp b/public/pictures/licenses/CC-BY-2.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05d0e9addab86059d437a5ed057b6e68ef874591
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.0_small@2x.png b/public/pictures/licenses/CC-BY-2.0_small@2x.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_medium.png b/public/pictures/licenses/CC-BY-2.5_medium.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_medium.webp b/public/pictures/licenses/CC-BY-2.5_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..cee6dc8226b38051d35f35fe368c8f7ff3a9dd37
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.5_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.5_medium@2x.png b/public/pictures/licenses/CC-BY-2.5_medium@2x.png
deleted file mode 100644
index 3bfad3d380fbfe0dba1bfcc9965e16f7c3617e34..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_normal.png b/public/pictures/licenses/CC-BY-2.5_normal.png
deleted file mode 100644
index 6c5f5647ef925a2d89be2b642a7ca535dbb8db93..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_normal.webp b/public/pictures/licenses/CC-BY-2.5_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..16d7b88a4a9d1da777944ae69c69ff2b9938a106
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.5_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.5_normal@2x.png b/public/pictures/licenses/CC-BY-2.5_normal@2x.png
deleted file mode 100644
index 12a845007054147867c1940385494b65a64bfd8c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_small.png b/public/pictures/licenses/CC-BY-2.5_small.png
deleted file mode 100644
index dcf08cc0ef28ccf1b25ca4d2a4902ba83e84096b..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-2.5_small.webp b/public/pictures/licenses/CC-BY-2.5_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05d0e9addab86059d437a5ed057b6e68ef874591
Binary files /dev/null and b/public/pictures/licenses/CC-BY-2.5_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-2.5_small@2x.png b/public/pictures/licenses/CC-BY-2.5_small@2x.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-2.5_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_medium.png b/public/pictures/licenses/CC-BY-3.0_medium.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_medium.webp b/public/pictures/licenses/CC-BY-3.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..cee6dc8226b38051d35f35fe368c8f7ff3a9dd37
Binary files /dev/null and b/public/pictures/licenses/CC-BY-3.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-3.0_medium@2x.png b/public/pictures/licenses/CC-BY-3.0_medium@2x.png
deleted file mode 100644
index 3bfad3d380fbfe0dba1bfcc9965e16f7c3617e34..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_normal.png b/public/pictures/licenses/CC-BY-3.0_normal.png
deleted file mode 100644
index c5236c9d5a1eddd698dd832af8b01928e87165e0..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_normal.webp b/public/pictures/licenses/CC-BY-3.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..16d7b88a4a9d1da777944ae69c69ff2b9938a106
Binary files /dev/null and b/public/pictures/licenses/CC-BY-3.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-3.0_normal@2x.png b/public/pictures/licenses/CC-BY-3.0_normal@2x.png
deleted file mode 100644
index 12a845007054147867c1940385494b65a64bfd8c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_small.png b/public/pictures/licenses/CC-BY-3.0_small.png
deleted file mode 100644
index 963d3a49af1c4dcd5b7a068073eb067ef8ba2c80..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-3.0_small.webp b/public/pictures/licenses/CC-BY-3.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05d0e9addab86059d437a5ed057b6e68ef874591
Binary files /dev/null and b/public/pictures/licenses/CC-BY-3.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-3.0_small@2x.png b/public/pictures/licenses/CC-BY-3.0_small@2x.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-3.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_medium.png b/public/pictures/licenses/CC-BY-4.0_medium.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_medium.webp b/public/pictures/licenses/CC-BY-4.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..cee6dc8226b38051d35f35fe368c8f7ff3a9dd37
Binary files /dev/null and b/public/pictures/licenses/CC-BY-4.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-4.0_medium@2x.png b/public/pictures/licenses/CC-BY-4.0_medium@2x.png
deleted file mode 100644
index 3bfad3d380fbfe0dba1bfcc9965e16f7c3617e34..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_normal.png b/public/pictures/licenses/CC-BY-4.0_normal.png
deleted file mode 100644
index d8568aa11e246d6f16d38d40b8592bcdd95687ab..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_normal.webp b/public/pictures/licenses/CC-BY-4.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..16d7b88a4a9d1da777944ae69c69ff2b9938a106
Binary files /dev/null and b/public/pictures/licenses/CC-BY-4.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-4.0_normal@2x.png b/public/pictures/licenses/CC-BY-4.0_normal@2x.png
deleted file mode 100644
index 12a845007054147867c1940385494b65a64bfd8c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_small.png b/public/pictures/licenses/CC-BY-4.0_small.png
deleted file mode 100644
index 76a3de344ff314f517a9ab0a6231b8fc50924a8a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-4.0_small.webp b/public/pictures/licenses/CC-BY-4.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..05d0e9addab86059d437a5ed057b6e68ef874591
Binary files /dev/null and b/public/pictures/licenses/CC-BY-4.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-4.0_small@2x.png b/public/pictures/licenses/CC-BY-4.0_small@2x.png
deleted file mode 100644
index cc70c2a997ad7a8e9dcdddfaa6da08ee763e797f..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-4.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_medium.png b/public/pictures/licenses/CC-BY-SA-1.0_medium.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_medium.webp b/public/pictures/licenses/CC-BY-SA-1.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..3e13a4d88a989190f5cfa02e2060e3bef4257258
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-1.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_medium@2x.png b/public/pictures/licenses/CC-BY-SA-1.0_medium@2x.png
deleted file mode 100644
index 8e2a6252ef16264af25cdad30fd3530b6e5cf894..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_normal.png b/public/pictures/licenses/CC-BY-SA-1.0_normal.png
deleted file mode 100644
index 9257b2de5d316f8f9960dddb49ed7b6492765da4..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_normal.webp b/public/pictures/licenses/CC-BY-SA-1.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..d7187912d1e43294e643a63d016aeb005c82b848
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-1.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_normal@2x.png b/public/pictures/licenses/CC-BY-SA-1.0_normal@2x.png
deleted file mode 100644
index 769fe78718acf32f7e18928a0a428f810f0c4a44..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_small.png b/public/pictures/licenses/CC-BY-SA-1.0_small.png
deleted file mode 100644
index 15e2ca323f9638043aae506f973b7351b1e34a51..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_small.webp b/public/pictures/licenses/CC-BY-SA-1.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..69bc29ac0d5b5277474e51fa757f65bb67d49421
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-1.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-1.0_small@2x.png b/public/pictures/licenses/CC-BY-SA-1.0_small@2x.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-1.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_medium.png b/public/pictures/licenses/CC-BY-SA-2.0_medium.png
deleted file mode 100644
index 17ad272758c2844606ea81a33631b2b40c45221d..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_medium.webp b/public/pictures/licenses/CC-BY-SA-2.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..5e46086d1ee9b39ddb1aba342ceacef3d8f7d2a6
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_medium@2x.png b/public/pictures/licenses/CC-BY-SA-2.0_medium@2x.png
deleted file mode 100644
index 9769397b3191aeb4684b5e0e9d26455498a88d50..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_normal.png b/public/pictures/licenses/CC-BY-SA-2.0_normal.png
deleted file mode 100644
index 1a461d6bb0c3dffc3f00d668d12d5d5fb936e0ea..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_normal.webp b/public/pictures/licenses/CC-BY-SA-2.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..5c88fd8914603f92e06131191546777e1356155d
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_normal@2x.png b/public/pictures/licenses/CC-BY-SA-2.0_normal@2x.png
deleted file mode 100644
index a22f3517380d59e148e537b22973b5bda661651e..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_small.png b/public/pictures/licenses/CC-BY-SA-2.0_small.png
deleted file mode 100644
index 4ef2b7cd4d6e542546c507fbd732624f7d7d27e6..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_small.webp b/public/pictures/licenses/CC-BY-SA-2.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0ec7f2d5025386714deadb4992d0f327a520883e
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.0_small@2x.png b/public/pictures/licenses/CC-BY-SA-2.0_small@2x.png
deleted file mode 100644
index 14af68a398bc9ba0b6d686aee5b999fa9fbf338c..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_medium.png b/public/pictures/licenses/CC-BY-SA-2.5_medium.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_medium.webp b/public/pictures/licenses/CC-BY-SA-2.5_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..3e13a4d88a989190f5cfa02e2060e3bef4257258
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.5_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_medium@2x.png b/public/pictures/licenses/CC-BY-SA-2.5_medium@2x.png
deleted file mode 100644
index 8e2a6252ef16264af25cdad30fd3530b6e5cf894..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_normal.png b/public/pictures/licenses/CC-BY-SA-2.5_normal.png
deleted file mode 100644
index 9257b2de5d316f8f9960dddb49ed7b6492765da4..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_normal.webp b/public/pictures/licenses/CC-BY-SA-2.5_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..d7187912d1e43294e643a63d016aeb005c82b848
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.5_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_normal@2x.png b/public/pictures/licenses/CC-BY-SA-2.5_normal@2x.png
deleted file mode 100644
index 769fe78718acf32f7e18928a0a428f810f0c4a44..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_small.png b/public/pictures/licenses/CC-BY-SA-2.5_small.png
deleted file mode 100644
index 39a017df9dead17bc3c31066a758811402521a07..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_small.webp b/public/pictures/licenses/CC-BY-SA-2.5_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..69bc29ac0d5b5277474e51fa757f65bb67d49421
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-2.5_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-2.5_small@2x.png b/public/pictures/licenses/CC-BY-SA-2.5_small@2x.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-2.5_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_medium.png b/public/pictures/licenses/CC-BY-SA-3.0_medium.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_medium.webp b/public/pictures/licenses/CC-BY-SA-3.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..3e13a4d88a989190f5cfa02e2060e3bef4257258
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-3.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_medium@2x.png b/public/pictures/licenses/CC-BY-SA-3.0_medium@2x.png
deleted file mode 100644
index 8e2a6252ef16264af25cdad30fd3530b6e5cf894..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_normal.png b/public/pictures/licenses/CC-BY-SA-3.0_normal.png
deleted file mode 100644
index 9257b2de5d316f8f9960dddb49ed7b6492765da4..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_normal.webp b/public/pictures/licenses/CC-BY-SA-3.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..d7187912d1e43294e643a63d016aeb005c82b848
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-3.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_normal@2x.png b/public/pictures/licenses/CC-BY-SA-3.0_normal@2x.png
deleted file mode 100644
index 769fe78718acf32f7e18928a0a428f810f0c4a44..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_small.png b/public/pictures/licenses/CC-BY-SA-3.0_small.png
deleted file mode 100644
index 4fb11a0b68f99dd92343b30271ae4ac77e7fb9bc..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_small.webp b/public/pictures/licenses/CC-BY-SA-3.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..69bc29ac0d5b5277474e51fa757f65bb67d49421
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-3.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-3.0_small@2x.png b/public/pictures/licenses/CC-BY-SA-3.0_small@2x.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-3.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_medium.png b/public/pictures/licenses/CC-BY-SA-4.0_medium.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_medium.webp b/public/pictures/licenses/CC-BY-SA-4.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..3e13a4d88a989190f5cfa02e2060e3bef4257258
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-4.0_medium.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_medium@2x.png b/public/pictures/licenses/CC-BY-SA-4.0_medium@2x.png
deleted file mode 100644
index 8e2a6252ef16264af25cdad30fd3530b6e5cf894..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_normal.png b/public/pictures/licenses/CC-BY-SA-4.0_normal.png
deleted file mode 100644
index 9257b2de5d316f8f9960dddb49ed7b6492765da4..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_normal.webp b/public/pictures/licenses/CC-BY-SA-4.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..d7187912d1e43294e643a63d016aeb005c82b848
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-4.0_normal.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_normal@2x.png b/public/pictures/licenses/CC-BY-SA-4.0_normal@2x.png
deleted file mode 100644
index 769fe78718acf32f7e18928a0a428f810f0c4a44..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_small.png b/public/pictures/licenses/CC-BY-SA-4.0_small.png
deleted file mode 100644
index 3d718e99299fb98e7320e3c5707ebb0c0f48cdc7..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_small.webp b/public/pictures/licenses/CC-BY-SA-4.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..69bc29ac0d5b5277474e51fa757f65bb67d49421
Binary files /dev/null and b/public/pictures/licenses/CC-BY-SA-4.0_small.webp differ
diff --git a/public/pictures/licenses/CC-BY-SA-4.0_small@2x.png b/public/pictures/licenses/CC-BY-SA-4.0_small@2x.png
deleted file mode 100644
index 725f1da01c5ccb1e1a449869b14d5ea52e4c6f3a..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC-BY-SA-4.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_medium.png b/public/pictures/licenses/CC0-1.0_medium.png
deleted file mode 100644
index 6b33ed05c9af35410a03dc34095b28684be9d9f1..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_medium.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_medium.webp b/public/pictures/licenses/CC0-1.0_medium.webp
new file mode 100644
index 0000000000000000000000000000000000000000..c4894dbd094ab7d1989af85563028bea36dd1b8d
Binary files /dev/null and b/public/pictures/licenses/CC0-1.0_medium.webp differ
diff --git a/public/pictures/licenses/CC0-1.0_medium@2x.png b/public/pictures/licenses/CC0-1.0_medium@2x.png
deleted file mode 100644
index bef472996957dddf1600159a9036fabae14c5941..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_medium@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_normal.png b/public/pictures/licenses/CC0-1.0_normal.png
deleted file mode 100644
index 70c7b8ea3827678d5c4b11bc084ccca8d0c841d7..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_normal.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_normal.webp b/public/pictures/licenses/CC0-1.0_normal.webp
new file mode 100644
index 0000000000000000000000000000000000000000..6066916a20839f7619dd83414369387d3a57e69d
Binary files /dev/null and b/public/pictures/licenses/CC0-1.0_normal.webp differ
diff --git a/public/pictures/licenses/CC0-1.0_normal@2x.png b/public/pictures/licenses/CC0-1.0_normal@2x.png
deleted file mode 100644
index 67c7bf1445eed033fff0f846c8433d7adc803c37..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_normal@2x.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_small.png b/public/pictures/licenses/CC0-1.0_small.png
deleted file mode 100644
index e911016775148d6416975aff669e09c6d47262e4..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_small.png and /dev/null differ
diff --git a/public/pictures/licenses/CC0-1.0_small.webp b/public/pictures/licenses/CC0-1.0_small.webp
new file mode 100644
index 0000000000000000000000000000000000000000..d6ebf816993499defa3b5987e1e1fbc0e1210f73
Binary files /dev/null and b/public/pictures/licenses/CC0-1.0_small.webp differ
diff --git a/public/pictures/licenses/CC0-1.0_small@2x.png b/public/pictures/licenses/CC0-1.0_small@2x.png
deleted file mode 100644
index 8bbd5f02f885a6683a888fc00661ff1967a42af2..0000000000000000000000000000000000000000
Binary files a/public/pictures/licenses/CC0-1.0_small@2x.png and /dev/null differ
diff --git a/public/pictures/user/.gitkeep b/public/pictures/user/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/public/pictures/user/nobody_medium.png b/public/pictures/user/nobody_medium.png
deleted file mode 100644
index 73f6adce4c3aeceda2d2643e1378dc10a8e35c2b..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_medium.png and /dev/null differ
diff --git a/public/pictures/user/nobody_medium@2x.png b/public/pictures/user/nobody_medium@2x.png
deleted file mode 100644
index 726a9c923f5dbb232aaed512d85eced7c5bf33c6..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_medium@2x.png and /dev/null differ
diff --git a/public/pictures/user/nobody_normal.png b/public/pictures/user/nobody_normal.png
deleted file mode 100644
index 57e29d9885ad8a25b27f7849a9f6528ff73e4775..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_normal.png and /dev/null differ
diff --git a/public/pictures/user/nobody_normal@2x.png b/public/pictures/user/nobody_normal@2x.png
deleted file mode 100644
index 9b926dbe291d5d564a9079a842e49efc08f14173..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_normal@2x.png and /dev/null differ
diff --git a/public/pictures/user/nobody_small.png b/public/pictures/user/nobody_small.png
deleted file mode 100644
index a7ebfe8a7424fe957cabdd368427e20a7d797202..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_small.png and /dev/null differ
diff --git a/public/pictures/user/nobody_small@2x.png b/public/pictures/user/nobody_small@2x.png
deleted file mode 100644
index 1e0034b8b0ad9fc0ea2186d37b2331c2df512945..0000000000000000000000000000000000000000
Binary files a/public/pictures/user/nobody_small@2x.png and /dev/null differ
diff --git a/templates/loginform.php b/templates/loginform.php
index edbd565f82336e8e4ee2648732f82b23dbc7a608..348cceea607880338694b14c4cafeeaa90e7a76c 100644
--- a/templates/loginform.php
+++ b/templates/loginform.php
@@ -65,7 +65,6 @@ if (!match_route('web_migrate.php')) {
                 <?= CSRFProtection::tokenTag() ?>
                 <input type="hidden" name="login_ticket" value="<?=Seminar_Session::get_ticket();?>">
                 <input type="hidden" name="resolution"  value="">
-                <input type="hidden" name="device_pixel_ratio" value="1">
                 <?= Button::createAccept(_('Anmelden'), _('Login')); ?>
                 <?= LinkButton::create(_('Abbrechen'), URLHelper::getURL('index.php', ['cancel_login' => 1], true)) ?>
         </form>
@@ -93,7 +92,6 @@ if (!match_route('web_migrate.php')) {
 $(function () {
     $('form[name=login]').submit(function () {
         $('input[name=resolution]', this).val( screen.width + 'x' + screen.height );
-        $('input[name=device_pixel_ratio]').val(window.devicePixelRatio || 1);
     });
 });
 // -->
diff --git a/templates/sidebar/sidebar.php b/templates/sidebar/sidebar.php
index fa8ee57702281681a299a80de919d301256e3ae5..9aa72dedf1f598afd423ed79206c04c9befa1574 100644
--- a/templates/sidebar/sidebar.php
+++ b/templates/sidebar/sidebar.php
@@ -4,7 +4,7 @@
     <? if ($avatar) : ?>
         <div class="sidebar-context">
         <? if ($avatar->is_customized()) : ?>
-            <a href="<?= htmlReady($avatar->getURL(file_exists($avatar->getFilename(Avatar::ORIGINAL)) ? Avatar::ORIGINAL : Avatar::NORMAL)) ?>"
+            <a href="<?= htmlReady($avatar->getURL(Avatar::NORMAL)) ?>"
                data-lightbox="sidebar-avatar"
                data-title="<?= htmlReady(PageLayout::getTitle()) ?>">
         <? endif ?>
diff --git a/tests/unit/lib/classes/AvatarClassTest.php b/tests/unit/lib/classes/AvatarClassTest.php
index 88b24bd2a8e43598a1d6bfa36eefd4030ed77b82..8172e20244f28bdd8172827387b241cb8fd3823d 100644
--- a/tests/unit/lib/classes/AvatarClassTest.php
+++ b/tests/unit/lib/classes/AvatarClassTest.php
@@ -11,136 +11,152 @@
 
 require_once 'lib/phplib/Seminar_Perm.class.php';
 
-/**
- * Testcase for Avatar class.
- *
- * @package    studip
- * @subpackage test
- *
- * @author    mlunzena
- * @copyright (c) Authors
- */
-class AvatarTestCase extends  \Codeception\Test\Unit
+abstract class AvatarTest extends \Codeception\Test\Unit
 {
-    private $avatar_id;
-    private $avatar;
+    protected $avatar_id;
+    protected $avatar;
 
-    public function setUp(): void
+    abstract protected function getType(): string;
+
+    protected function createPath(string $avatar_id, ?string $size, bool $subdir): string
     {
-        $stub = $this->createMock('Seminar_Perm');
-        // Configure the stub.
-        $stub->expects($this->any())
-            ->method('have_perm')
-            ->will($this->returnValue(true));
+        $result = $avatar_id;
 
-        $GLOBALS['perm'] = $stub;
-        $GLOBALS['DYNAMIC_CONTENT_URL'] = "/dynamic";
-        $GLOBALS['DYNAMIC_CONTENT_PATH'] = "/dynamic";
-        $this->avatar_id = "123456789";
-        $this->avatar = Avatar::getAvatar($this->avatar_id);
+        if ($size) {
+            $result .= "_{$size}";
+        }
+
+        $result .= '.' . Avatar::EXTENSION;
+
+        if ($subdir) {
+            $result = substr($avatar_id, 0, 2) . '/' . $result;
+        }
+        return "/dynamic/{$this->getType()}/{$result}";
     }
 
-    public function tearDown(): void
+    protected function createFixedPath(?string $size): string
+    {
+        $result = 'nobody';
+
+        if ($size) {
+            $result .= "_{$size}";
+        }
+
+        $result .= '.' . Avatar::EXTENSION;
+
+        return "/fixed/images/avatars/{$this->getType()}/{$result}";
+    }
+
+    protected function setUp(): void
     {
-        unset($GLOBALS['DYNAMIC_CONTENT_PATH'], $GLOBALS['DYNAMIC_CONTENT_URL']);
+        $GLOBALS['DYNAMIC_CONTENT_URL'] = "/dynamic";
+        $GLOBALS['DYNAMIC_CONTENT_PATH'] = "/dynamic";
+        $GLOBALS['ASSETS_URL'] = "/fixed/";
+        $GLOBALS['ASSETS_PATH'] = "/fixed/";
+
+        Assets::set_assets_url($GLOBALS['ASSETS_URL']);
+        Assets::set_assets_path($GLOBALS['ASSETS_PATH']);
     }
 
-    public function test_class_should_exist()
+    public function tearDown(): void
     {
-        $this->assertTrue(class_exists('Avatar'));
+        unset(
+            $GLOBALS['DYNAMIC_CONTENT_PATH'],
+            $GLOBALS['DYNAMIC_CONTENT_URL'],
+            $GLOBALS['ASSETS_URL'],
+            $GLOBALS['ASSETS_PATH']
+        );
     }
 
     public function test_avatar_url()
     {
-        $url = $this->avatar->getCustomAvatarUrl(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/user/" . $this->avatar_id . "_normal.png?d=0", $url);
+        $this->assertEquals(
+            $this->createPath($this->avatar_id, Avatar::NORMAL, true) . '?d=0',
+            $this->avatar->getCustomAvatarUrl(Avatar::NORMAL)
+        );
     }
 
     public function test_avatar_path()
     {
-        $path = $this->avatar->getCustomAvatarPath(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/user/" . $this->avatar_id . "_normal.png", $path);
+        $this->assertEquals(
+            $this->createPath($this->avatar_id, Avatar::NORMAL, true),
+            $this->avatar->getCustomAvatarPath(Avatar::NORMAL)
+        );
     }
 
     public function test_nobody_url()
     {
-        $url = Avatar::getNobody()->getUrl(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/user/nobody_normal.png?d=0", $url);
+        $this->assertEquals(
+            $this->createFixedPath(Avatar::NORMAL),
+            $this->avatar->getNobody()->getURL(Avatar::NORMAL)
+        );
     }
 
     public function test_nobody_path()
     {
-        $path = Avatar::getNobody()->getCustomAvatarPath(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/user/nobody_normal.png", $path);
+        $this->assertEquals(
+            $this->createFixedPath(Avatar::NORMAL),
+            $this->avatar->getNobody()->getFilename(Avatar::NORMAL)
+        );
     }
 }
 
-
-class CourseAvatarTestCase extends \Codeception\Test\Unit
+/**
+ * Testcase for Avatar class.
+ *
+ * @package    studip
+ * @subpackage test
+ *
+ * @author    mlunzena
+ * @copyright (c) Authors
+ */
+class AvatarTestCase extends AvatarTest
 {
-    private $avatar_id;
-    private $avatar;
-
     public function setUp(): void
     {
-        $this->avatar_id = "123456789";
-        $this->avatar = CourseAvatar::getAvatar($this->avatar_id);
-
-        $this->setUpFS();
+        parent::setUp();
 
-        $GLOBALS['DYNAMIC_CONTENT_URL'] = "/dynamic";
-        $GLOBALS['DYNAMIC_CONTENT_PATH'] = "/dynamic";
-    }
+        $stub = $this->createMock('Seminar_Perm');
+        // Configure the stub.
+        $stub->expects($this->any())
+            ->method('have_perm')
+            ->will($this->returnValue(true));
 
-    private function setUpFS()
-    {
-        ArrayFileStream::set_filesystem([
-            'dynamic' => [
-                'course' => [
-                    $this->avatar_id . '_normal.png' => '',
-                    $this->avatar_id . '_medium.png' => '',
-                    $this->avatar_id . '_small.png' => '',
-                ],
-            ],
-        ]);
-
-        if (!stream_wrapper_register("var", "ArrayFileStream")) {
-            throw new Exception("Failed to register protocol");
-        }
-    }
+        $GLOBALS['perm'] = $stub;
 
-    public function tearDown(): void
-    {
-        stream_wrapper_unregister("var");
-        unset($GLOBALS['DYNAMIC_CONTENT_PATH'], $GLOBALS['DYNAMIC_CONTENT_URL']);
+        $this->avatar_id = "123456789";
+        $this->avatar = Avatar::getAvatar($this->avatar_id);
     }
 
     public function test_class_should_exist()
     {
-        $this->assertTrue(class_exists('CourseAvatar'));
+        $this->assertTrue(class_exists(Avatar::class));
     }
 
-    public function test_avatar_url()
+    protected function getType(): string
     {
-        $url = $this->avatar->getCustomAvatarUrl(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/course/". $this->avatar_id . "_normal.png?d=0", $url);
+        return 'user';
     }
+}
 
-    public function test_avatar_path()
+
+class CourseAvatarTestCase extends AvatarTest
+{
+    public function setUp(): void
     {
-        $path = $this->avatar->getCustomAvatarPath(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/course/". $this->avatar_id . "_normal.png", $path);
+        parent::setUp();
+
+        $this->avatar_id = "123456789";
+        $this->avatar = CourseAvatar::getAvatar($this->avatar_id);
     }
 
-    public function test_nobody_url()
+    public function test_class_should_exist()
     {
-        $url = CourseAvatar::getNobody()->getUrl(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/course/nobody_normal.png?d=0", $url);
+        $this->assertTrue(class_exists(CourseAvatar::class));
     }
 
-    public function test_nobody_path()
+    protected function getType(): string
     {
-        $path = CourseAvatar::getNobody()->getCustomAvatarPath(Avatar::NORMAL);
-        $this->assertEquals("/dynamic/course/nobody_normal.png", $path);
+        return 'course';
     }
 }