From 6513422e40ab69e1d9b7edfb342530f6bf0ee64b Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Fri, 29 May 2020 18:08:18 +0400
Subject: [PATCH] Remove legacy image-related code.

---
 Telegram/CMakeLists.txt                       |   1 -
 Telegram/SourceFiles/app.cpp                  |   2 -
 Telegram/SourceFiles/boxes/background_box.cpp |   9 +-
 .../boxes/background_preview_box.cpp          |   1 -
 Telegram/SourceFiles/boxes/edit_caption_box.h |   2 +
 Telegram/SourceFiles/calls/calls_panel.h      |   2 +
 .../chat_helpers/gifs_list_widget.cpp         |  16 +-
 .../chat_helpers/stickers_emoji_pack.cpp      | 138 +---
 .../chat_helpers/stickers_emoji_pack.h        |   1 +
 .../SourceFiles/chat_helpers/stickers_set.cpp |   2 +-
 .../SourceFiles/core/media_active_cache.h     |  83 ---
 Telegram/SourceFiles/data/data_chat.h         |   1 -
 Telegram/SourceFiles/data/data_cloud_file.cpp |   2 +-
 Telegram/SourceFiles/data/data_cloud_file.h   |   1 +
 Telegram/SourceFiles/data/data_document.cpp   |   6 -
 Telegram/SourceFiles/data/data_document.h     |   1 -
 .../SourceFiles/data/data_document_media.cpp  |  35 +-
 .../SourceFiles/data/data_document_media.h    |   1 +
 Telegram/SourceFiles/data/data_media_types.h  |   1 +
 Telegram/SourceFiles/data/data_peer.cpp       |  19 +-
 Telegram/SourceFiles/data/data_photo.cpp      |   4 -
 Telegram/SourceFiles/data/data_photo.h        |   1 -
 .../SourceFiles/data/data_photo_media.cpp     |  11 +-
 .../SourceFiles/data/data_reply_preview.cpp   |   5 +-
 .../SourceFiles/data/data_reply_preview.h     |   2 +
 Telegram/SourceFiles/data/data_session.cpp    |  15 +-
 Telegram/SourceFiles/data/data_wall_paper.cpp |   6 -
 Telegram/SourceFiles/data/data_wall_paper.h   |   1 -
 .../SourceFiles/history/history_widget.cpp    |   1 -
 .../view/media/history_view_contact.cpp       |   4 +
 .../history/view/media/history_view_gif.cpp   |  26 +-
 .../history/view/media/history_view_gif.h     |   1 +
 .../view/media/history_view_large_emoji.cpp   |   2 +-
 .../view/media/history_view_large_emoji.h     |   2 +
 .../view/media/history_view_location.cpp      |   7 +
 .../view/media/history_view_location.h        |   1 +
 .../history/view/media/history_view_poll.cpp  |   4 +
 .../view/media/history_view_sticker.cpp       |   5 +-
 .../media/history_view_theme_document.cpp     |  10 +-
 .../view/media/history_view_theme_document.h  |   2 +
 .../inline_bot_layout_internal.cpp            |  58 +-
 .../inline_bots/inline_bot_layout_item.h      |   2 +
 .../inline_bots/inline_bot_result.cpp         |   9 -
 .../inline_bots/inline_bot_result.h           |   1 -
 .../inline_bots/inline_results_widget.cpp     |  14 +-
 Telegram/SourceFiles/main/main_account.cpp    |   1 -
 Telegram/SourceFiles/mainwidget.cpp           |   2 -
 Telegram/SourceFiles/mainwidget.h             |   1 +
 .../media/view/media_view_group_thumbs.cpp    |   4 -
 .../media/view/media_view_overlay_widget.cpp  |   7 +-
 .../SourceFiles/media/view/media_view_pip.cpp |  17 +-
 .../SourceFiles/overview/overview_layout.cpp  |   2 -
 .../SourceFiles/overview/overview_layout.h    |   2 +
 .../SourceFiles/settings/settings_chat.cpp    |   4 +-
 Telegram/SourceFiles/ui/image/image.cpp       | 175 +----
 Telegram/SourceFiles/ui/image/image.h         |  70 +-
 .../SourceFiles/ui/image/image_location.cpp   |  17 -
 .../SourceFiles/ui/image/image_location.h     |  16 -
 .../SourceFiles/ui/image/image_source.cpp     | 600 +-----------------
 Telegram/SourceFiles/ui/image/image_source.h  | 234 +------
 60 files changed, 161 insertions(+), 1509 deletions(-)
 delete mode 100644 Telegram/SourceFiles/core/media_active_cache.h

diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 32cdc60f8..1db53bfde 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -331,7 +331,6 @@ PRIVATE
     core/launcher.h
     core/local_url_handlers.cpp
     core/local_url_handlers.h
-    core/media_active_cache.h
     core/mime_type.cpp
     core/mime_type.h
     core/sandbox.cpp
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 4050fa326..d0de88e9e 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -227,8 +227,6 @@ namespace App {
 		clearCorners();
 
 		Data::clearGlobalStructures();
-
-		Images::ClearAll();
 	}
 
 	void hoveredItem(HistoryView::Element *item) {
diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp
index 2260de3f1..03700d875 100644
--- a/Telegram/SourceFiles/boxes/background_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_box.cpp
@@ -266,10 +266,8 @@ void BackgroundBox::Inner::resizeToContentAndPreload() {
 
 	const auto preload = kBackgroundsInRow * 3;
 	for (const auto &paper : _papers | ranges::view::take(preload)) {
-		if (paper.data.localThumbnail()) {
-			paper.data.loadLocalThumbnail();
-		} else if (const auto document = paper.data.document()) {
-			if (!paper.dataMedia) {
+		if (!paper.data.localThumbnail() && !paper.dataMedia) {
+			if (const auto document = paper.data.document()) {
 				paper.dataMedia = document->createMediaView();
 				paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
 			}
@@ -323,9 +321,6 @@ void BackgroundBox::Inner::validatePaperThumbnail(
 		if (!paper.dataMedia || !paper.dataMedia->thumbnail()) {
 			return;
 		}
-	} else if (!localThumbnail->loaded()) {
-		localThumbnail->load(paper.data.fileOrigin());
-		return;
 	}
 	const auto thumbnail = localThumbnail
 		? localThumbnail
diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp
index 311acd79f..aef469873 100644
--- a/Telegram/SourceFiles/boxes/background_preview_box.cpp
+++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp
@@ -434,7 +434,6 @@ void BackgroundPreviewBox::prepare() {
 	}
 	updateServiceBg(_paper.backgroundColor());
 
-	_paper.loadLocalThumbnail();
 	_paper.loadDocument();
 	const auto document = _paper.document();
 	if (document && document->loading()) {
diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.h b/Telegram/SourceFiles/boxes/edit_caption_box.h
index 7cecf946f..c7c5bebb2 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.h
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.h
@@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/wrap/slide_wrap.h"
 #include "mtproto/mtproto_rpc_sender.h"
 
+class Image;
+
 namespace ChatHelpers {
 class TabbedPanel;
 } // namespace ChatHelpers
diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h
index 724825f34..ffa69a844 100644
--- a/Telegram/SourceFiles/calls/calls_panel.h
+++ b/Telegram/SourceFiles/calls/calls_panel.h
@@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/effects/animations.h"
 #include "ui/rp_widget.h"
 
+class Image;
+
 namespace Data {
 class PhotoMedia;
 class CloudImageView;
diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
index 61a0ea27b..9bce21d4f 100644
--- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
@@ -452,25 +452,13 @@ void GifsListWidget::processPanelHideFinished() {
 }
 
 void GifsListWidget::clearHeavyData() {
-	const auto itemForget = [](const auto &item) {
-		if (const auto document = item->getDocument()) {
-			document->unload();
-		}
-		if (const auto photo = item->getPhoto()) {
-			photo->unload();
-		}
-		if (const auto result = item->getResult()) {
-			result->unload();
-		}
-		item->unloadHeavyPart();
-	};
 	// Preserve panel state through visibility toggles.
 	//clearInlineRows(false);
 	for (const auto &[document, layout] : _gifLayouts) {
-		itemForget(layout);
+		layout->unloadHeavyPart();
 	}
 	for (const auto &[document, layout] : _inlineLayouts) {
-		itemForget(layout);
+		layout->unloadHeavyPart();
 	}
 }
 
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp
index 2c99cd707..59da0625f 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp
+++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp
@@ -123,31 +123,11 @@ public:
 		EmojiPtr emoji,
 		not_null<crl::object_on_queue<EmojiImageLoader>*> loader);
 
-	void load(Data::FileOrigin origin) override;
-	void loadEvenCancelled(Data::FileOrigin origin) override;
+	void load() override;
 	QImage takeLoaded() override;
-	void unload() override;
-
-	bool loading() override;
-	bool displayLoading() override;
-	void cancel() override;
-	float64 progress() override;
-	int loadOffset() override;
-
-	const StorageImageLocation &location() override;
-	void refreshFileReference(const QByteArray &data) override;
-	Storage::Cache::Key cacheKey() override;
-	void setDelayedStorageLocation(
-		const StorageImageLocation &location) override;
-	void performDelayedLoad(Data::FileOrigin origin) override;
-	void setImageBytes(const QByteArray &bytes) override;
 
 	int width() override;
 	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-	QByteArray bytesForCache() override;
 
 private:
 	// While HistoryView::Element-s are almost never destroyed
@@ -155,8 +135,6 @@ private:
 	not_null<crl::object_on_queue<EmojiImageLoader>*> _loader;
 	EmojiPtr _emoji = nullptr;
 	QImage _data;
-	QByteArray _format;
-	QByteArray _bytes;
 	QSize _size;
 	base::binary_guard _loading;
 
@@ -170,92 +148,29 @@ ImageSource::ImageSource(
 , _size(SingleSize()) {
 }
 
-void ImageSource::load(Data::FileOrigin origin) {
-	if (!_data.isNull()) {
+void ImageSource::load() {
+	if (!_data.isNull() || _loading) {
 		return;
 	}
-	if (_bytes.isEmpty()) {
-		_loader->with([
-			this,
-			emoji = _emoji,
-			guard = _loading.make_guard()
-		](EmojiImageLoader &loader) mutable {
-			if (!guard) {
-				return;
-			}
-			crl::on_main(std::move(guard), [this, image = loader.prepare(emoji)]{
-				_data = image;
-				Auth().downloaderTaskFinished().notify();
-			});
+	_loader->with([
+		this,
+		emoji = _emoji,
+		guard = _loading.make_guard()
+	](EmojiImageLoader &loader) mutable {
+		if (!guard) {
+			return;
+		}
+		crl::on_main(std::move(guard), [this, image = loader.prepare(emoji)]{
+			_data = image;
+			Auth().downloaderTaskFinished().notify();
 		});
-	} else {
-		_data = App::readImage(_bytes, &_format, false);
-	}
-}
-
-void ImageSource::loadEvenCancelled(Data::FileOrigin origin) {
-	load(origin);
+	});
 }
 
 QImage ImageSource::takeLoaded() {
-	load({});
 	return _data;
 }
 
-void ImageSource::unload() {
-	if (_bytes.isEmpty() && !_data.isNull()) {
-		if (_format != "JPG") {
-			_format = "PNG";
-		}
-		{
-			QBuffer buffer(&_bytes);
-			_data.save(&buffer, _format);
-		}
-		Assert(!_bytes.isEmpty());
-	}
-	_data = QImage();
-}
-
-bool ImageSource::loading() {
-	return _data.isNull() && _bytes.isEmpty();
-}
-
-bool ImageSource::displayLoading() {
-	return false;
-}
-
-void ImageSource::cancel() {
-}
-
-float64 ImageSource::progress() {
-	return 1.;
-}
-
-int ImageSource::loadOffset() {
-	return 0;
-}
-
-const StorageImageLocation &ImageSource::location() {
-	return StorageImageLocation::Invalid();
-}
-
-void ImageSource::refreshFileReference(const QByteArray &data) {
-}
-
-Storage::Cache::Key ImageSource::cacheKey() {
-	return {};
-}
-
-void ImageSource::setDelayedStorageLocation(
-	const StorageImageLocation &location) {
-}
-
-void ImageSource::performDelayedLoad(Data::FileOrigin origin) {
-}
-
-void ImageSource::setImageBytes(const QByteArray &bytes) {
-}
-
 int ImageSource::width() {
 	return _size.width();
 }
@@ -264,29 +179,6 @@ int ImageSource::height() {
 	return _size.height();
 }
 
-int ImageSource::bytesSize() {
-	return _bytes.size();
-}
-
-void ImageSource::setInformation(int size, int width, int height) {
-	if (width && height) {
-		_size = QSize(width, height);
-	}
-}
-
-QByteArray ImageSource::bytesForCache() {
-	auto result = QByteArray();
-	{
-		QBuffer buffer(&result);
-		if (!_data.save(&buffer, _format)) {
-			if (_data.save(&buffer, "PNG")) {
-				_format = "PNG";
-			}
-		}
-	}
-	return result;
-}
-
 } // namespace
 
 EmojiImageLoader::EmojiImageLoader(
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h
index 16d3e1476..52973b94c 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h
+++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include <crl/crl_object_on_queue.h>
 
+class Image;
 class HistoryItem;
 class DocumentData;
 
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_set.cpp b/Telegram/SourceFiles/chat_helpers/stickers_set.cpp
index 07e249eaa..6d7452157 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_set.cpp
+++ b/Telegram/SourceFiles/chat_helpers/stickers_set.cpp
@@ -31,7 +31,7 @@ void SetThumbnailView::set(
 		_content = std::move(content);
 	} else {
 		_image = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
+			std::make_unique<Images::ImageSource>(std::move(image)));
 	}
 	session->downloaderTaskFinished().notify();
 }
diff --git a/Telegram/SourceFiles/core/media_active_cache.h b/Telegram/SourceFiles/core/media_active_cache.h
deleted file mode 100644
index a395a8857..000000000
--- a/Telegram/SourceFiles/core/media_active_cache.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-This file is part of Telegram Desktop,
-the official desktop application for the Telegram messaging service.
-
-For license and copyright information please follow this link:
-https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
-*/
-#pragma once
-
-#include "base/last_used_cache.h"
-
-namespace Core {
-
-template <typename Type>
-class MediaActiveCache {
-public:
-	template <typename Unload>
-	MediaActiveCache(int64 limit, Unload &&unload);
-
-	void up(Type *entry);
-	void remove(Type *entry);
-	void clear();
-
-	void increment(int64 amount);
-	void decrement(int64 amount);
-
-private:
-	template <typename Unload>
-	void check(Unload &&unload);
-
-	base::last_used_cache<Type*> _cache;
-	SingleQueuedInvokation _delayed;
-	int64 _usage = 0;
-	int64 _limit = 0;
-
-};
-
-template <typename Type>
-template <typename Unload>
-MediaActiveCache<Type>::MediaActiveCache(int64 limit, Unload &&unload)
-: _delayed([=] { check(unload); })
-, _limit(limit) {
-}
-
-template <typename Type>
-void MediaActiveCache<Type>::up(Type *entry) {
-	_cache.up(entry);
-	_delayed.call();
-}
-
-template <typename Type>
-void MediaActiveCache<Type>::remove(Type *entry) {
-	_cache.remove(entry);
-}
-
-template <typename Type>
-void MediaActiveCache<Type>::clear() {
-	_cache.clear();
-}
-
-template <typename Type>
-void MediaActiveCache<Type>::increment(int64 amount) {
-	_usage += amount;
-}
-
-template <typename Type>
-void MediaActiveCache<Type>::decrement(int64 amount) {
-	_usage -= amount;
-}
-
-template <typename Type>
-template <typename Unload>
-void MediaActiveCache<Type>::check(Unload &&unload) {
-	while (_usage > _limit) {
-		if (const auto entry = _cache.take_lowest()) {
-			unload(entry);
-		} else {
-			break;
-		}
-	}
-}
-
-} // namespace Core
diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h
index 051091c7a..ed99c6d63 100644
--- a/Telegram/SourceFiles/data/data_chat.h
+++ b/Telegram/SourceFiles/data/data_chat.h
@@ -175,7 +175,6 @@ public:
 	std::deque<not_null<UserData*>> lastAuthors;
 	base::flat_set<not_null<PeerData*>> markupSenders;
 	int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
-//	ImagePtr photoFull;
 
 private:
 	Flags _flags;
diff --git a/Telegram/SourceFiles/data/data_cloud_file.cpp b/Telegram/SourceFiles/data/data_cloud_file.cpp
index cdc969d25..7ec7319df 100644
--- a/Telegram/SourceFiles/data/data_cloud_file.cpp
+++ b/Telegram/SourceFiles/data/data_cloud_file.cpp
@@ -22,7 +22,7 @@ void CloudImageView::set(
 		not_null<Main::Session*> session,
 		QImage image) {
 	_image = std::make_unique<Image>(
-		std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
+		std::make_unique<Images::ImageSource>(std::move(image)));
 	session->downloaderTaskFinished().notify();
 }
 
diff --git a/Telegram/SourceFiles/data/data_cloud_file.h b/Telegram/SourceFiles/data/data_cloud_file.h
index e739fe645..fb5b18770 100644
--- a/Telegram/SourceFiles/data/data_cloud_file.h
+++ b/Telegram/SourceFiles/data/data_cloud_file.h
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/image/image_location.h"
 
 class FileLoader;
+class Image;
 
 namespace Storage {
 namespace Cache {
diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp
index 32d519c7b..d2576d7e6 100644
--- a/Telegram/SourceFiles/data/data_document.cpp
+++ b/Telegram/SourceFiles/data/data_document.cpp
@@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "main/main_session.h"
 #include "mainwidget.h"
 #include "core/file_utilities.h"
-#include "core/media_active_cache.h"
 #include "core/mime_type.h"
 #include "chat_helpers/stickers.h"
 #include "chat_helpers/stickers_set.h"
@@ -457,7 +456,6 @@ DocumentData::~DocumentData() {
 	base::take(_thumbnail.loader).reset();
 	base::take(_videoThumbnail.loader).reset();
 	destroyLoader();
-	unload();
 }
 
 Data::Session &DocumentData::owner() const {
@@ -803,10 +801,6 @@ bool DocumentData::saveToCache() const {
 			|| isTheme());
 }
 
-void DocumentData::unload() {
-	_replyPreview = nullptr;
-}
-
 void DocumentData::automaticLoadSettingsChanged() {
 	if (!cancelled() || status != FileReady) {
 		return;
diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h
index 4af95d1c9..eea01639d 100644
--- a/Telegram/SourceFiles/data/data_document.h
+++ b/Telegram/SourceFiles/data/data_document.h
@@ -125,7 +125,6 @@ public:
 
 	[[nodiscard]] bool saveToCache() const;
 
-	void unload();
 	[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
 
 	[[nodiscard]] StickerData *sticker() const;
diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp
index 04587f0a2..34b3f6ca6 100644
--- a/Telegram/SourceFiles/data/data_document_media.cpp
+++ b/Telegram/SourceFiles/data/data_document_media.cpp
@@ -166,7 +166,7 @@ void DocumentMedia::setGoodThumbnail(QImage thumbnail) {
 		return;
 	}
 	_goodThumbnail = std::make_unique<Image>(
-		std::make_unique<Images::ImageSource>(std::move(thumbnail), "PNG"));
+		std::make_unique<Images::ImageSource>(std::move(thumbnail)));
 	_owner->session().downloaderTaskFinished().notify();
 }
 
@@ -175,9 +175,7 @@ Image *DocumentMedia::thumbnailInline() const {
 		auto image = Images::FromInlineBytes(_owner->inlineThumbnailBytes());
 		if (!image.isNull()) {
 			_inlineThumbnail = std::make_unique<Image>(
-				std::make_unique<Images::ImageSource>(
-					std::move(image),
-					"PNG"));
+				std::make_unique<Images::ImageSource>(std::move(image)));
 		}
 	}
 	return _inlineThumbnail.get();
@@ -203,7 +201,7 @@ QSize DocumentMedia::thumbnailSize() const {
 
 void DocumentMedia::setThumbnail(QImage thumbnail) {
 	_thumbnail = std::make_unique<Image>(
-		std::make_unique<Images::ImageSource>(std::move(thumbnail), "PNG"));
+		std::make_unique<Images::ImageSource>(std::move(thumbnail)));
 	_owner->session().downloaderTaskFinished().notify();
 }
 
@@ -243,18 +241,12 @@ void DocumentMedia::checkStickerLarge() {
 		const auto &loc = _owner->location(true);
 		if (loc.accessEnable()) {
 			_sticker = std::make_unique<Image>(
-				std::make_unique<Images::LocalFileSource>(loc.name()));
+				std::make_unique<Images::ImageSource>(loc.name()));
 			loc.accessDisable();
 		}
 	} else {
-		auto format = QByteArray();
-		auto image = App::readImage(_bytes, &format, false);
 		_sticker = std::make_unique<Image>(
-			std::make_unique<Images::LocalFileSource>(
-				QString(),
-				_bytes,
-				format,
-				std::move(image)));
+			std::make_unique<Images::ImageSource>(_bytes));
 	}
 }
 
@@ -297,19 +289,19 @@ void DocumentMedia::automaticLoad(
 void DocumentMedia::collectLocalData(not_null<DocumentMedia*> local) {
 	if (const auto image = local->_goodThumbnail.get()) {
 		_goodThumbnail = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(image->original(), "PNG"));
+			std::make_unique<Images::ImageSource>(image->original()));
 	}
 	if (const auto image = local->_inlineThumbnail.get()) {
 		_inlineThumbnail = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(image->original(), "PNG"));
+			std::make_unique<Images::ImageSource>(image->original()));
 	}
 	if (const auto image = local->_thumbnail.get()) {
 		_thumbnail = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(image->original(), "PNG"));
+			std::make_unique<Images::ImageSource>(image->original()));
 	}
 	if (const auto image = local->_sticker.get()) {
 		_sticker = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(image->original(), "PNG"));
+			std::make_unique<Images::ImageSource>(image->original()));
 	}
 	_bytes = local->_bytes;
 	_videoThumbnailBytes = local->_videoThumbnailBytes;
@@ -380,14 +372,9 @@ Image *DocumentMedia::getStickerSmall() {
 void DocumentMedia::checkStickerLarge(not_null<FileLoader*> loader) {
 	if (_owner->sticker()
 		&& !_sticker
-		&& !loader->imageData().isNull()
-		&& !_bytes.isEmpty()) {
+		&& !loader->imageData().isNull()) {
 		_sticker = std::make_unique<Image>(
-			std::make_unique<Images::LocalFileSource>(
-				QString(),
-				_bytes,
-				loader->imageFormat(),
-				loader->imageData()));
+			std::make_unique<Images::ImageSource>(loader->imageData()));
 	}
 }
 
diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h
index 1fd8af8ce..b153ce1a7 100644
--- a/Telegram/SourceFiles/data/data_document_media.h
+++ b/Telegram/SourceFiles/data/data_document_media.h
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "base/flags.h"
 
+class Image;
 class FileLoader;
 
 namespace Media {
diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h
index 7baa7c558..ab09b28f4 100644
--- a/Telegram/SourceFiles/data/data_media_types.h
+++ b/Telegram/SourceFiles/data/data_media_types.h
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "data/data_location.h"
 
+class Image;
 class HistoryItem;
 
 namespace base {
diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp
index 7f85f08a1..370b12a7b 100644
--- a/Telegram/SourceFiles/data/data_peer.cpp
+++ b/Telegram/SourceFiles/data/data_peer.cpp
@@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "mainwindow.h"
 #include "window/window_session_controller.h"
 #include "ui/image/image.h"
+#include "ui/image/image_source.h"
 #include "ui/empty_userpic.h"
 #include "ui/text_options.h"
 #include "history/history.h"
@@ -217,6 +218,13 @@ Image *PeerData::currentUserpic(
 	const auto image = view ? view->image() : nullptr;
 	if (image) {
 		_userpicEmpty = nullptr;
+	} else if (isNotificationsUser()) {
+		static auto result = Image(
+			std::make_unique<Images::ImageSource>(
+				Core::App().logoNoMargin().scaledToWidth(
+					kUserpicSize,
+					Qt::SmoothTransformation)));
+		return &result;
 	}
 	return image;
 }
@@ -370,17 +378,6 @@ void PeerData::updateUserpic(
 }
 
 void PeerData::clearUserpic() {
-	//const auto photo = [&] { // #TODO optimize
-	//	if (isNotificationsUser()) {
-	//		auto image = Core::App().logoNoMargin().scaledToWidth(
-	//			kUserpicSize,
-	//			Qt::SmoothTransformation);
-	//		return _userpic
-	//			? _userpic
-	//			: Images::Create(std::move(image), "PNG");
-	//	}
-	//	return ImagePtr();
-	//}();
 	setUserpicChecked(PhotoId(), ImageLocation());
 }
 
diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp
index 7f21d2daf..fc73fe744 100644
--- a/Telegram/SourceFiles/data/data_photo.cpp
+++ b/Telegram/SourceFiles/data/data_photo.cpp
@@ -169,10 +169,6 @@ bool PhotoData::uploading() const {
 	return (uploadingData != nullptr);
 }
 
-void PhotoData::unload() {
-	_replyPreview = nullptr;
-}
-
 Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
 	if (!_replyPreview) {
 		_replyPreview = std::make_unique<Data::ReplyPreview>(this);
diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h
index 976d0b35a..6c57bbed8 100644
--- a/Telegram/SourceFiles/data/data_photo.h
+++ b/Telegram/SourceFiles/data/data_photo.h
@@ -59,7 +59,6 @@ public:
 	void setWaitingForAlbum();
 	[[nodiscard]] bool waitingForAlbum() const;
 
-	void unload();
 	[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
 
 	void setRemoteLocation(
diff --git a/Telegram/SourceFiles/data/data_photo_media.cpp b/Telegram/SourceFiles/data/data_photo_media.cpp
index 8615f010c..620874fea 100644
--- a/Telegram/SourceFiles/data/data_photo_media.cpp
+++ b/Telegram/SourceFiles/data/data_photo_media.cpp
@@ -38,8 +38,7 @@ Image *PhotoMedia::thumbnailInline() const {
 		if (!image.isNull()) {
 			_inlineThumbnail = std::make_unique<Image>(
 				std::make_unique<Images::ImageSource>(
-					std::move(image),
-					"PNG"));
+					std::move(image)));
 		}
 	}
 	return _inlineThumbnail.get();
@@ -79,7 +78,7 @@ void PhotoMedia::set(PhotoSize size, QImage image) {
 			Qt::SmoothTransformation);
 	}
 	_images[index] = std::make_unique<Image>(
-		std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
+		std::make_unique<Images::ImageSource>(std::move(image)));
 	_owner->session().downloaderTaskFinished().notify();
 }
 
@@ -114,14 +113,12 @@ void PhotoMedia::automaticLoad(
 void PhotoMedia::collectLocalData(not_null<PhotoMedia*> local) {
 	if (const auto image = local->_inlineThumbnail.get()) {
 		_inlineThumbnail = std::make_unique<Image>(
-			std::make_unique<Images::ImageSource>(image->original(), "PNG"));
+			std::make_unique<Images::ImageSource>(image->original()));
 	}
 	for (auto i = 0; i != kPhotoSizeCount; ++i) {
 		if (const auto image = local->_images[i].get()) {
 			_images[i] = std::make_unique<Image>(
-				std::make_unique<Images::ImageSource>(
-					image->original(),
-					"PNG"));
+				std::make_unique<Images::ImageSource>(image->original()));
 		}
 	}
 }
diff --git a/Telegram/SourceFiles/data/data_reply_preview.cpp b/Telegram/SourceFiles/data/data_reply_preview.cpp
index b98737fec..0ec61e76c 100644
--- a/Telegram/SourceFiles/data/data_reply_preview.cpp
+++ b/Telegram/SourceFiles/data/data_reply_preview.cpp
@@ -25,6 +25,8 @@ ReplyPreview::ReplyPreview(not_null<PhotoData*> photo)
 : _photo(photo) {
 }
 
+ReplyPreview::~ReplyPreview() = default;
+
 void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
 	if (image->isNull() || !image->loaded()) {
 		return;
@@ -53,8 +55,7 @@ void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
 		outerSize);
 	_image = std::make_unique<Image>(
 		std::make_unique<Images::ImageSource>(
-			bitmap.toImage(),
-			"PNG"));
+			bitmap.toImage()));
 	_good = ((options & Images::Option::Blurred) == 0);
 }
 
diff --git a/Telegram/SourceFiles/data/data_reply_preview.h b/Telegram/SourceFiles/data/data_reply_preview.h
index 4e9f0cd74..3c31cbe84 100644
--- a/Telegram/SourceFiles/data/data_reply_preview.h
+++ b/Telegram/SourceFiles/data/data_reply_preview.h
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+class Image;
 class DocumentData;
 class PhotoData;
 
@@ -20,6 +21,7 @@ class ReplyPreview {
 public:
 	explicit ReplyPreview(not_null<DocumentData*> document);
 	explicit ReplyPreview(not_null<PhotoData*> photo);
+	~ReplyPreview();
 
 	[[nodiscard]] Image *image(Data::FileOrigin origin);
 
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 2d717c2af..797eb12e9 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "core/mime_type.h" // Core::IsMimeSticker
 #include "core/crash_reports.h" // CrashReports::SetAnnotation
 #include "ui/image/image.h"
-#include "ui/image/image_source.h" // Images::LocalFileSource
+#include "ui/image/image_source.h" // Images::ImageSource
 #include "ui/image/image_location_factory.h" // Images::FromPhotoSize
 #include "export/export_controller.h"
 #include "export/view/export_view_panel_controller.h"
@@ -1080,7 +1080,6 @@ Session::~Session() {
 	_session->notifications().clearAllFast();
 
 	clear();
-	Images::ClearRemote();
 }
 
 template <typename Method>
@@ -3823,10 +3822,8 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
 
 	_wallpapers.push_back(Data::Legacy1DefaultWallPaper());
 	_wallpapers.back().setLocalImageAsThumbnail(std::make_shared<Image>(
-		std::make_unique<Images::LocalFileSource>(
-			qsl(":/gui/art/bg_initial.jpg"),
-			QByteArray(),
-			"JPG")));
+		std::make_unique<Images::ImageSource>(
+			u":/gui/art/bg_initial.jpg"_q)));
 	for (const auto &paper : data) {
 		if (const auto parsed = Data::WallPaper::Create(paper)) {
 			_wallpapers.push_back(*parsed);
@@ -3838,10 +3835,8 @@ void Session::setWallpapers(const QVector<MTPWallPaper> &data, int32 hash) {
 	if (defaultFound == end(_wallpapers)) {
 		_wallpapers.push_back(Data::DefaultWallPaper());
 		_wallpapers.back().setLocalImageAsThumbnail(std::make_shared<Image>(
-			std::make_unique<Images::LocalFileSource>(
-				qsl(":/gui/arg/bg.jpg"),
-				QByteArray(),
-				"JPG")));
+			std::make_unique<Images::ImageSource>(
+				u":/gui/arg/bg.jpg"_q)));
 	}
 }
 
diff --git a/Telegram/SourceFiles/data/data_wall_paper.cpp b/Telegram/SourceFiles/data/data_wall_paper.cpp
index b1140e184..c938e0163 100644
--- a/Telegram/SourceFiles/data/data_wall_paper.cpp
+++ b/Telegram/SourceFiles/data/data_wall_paper.cpp
@@ -183,12 +183,6 @@ QString WallPaper::shareUrl() const {
 		: base + '?' + params.join('&');
 }
 
-void WallPaper::loadLocalThumbnail() const {
-	if (_thumbnail) {
-		_thumbnail->load(fileOrigin());
-	}
-}
-
 void WallPaper::loadDocumentThumbnail() const {
 	if (_document) {
 		_document->loadThumbnail(fileOrigin());
diff --git a/Telegram/SourceFiles/data/data_wall_paper.h b/Telegram/SourceFiles/data/data_wall_paper.h
index cd8eab377..4af1c1fd1 100644
--- a/Telegram/SourceFiles/data/data_wall_paper.h
+++ b/Telegram/SourceFiles/data/data_wall_paper.h
@@ -34,7 +34,6 @@ public:
 	[[nodiscard]] QString shareUrl() const;
 
 	void loadDocument() const;
-	void loadLocalThumbnail() const;
 	void loadDocumentThumbnail() const;
 	[[nodiscard]] FileOrigin fileOrigin() const;
 
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index ecb227f20..2b471eba8 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -6921,7 +6921,6 @@ void HistoryWidget::drawPinnedBar(Painter &p) {
 
 	auto top = _topBar->bottomNoMargins();
 	bool serviceColor = false, hasForward = readyToForward();
-	ImagePtr preview;
 	p.fillRect(myrtlrect(0, top, width(), st::historyReplyHeight), st::historyPinnedBg);
 
 	top += st::msgReplyPadding.top();
diff --git a/Telegram/SourceFiles/history/view/media/history_view_contact.cpp b/Telegram/SourceFiles/history/view/media/history_view_contact.cpp
index 4ff76fb0b..602b6e18f 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_contact.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_contact.cpp
@@ -80,6 +80,10 @@ Contact::Contact(
 
 Contact::~Contact() {
 	history()->owner().unregisterContactView(_userId, _parent);
+	if (_userpic) {
+		_userpic = nullptr;
+		_parent->checkHeavyPart();
+	}
 }
 
 void Contact::updateSharedContactUserId(UserId userId) {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
index 29fc3480f..7f03edc7a 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp
@@ -421,13 +421,9 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
 		}
 	} else {
 		ensureDataMediaCreated();
-		const auto good = _dataMedia->goodThumbnail();
-		if (good && good->loaded()) {
+		if (const auto good = _dataMedia->goodThumbnail()) {
 			p.drawPixmap(rthumb.topLeft(), good->pixSingle({}, _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
 		} else {
-			if (good) {
-				good->load({});
-			}
 			const auto normal = _dataMedia->thumbnail();
 			if (normal) {
 				if (normal->width() >= kUseNonBlurredThreshold
@@ -657,8 +653,7 @@ void Gif::validateVideoThumbnail() const {
 		std::make_unique<Images::ImageSource>(
 			(info.thumbnail.isNull()
 				? Image::BlankMedia()->original()
-				: info.thumbnail),
-			"PNG"));
+				: info.thumbnail)));
 }
 
 void Gif::drawCornerStatus(Painter &p, bool selected, QPoint position) const {
@@ -1179,23 +1174,18 @@ void Gif::validateGroupedCache(
 	ensureDataMediaCreated();
 
 	const auto good = _dataMedia->goodThumbnail();
-	const auto useGood = (good && good->loaded());
 	const auto thumb = _dataMedia->thumbnail();
-	const auto useThumb = (thumb != nullptr);
-	const auto image = useGood
+	const auto image = good
 		? good
-		: useThumb
+		: thumb
 		? thumb
 		: _dataMedia->thumbnailInline();
-	const auto blur = !useGood
-		&& (!useThumb
+	const auto blur = !good
+		&& (!thumb
 			|| (thumb->width() < kUseNonBlurredThreshold
 				&& thumb->height() < kUseNonBlurredThreshold));
-	if (good && !useGood) {
-		good->load({});
-	}
 
-	const auto loadLevel = useGood ? 3 : useThumb ? 2 : image ? 1 : 0;
+	const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0;
 	const auto width = geometry.width();
 	const auto height = geometry.height();
 	const auto options = Option::Smooth
@@ -1312,6 +1302,7 @@ bool Gif::hasHeavyPart() const {
 void Gif::unloadHeavyPart() {
 	stopAnimation();
 	_dataMedia = nullptr;
+	_videoThumbnailFrame = nullptr;
 }
 
 void Gif::refreshParentId(not_null<HistoryItem*> realParent) {
@@ -1498,7 +1489,6 @@ void Gif::stopAnimation() {
 	if (_streamed) {
 		setStreamed(nullptr);
 		history()->owner().requestViewResize(_parent);
-		_data->unload();
 	}
 }
 
diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h
index 9a489cb7e..723cc836c 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_gif.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/media/history_view_file.h"
 #include "media/streaming/media_streaming_common.h"
 
+class Image;
 struct HistoryMessageVia;
 struct HistoryMessageReply;
 struct HistoryMessageForwarded;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp
index 64cdd46ae..f44ec7ec3 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp
@@ -72,7 +72,7 @@ void LargeEmoji::draw(Painter &p, const QRect &r, bool selected) {
 	const auto o = Data::FileOrigin();
 	const auto skip = st::largeEmojiSkip - 2 * st::largeEmojiOutline;
 	for (const auto &image : images) {
-		image->load(Data::FileOrigin());
+		image->load();
 		const auto w = image->width() / cIntRetinaFactor();
 		if (image->loaded()) {
 			const auto h = image->height() / cIntRetinaFactor();
diff --git a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h
index 554cd6d34..b90ddc951 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/media/history_view_media_unwrapped.h"
 #include "ui/text/text_isolated_emoji.h"
 
+class Image;
+
 namespace Data {
 struct FileOrigin;
 } // namespace Data
diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.cpp b/Telegram/SourceFiles/history/view/media/history_view_location.cpp
index d4b9ea0b7..70f2b7b8c 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_location.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_location.cpp
@@ -51,6 +51,13 @@ Location::Location(
 	}
 }
 
+Location::~Location() {
+	if (_media) {
+		_media = nullptr;
+		_parent->checkHeavyPart();
+	}
+}
+
 void Location::ensureMediaCreated() const {
 	if (_media) {
 		return;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.h b/Telegram/SourceFiles/history/view/media/history_view_location.h
index 2538dc3e5..db7fe50ef 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_location.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_location.h
@@ -25,6 +25,7 @@ public:
 		Data::LocationPoint point,
 		const QString &title = QString(),
 		const QString &description = QString());
+	~Location();
 
 	void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
 	TextState textState(QPoint point, StateRequest request) const override;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp
index 95e04b7cf..0969a95c5 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp
@@ -1523,6 +1523,10 @@ void Poll::toggleLinkRipple(bool pressed) {
 
 Poll::~Poll() {
 	history()->owner().unregisterPollView(_poll, _parent);
+	if (hasHeavyPart()) {
+		unloadHeavyPart();
+		_parent->checkHeavyPart();
+	}
 }
 
 } // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
index 02c0dcc20..b7dae0d88 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
@@ -213,9 +213,6 @@ QPixmap Sticker::paintedPixmap(bool selected) const {
 	const auto h = _size.height();
 	const auto &c = st::msgStickerOverlay;
 	const auto good = _dataMedia->goodThumbnail();
-	if (good && !good->loaded()) {
-		good->load({});
-	}
 	if (const auto image = _dataMedia->getStickerLarge()) {
 		return selected
 			? image->pixColored(o, c, w, h)
@@ -227,7 +224,7 @@ QPixmap Sticker::paintedPixmap(bool selected) const {
 	//	return selected
 	//		? blurred->pixBlurredColored(o, c, w, h)
 	//		: blurred->pixBlurred(o, w, h);
-	} else if (good && good->loaded()) {
+	} else if (good) {
 		return selected
 			? good->pixColored(o, c, w, h)
 			: good->pix(o, w, h);
diff --git a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp
index 7eacc1ec7..8f8cd7b19 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp
@@ -207,14 +207,10 @@ void ThemeDocument::validateThumbnail() const {
 	}
 	ensureDataMediaCreated();
 	if (const auto good = _dataMedia->goodThumbnail()) {
-		if (good->loaded()) {
-			prepareThumbnailFrom(good, 1);
-			return;
-		} else {
-			good->load({});
-		}
+		prepareThumbnailFrom(good, 1);
+		return;
 	}
-	if (_thumbnailGood >= 0 || !_dataMedia->thumbnail()) {
+	if (_thumbnailGood >= 0) {
 		return;
 	}
 	if (const auto normal = _dataMedia->thumbnail()) {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_theme_document.h b/Telegram/SourceFiles/history/view/media/history_view_theme_document.h
index 3253bce9b..e0c9427ee 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_theme_document.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.h
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "history/view/media/history_view_file.h"
 
+class Image;
+
 namespace Data {
 class DocumentMedia;
 } // namespace Data
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
index 22849a645..122891308 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
@@ -315,9 +315,6 @@ void Gif::validateThumbnail(
 		bool good) const {
 	if (!image || (_thumbGood && !good)) {
 		return;
-	} else if (!image->loaded()) {
-		image->load(fileOrigin());
-		return;
 	} else if ((_thumb.size() == size * cIntRetinaFactor())
 		&& (_thumbGood || !good)) {
 		return;
@@ -393,7 +390,6 @@ void Gif::radialAnimationCallback(crl::time now) const {
 
 void Gif::unloadHeavyPart() {
 	_gif.reset();
-	getShownDocument()->unload();
 	_dataMedia = nullptr;
 }
 
@@ -404,7 +400,6 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
 		if (_gif) {
 			if (_gif->state() == State::Error) {
 				_gif.setBad();
-				getShownDocument()->unload();
 			} else if (_gif->ready() && !_gif->started()) {
 				if (_gif->width() * _gif->height() > kMaxInlineArea) {
 					getShownDocument()->dimensions = QSize(
@@ -608,7 +603,6 @@ TextState Photo::getState(
 }
 
 void Photo::unloadHeavyPart() {
-	getShownPhoto()->unload();
 	_photoMedia = nullptr;
 }
 
@@ -653,9 +647,6 @@ void Photo::validateThumbnail(
 		bool good) const {
 	if (!image || (_thumbGood && !good)) {
 		return;
-	} else if (!image->loaded()) {
-		image->load(fileOrigin());
-		return;
 	} else if ((_thumb.size() == size * cIntRetinaFactor())
 		&& (_thumbGood || !good)) {
 		return;
@@ -802,28 +793,23 @@ void Video::prepareThumbnail(QSize size) const {
 	if (!thumb) {
 		return;
 	}
-	const auto origin = fileOrigin();
-	if (thumb->loaded()) {
-		if (_thumb.size() != size * cIntRetinaFactor()) {
-			const auto width = size.width();
-			const auto height = size.height();
-			auto w = qMax(style::ConvertScale(thumb->width()), 1);
-			auto h = qMax(style::ConvertScale(thumb->height()), 1);
-			if (w * height > h * width) {
-				if (height < h) {
-					w = w * height / h;
-					h = height;
-				}
-			} else {
-				if (width < w) {
-					h = h * width / w;
-					w = width;
-				}
+	if (_thumb.size() != size * cIntRetinaFactor()) {
+		const auto width = size.width();
+		const auto height = size.height();
+		auto w = qMax(style::ConvertScale(thumb->width()), 1);
+		auto h = qMax(style::ConvertScale(thumb->height()), 1);
+		if (w * height > h * width) {
+			if (height < h) {
+				w = w * height / h;
+				h = height;
+			}
+		} else {
+			if (width < w) {
+				h = h * width / w;
+				w = width;
 			}
-			_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
 		}
-	} else {
-		thumb->load(origin);
+		_thumb = thumb->pixNoCache({}, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
 	}
 }
 
@@ -1497,9 +1483,6 @@ void Game::ensureDataMediaCreated(not_null<PhotoData*> photo) const {
 void Game::validateThumbnail(Image *image, QSize size, bool good) const {
 	if (!image || (_thumbGood && !good)) {
 		return;
-	} else if (!image->loaded()) {
-		image->load(fileOrigin());
-		return;
 	} else if ((_thumb.size() == size * cIntRetinaFactor())
 		&& (_thumbGood || !good)) {
 		return;
@@ -1565,14 +1548,8 @@ void Game::radialAnimationCallback(crl::time now) const {
 
 void Game::unloadHeavyPart() {
 	_gif.reset();
-	if (const auto document = getResultDocument()) {
-		document->unload();
-		_documentMedia = nullptr;
-	}
-	if (const auto photo = getResultPhoto()) {
-		photo->unload();
-		_photoMedia = nullptr;
-	}
+	_documentMedia = nullptr;
+	_photoMedia = nullptr;
 }
 
 void Game::clipCallback(Media::Clip::Notification notification) {
@@ -1582,7 +1559,6 @@ void Game::clipCallback(Media::Clip::Notification notification) {
 		if (_gif) {
 			if (_gif->state() == State::Error) {
 				_gif.setBad();
-				getResultDocument()->unload();
 			} else if (_gif->ready() && !_gif->started()) {
 				if (_gif->width() * _gif->height() > kMaxInlineArea) {
 					getResultDocument()->dimensions = QSize(
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h
index 1f58116f1..2295af96f 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h
@@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "layout.h"
 #include "ui/text/text.h"
 
+class Image;
+
 namespace Data {
 class CloudImageView;
 } // namespace Data
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp
index b76b72c46..10b84c87d 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp
@@ -329,15 +329,6 @@ bool Result::onChoose(Layout::ItemBase *layout) {
 	return true;
 }
 
-void Result::unload() {
-	if (_document) {
-		_document->unload();
-	}
-	if (_photo) {
-		_photo->unload();
-	}
-}
-
 void Result::openFile() {
 	if (_document) {
 		DocumentOpenClickHandler(_document).onClick({});
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.h b/Telegram/SourceFiles/inline_bots/inline_bot_result.h
index b778b469b..45395a102 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_result.h
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.h
@@ -52,7 +52,6 @@ public:
 	// inline bot result. If it returns true you need to send this result.
 	bool onChoose(Layout::ItemBase *layout);
 
-	void unload();
 	void openFile();
 	void cancelFile();
 
diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
index a3855e7d9..fafe5299f 100644
--- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp
@@ -297,21 +297,9 @@ void Inner::hideFinished() {
 }
 
 void Inner::clearHeavyData() {
-	const auto unload = [](const auto &item) {
-		if (const auto document = item->getDocument()) {
-			document->unload();
-		}
-		if (const auto photo = item->getPhoto()) {
-			photo->unload();
-		}
-		if (const auto result = item->getResult()) {
-			result->unload();
-		}
-		item->unloadHeavyPart();
-	};
 	clearInlineRows(false);
 	for (const auto &[result, layout] : _inlineLayouts) {
-		unload(layout);
+		layout->unloadHeavyPart();
 	}
 }
 
diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp
index 78dd136a7..73ad80d97 100644
--- a/Telegram/SourceFiles/main/main_account.cpp
+++ b/Telegram/SourceFiles/main/main_account.cpp
@@ -442,7 +442,6 @@ void Account::loggedOut() {
 	Local::reset();
 
 	cSetOtherOnline(0);
-	Images::ClearRemote();
 }
 
 void Account::destroyMtpKeys(MTP::AuthKeysList &&keys) {
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 4a04e8453..c98ce3c4a 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -1383,8 +1383,6 @@ float64 MainWidget::chatBackgroundProgress() const {
 			return 1.;
 		} else if (const auto document = _background->data.document()) {
 			return _background->dataMedia->progress();
-		} else if (const auto thumbnail = _background->data.localThumbnail()) {
-			return thumbnail->progress();
 		}
 	}
 	return 1.;
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index c82ff75f0..240c1c0c3 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -22,6 +22,7 @@ class HistoryWidget;
 class StackItem;
 struct FileLoadResult;
 class History;
+class Image;
 
 namespace Api {
 struct SendAction;
diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
index f32008236..461e0cb2d 100644
--- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp
@@ -241,10 +241,6 @@ void GroupThumbs::Thumb::validateImage() {
 	if (!_full.isNull() || !_image) {
 		return;
 	}
-	_image->load(_origin);
-	if (!_image->loaded()) {
-		return;
-	}
 
 	const auto pixSize = wantedPixSize();
 	if (pixSize.width() > st::mediaviewGroupWidthMax) {
diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
index 625671813..f8c4664bf 100644
--- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp
@@ -2214,15 +2214,10 @@ void OverlayWidget::initStreamingThumbnail() {
 	Expects(_document != nullptr);
 
 	const auto good = _documentMedia->goodThumbnail();
-	const auto useGood = (good && good->loaded());
+	const auto useGood = (good != nullptr);
 	const auto thumbnail = _documentMedia->thumbnail();
 	const auto useThumb = (thumbnail != nullptr);
 	const auto blurred = _documentMedia->thumbnailInline();
-	if (good && !useGood) {
-		good->load({});
-	} else if (thumbnail) {
-		thumbnail->load(fileOrigin());
-	}
 	const auto size = useGood ? good->size() : _document->dimensions;
 	if (!useGood && !thumbnail && !blurred) {
 		return;
diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp
index 99e73c292..ed9ee3e3d 100644
--- a/Telegram/SourceFiles/media/view/media_view_pip.cpp
+++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp
@@ -1379,16 +1379,14 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
 		? nullptr
 		: _data->createMediaView();
 	const auto good = use ? use->goodThumbnail() : nullptr;
-	const auto useGood = (good && good->loaded());
 	const auto thumb = use ? use->thumbnail() : nullptr;
-	const auto useThumb = (thumb && thumb->loaded());
 	const auto blurred = use ? use->thumbnailInline() : nullptr;
 
 	const auto state = !cover.isNull()
 		? ThumbState::Cover
-		: useGood
+		: good
 		? ThumbState::Good
-		: useThumb
+		: thumb
 		? ThumbState::Thumb
 		: blurred
 		? ThumbState::Inline
@@ -1406,14 +1404,9 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
 				request,
 				std::move(_preparedCoverStorage));
 		} else if (!request.resize.isEmpty()) {
-			if (good && !useGood) {
-				good->load({});
-			} else if (thumb && !useThumb) {
-				thumb->load(_contextId);
-			}
 			using Option = Images::Option;
 			const auto options = Option::Smooth
-				| (useGood ? Option(0) : Option::Blurred)
+				| (good ? Option(0) : Option::Blurred)
 				| Option::RoundedLarge
 				| ((request.corners & RectPart::TopLeft)
 					? Option::RoundedTopLeft
@@ -1427,9 +1420,9 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
 				| ((request.corners & RectPart::BottomLeft)
 					? Option::RoundedBottomLeft
 					: Option(0));
-			_preparedCoverStorage = (useGood
+			_preparedCoverStorage = (good
 				? good
-				: useThumb
+				: thumb
 				? thumb
 				: blurred
 				? blurred
diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp
index 1001ade11..439aaefa2 100644
--- a/Telegram/SourceFiles/overview/overview_layout.cpp
+++ b/Telegram/SourceFiles/overview/overview_layout.cpp
@@ -358,8 +358,6 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
 }
 
 void Photo::setPixFrom(not_null<Image*> image) {
-	Expects(image->loaded());
-
 	const auto size = _width * cIntRetinaFactor();
 	auto img = image->original();
 	if (!_goodLoaded) {
diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h
index a81d40a18..f3f51ca8f 100644
--- a/Telegram/SourceFiles/overview/overview_layout.h
+++ b/Telegram/SourceFiles/overview/overview_layout.h
@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/effects/radial_animation.h"
 #include "styles/style_overview.h"
 
+class Image;
+
 namespace style {
 struct RoundCheckbox;
 } // namespace style
diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp
index 3477ca29f..8c72a50f1 100644
--- a/Telegram/SourceFiles/settings/settings_chat.cpp
+++ b/Telegram/SourceFiles/settings/settings_chat.cpp
@@ -630,9 +630,7 @@ void ChooseFromFile(
 		}
 		auto local = Data::CustomWallPaper();
 		local.setLocalImageAsThumbnail(std::make_shared<Image>(
-			std::make_unique<Images::ImageSource>(
-				std::move(image),
-				"JPG")));
+			std::make_unique<Images::ImageSource>(std::move(image))));
 		Ui::show(Box<BackgroundPreviewBox>(session, local));
 	});
 	FileDialog::GetOpenPath(
diff --git a/Telegram/SourceFiles/ui/image/image.cpp b/Telegram/SourceFiles/ui/image/image.cpp
index 08c916da4..5b2f37f69 100644
--- a/Telegram/SourceFiles/ui/image/image.cpp
+++ b/Telegram/SourceFiles/ui/image/image.cpp
@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/image/image.h"
 
 #include "ui/image/image_source.h"
-#include "core/media_active_cache.h"
 #include "storage/cache/storage_cache_database.h"
 #include "data/data_session.h"
 #include "data/data_file_origin.h"
@@ -21,31 +20,6 @@ using namespace Images;
 namespace Images {
 namespace {
 
-// After 128 MB of unpacked images we try to clear some memory.
-constexpr auto kMemoryForCache = 128 * 1024 * 1024;
-
-std::unordered_map<InMemoryKey, std::unique_ptr<Image>> StorageImages;
-std::unordered_map<InMemoryKey, std::unique_ptr<Image>> GeoPointImages;
-
-int64 ComputeUsage(QSize size) {
-	return int64(size.width()) * size.height() * 4;
-}
-
-int64 ComputeUsage(const QPixmap &image) {
-	return ComputeUsage(image.size());
-}
-
-int64 ComputeUsage(const QImage &image) {
-	return ComputeUsage(image.size());
-}
-
-[[nodiscard]] Core::MediaActiveCache<const Image> &ActiveCache() {
-	static auto Instance = Core::MediaActiveCache<const Image>(
-		kMemoryForCache,
-		[](const Image *image) { image->unload(); });
-	return Instance;
-}
-
 uint64 PixKey(int width, int height, Options options) {
 	return static_cast<uint64>(width)
 		| (static_cast<uint64>(height) << 24)
@@ -111,54 +85,6 @@ QImage FromInlineBytes(const QByteArray &bytes) {
 	return App::readImage(ExpandInlineBytes(bytes));
 }
 
-void ClearRemote() {
-	base::take(StorageImages);
-	base::take(GeoPointImages);
-}
-
-void ClearAll() {
-	ActiveCache().clear();
-	ClearRemote();
-}
-
-ImagePtr Create(QImage &&image, QByteArray format) {
-	return ImagePtr(new Image(std::make_unique<ImageSource>(
-		std::move(image),
-		format)));
-}
-
-template <typename SourceType>
-ImagePtr Create(
-		const StorageImageLocation &location,
-		int size,
-		const QByteArray &bytes) {
-	if (!location.valid()) {
-		return ImagePtr();
-	}
-	const auto key = inMemoryKey(location);
-	const auto i = StorageImages.find(key);
-	const auto found = (i != end(StorageImages));
-	const auto image = found
-		? i->second.get()
-		: StorageImages.emplace(
-			key,
-			std::make_unique<Image>(
-				std::make_unique<SourceType>(location, size))
-		).first->second.get();
-	if (found) {
-		image->refreshFileReference(location.fileReference());
-	}
-	if (!bytes.isEmpty()) {
-		image->setImageBytes(bytes);
-	}
-	return ImagePtr(image);
-
-}
-
-ImagePtr Create(const StorageImageLocation &location, int size) {
-	return Create<StorageSource>(location, size, QByteArray());
-}
-
 QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
 	for (const auto &attribute : attributes) {
 		if (attribute.type() == mtpc_documentAttributeImageSize) {
@@ -169,33 +95,13 @@ QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
 	return QSize();
 }
 
-ImagePtr Create(const GeoPointLocation &location) {
-	const auto key = inMemoryKey(location);
-	const auto i = GeoPointImages.find(key);
-	const auto image = (i != end(GeoPointImages))
-		? i->second.get()
-		: GeoPointImages.emplace(
-			key,
-			std::make_unique<Image>(
-				std::make_unique<GeoPointSource>(location))
-		).first->second.get();
-	return ImagePtr(image);
-}
-
 } // namespace Images
 
 Image::Image(std::unique_ptr<Source> &&source)
 : _source(std::move(source)) {
 }
 
-void Image::replaceSource(std::unique_ptr<Source> &&source) {
-	const auto width = _source->width();
-	const auto height = _source->height();
-	if (width > 0 && height > 0) {
-		source->setInformation(_source->bytesSize(), width, height);
-	}
-	_source = std::move(source);
-}
+Image::~Image() = default;
 
 not_null<Image*> Image::Empty() {
 	static auto result = [] {
@@ -206,7 +112,7 @@ not_null<Image*> Image::Empty() {
 			QImage::Format_ARGB32_Premultiplied);
 		data.fill(Qt::transparent);
 		data.setDevicePixelRatio(cRetinaFactor());
-		return Image(std::make_unique<ImageSource>(std::move(data), "GIF"));
+		return Image(std::make_unique<ImageSource>(std::move(data)));
 	}();
 	return &result;
 }
@@ -220,7 +126,7 @@ not_null<Image*> Image::BlankMedia() {
 			QImage::Format_ARGB32_Premultiplied);
 		data.fill(Qt::black);
 		data.setDevicePixelRatio(cRetinaFactor());
-		return Image(std::make_unique<ImageSource>(std::move(data), "GIF"));
+		return Image(std::make_unique<ImageSource>(std::move(data)));
 	}();
 	return &result;
 }
@@ -248,7 +154,6 @@ const QPixmap &Image::pix(
 		auto p = pixNoCache(origin, w, h, options);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -287,7 +192,6 @@ const QPixmap &Image::pixRounded(
 		auto p = pixNoCache(origin, w, h, options);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -311,7 +215,6 @@ const QPixmap &Image::pixCircled(
 		auto p = pixNoCache(origin, w, h, options);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -335,7 +238,6 @@ const QPixmap &Image::pixBlurredCircled(
 		auto p = pixNoCache(origin, w, h, options);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -359,7 +261,6 @@ const QPixmap &Image::pixBlurred(
 		auto p = pixNoCache(origin, w, h, options);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -384,7 +285,6 @@ const QPixmap &Image::pixColored(
 		auto p = pixColoredNoCache(origin, add, w, h, true);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -409,7 +309,6 @@ const QPixmap &Image::pixBlurredColored(
 		auto p = pixBlurredColoredNoCache(origin, add, w, h);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -453,13 +352,9 @@ const QPixmap &Image::pixSingle(
 	auto k = SinglePixKey(options);
 	auto i = _sizesCache.constFind(k);
 	if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
-		if (i != _sizesCache.cend()) {
-			ActiveCache().decrement(ComputeUsage(*i));
-		}
 		auto p = pixNoCache(origin, w, h, options, outerw, outerh, colored);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -499,13 +394,9 @@ const QPixmap &Image::pixBlurredSingle(
 	auto k = SinglePixKey(options);
 	auto i = _sizesCache.constFind(k);
 	if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
-		if (i != _sizesCache.cend()) {
-			ActiveCache().decrement(ComputeUsage(*i));
-		}
 		auto p = pixNoCache(origin, w, h, options, outerw, outerh);
 		p.setDevicePixelRatio(cRetinaFactor());
 		i = _sizesCache.insert(k, p);
-		ActiveCache().increment(ComputeUsage(*i));
 	}
 	return i.value();
 }
@@ -518,9 +409,6 @@ QPixmap Image::pixNoCache(
 		int outerw,
 		int outerh,
 		const style::color *colored) const {
-	if (!loading()) {
-		const_cast<Image*>(this)->load(origin);
-	}
 	checkSource();
 
 	if (_data.isNull()) {
@@ -579,9 +467,6 @@ QPixmap Image::pixColoredNoCache(
 		int32 w,
 		int32 h,
 		bool smooth) const {
-	if (!loading()) {
-		const_cast<Image*>(this)->load(origin);
-	}
 	checkSource();
 
 	if (_data.isNull()) {
@@ -603,9 +488,6 @@ QPixmap Image::pixBlurredColoredNoCache(
 		style::color add,
 		int32 w,
 		int32 h) const {
-	if (!loading()) {
-		const_cast<Image*>(this)->load(origin);
-	}
 	checkSource();
 
 	if (_data.isNull()) {
@@ -627,22 +509,12 @@ QImage Image::original() const {
 	return _data;
 }
 
-void Image::load(Data::FileOrigin origin) {
+void Image::load() {
 	if (!loaded()) {
-		_source->load(origin);
+		_source->load();
 	}
 }
 
-void Image::loadEvenCancelled(Data::FileOrigin origin) {
-	if (!loaded()) {
-		_source->loadEvenCancelled(origin);
-	}
-}
-
-Storage::Cache::Key Image::cacheKey() const {
-	return _source->cacheKey();
-}
-
 bool Image::loaded() const {
 	checkSource();
 	return !_data.isNull();
@@ -653,46 +525,9 @@ void Image::checkSource() const {
 	if (_data.isNull() && !data.isNull()) {
 		invalidateSizeCache();
 		_data = std::move(data);
-		ActiveCache().increment(ComputeUsage(_data));
 	}
-
-	ActiveCache().up(this);
-}
-
-void Image::unload() const {
-	_source->unload();
-	invalidateSizeCache();
-	ActiveCache().decrement(ComputeUsage(_data));
-	_data = QImage();
-}
-
-void Image::setDelayedStorageLocation(
-		Data::FileOrigin origin,
-		const StorageImageLocation &location) {
-	_source->setDelayedStorageLocation(location);
-	if (!loaded()) {
-		_source->performDelayedLoad(origin);
-	}
-}
-
-void Image::setImageBytes(const QByteArray &bytes) {
-	_source->setImageBytes(bytes);
-	checkSource();
 }
 
 void Image::invalidateSizeCache() const {
-	auto &cache = ActiveCache();
-	for (const auto &image : std::as_const(_sizesCache)) {
-		cache.decrement(ComputeUsage(image));
-	}
 	_sizesCache.clear();
 }
-
-Image::~Image() {
-	if (this != Empty() && this != BlankMedia()) {
-		invalidateSizeCache();
-		ActiveCache().decrement(ComputeUsage(_data));
-		_data = QImage();
-		ActiveCache().remove(this);
-	}
-}
diff --git a/Telegram/SourceFiles/ui/image/image.h b/Telegram/SourceFiles/ui/image/image.h
index 373932f67..340ddab3b 100644
--- a/Telegram/SourceFiles/ui/image/image.h
+++ b/Telegram/SourceFiles/ui/image/image.h
@@ -16,16 +16,9 @@ namespace Images {
 [[nodiscard]] QByteArray ExpandInlineBytes(const QByteArray &bytes);
 [[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes);
 
-void ClearRemote();
-void ClearAll();
-
 [[nodiscard]] QSize GetSizeForDocument(
 	const QVector<MTPDocumentAttribute> &attributes);
 
-ImagePtr Create(QImage &&data, QByteArray format);
-ImagePtr Create(const StorageImageLocation &location, int size = 0);
-ImagePtr Create(const GeoPointLocation &location);
-
 class Source {
 public:
 	Source() = default;
@@ -35,31 +28,11 @@ public:
 	Source &operator=(Source &&other) = delete;
 	virtual ~Source() = default;
 
-	virtual void load(Data::FileOrigin origin) = 0;
-	virtual void loadEvenCancelled(Data::FileOrigin origin) = 0;
+	virtual void load() = 0;
 	virtual QImage takeLoaded() = 0;
-	virtual void unload() = 0;
-
-	virtual bool loading() = 0;
-	virtual bool displayLoading() = 0;
-	virtual void cancel() = 0;
-	virtual float64 progress() = 0;
-	virtual int loadOffset() = 0;
-
-	virtual const StorageImageLocation &location() = 0;
-	virtual void refreshFileReference(const QByteArray &data) = 0;
-	virtual Storage::Cache::Key cacheKey() = 0;
-	virtual void setDelayedStorageLocation(
-		const StorageImageLocation &location) = 0;
-	virtual void performDelayedLoad(Data::FileOrigin origin) = 0;
-	virtual void setImageBytes(const QByteArray &bytes) = 0;
 
 	virtual int width() = 0;
 	virtual int height() = 0;
-	virtual int bytesSize() = 0;
-	virtual void setInformation(int size, int width, int height) = 0;
-
-	virtual QByteArray bytesForCache() = 0;
 
 };
 
@@ -69,8 +42,6 @@ class Image final {
 public:
 	explicit Image(std::unique_ptr<Images::Source> &&source);
 
-	void replaceSource(std::unique_ptr<Images::Source> &&source);
-
 	static not_null<Image*> Empty(); // 1x1 transparent
 	static not_null<Image*> BlankMedia(); // 1x1 black
 
@@ -145,21 +116,6 @@ public:
 		int32 w,
 		int32 h = 0) const;
 
-	bool loading() const {
-		return _source->loading();
-	}
-	bool displayLoading() const {
-		return _source->displayLoading();
-	}
-	void cancel() {
-		_source->cancel();
-	}
-	float64 progress() const {
-		return loaded() ? 1. : _source->progress();
-	}
-	int loadOffset() const {
-		return _source->loadOffset();
-	}
 	int width() const {
 		return _source->width();
 	}
@@ -169,32 +125,10 @@ public:
 	QSize size() const {
 		return { width(), height() };
 	}
-	int bytesSize() const {
-		return _source->bytesSize();
-	}
-	void setInformation(int size, int width, int height) {
-		_source->setInformation(size, width, height);
-	}
-	void load(Data::FileOrigin origin);
-	void loadEvenCancelled(Data::FileOrigin origin);
-	const StorageImageLocation &location() const {
-		return _source->location();
-	}
-	void refreshFileReference(const QByteArray &data) {
-		_source->refreshFileReference(data);
-	}
-	Storage::Cache::Key cacheKey() const;
-	QByteArray bytesForCache() const {
-		return _source->bytesForCache();
-	}
+	void load();
 
 	bool loaded() const;
 	bool isNull() const;
-	void unload() const;
-	void setDelayedStorageLocation(
-		Data::FileOrigin origin,
-		const StorageImageLocation &location);
-	void setImageBytes(const QByteArray &bytes);
 
 	~Image();
 
diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp
index 1b6553a86..f9f765c39 100644
--- a/Telegram/SourceFiles/ui/image/image_location.cpp
+++ b/Telegram/SourceFiles/ui/image/image_location.cpp
@@ -68,23 +68,6 @@ MTPInputPeer GenerateInputPeer(
 
 } // namespace
 
-ImagePtr::ImagePtr() : _data(Image::Empty()) {
-}
-
-ImagePtr::ImagePtr(not_null<Image*> data) : _data(data) {
-}
-
-Image *ImagePtr::operator->() const {
-	return _data;
-}
-Image *ImagePtr::get() const {
-	return _data;
-}
-
-ImagePtr::operator bool() const {
-	return !_data->isNull();
-}
-
 WebFileLocation WebFileLocation::Null;
 
 StorageFileLocation::StorageFileLocation(
diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h
index a041e2818..747912cb7 100644
--- a/Telegram/SourceFiles/ui/image/image_location.h
+++ b/Telegram/SourceFiles/ui/image/image_location.h
@@ -616,22 +616,6 @@ struct ImageWithLocation {
 	QImage preloaded;
 };
 
-class Image;
-class ImagePtr {
-public:
-	ImagePtr();
-	explicit ImagePtr(not_null<Image*> data);
-
-	Image *operator->() const;
-	Image *get() const;
-
-	explicit operator bool() const;
-
-private:
-	not_null<Image*> _data;
-
-};
-
 InMemoryKey inMemoryKey(const StorageFileLocation &location);
 
 inline InMemoryKey inMemoryKey(const StorageImageLocation &location) {
diff --git a/Telegram/SourceFiles/ui/image/image_source.cpp b/Telegram/SourceFiles/ui/image/image_source.cpp
index 61304fd5e..94a8ab19c 100644
--- a/Telegram/SourceFiles/ui/image/image_source.cpp
+++ b/Telegram/SourceFiles/ui/image/image_source.cpp
@@ -20,597 +20,45 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include <QtCore/QBuffer>
 
 namespace Images {
+namespace {
 
-ImageSource::ImageSource(QImage &&data, const QByteArray &format)
-: _data(std::move(data))
-, _format(format)
-, _width(_data.width())
-, _height(_data.height()) {
+[[nodiscard]] QByteArray ReadContent(const QString &path) {
+	auto file = QFile(path);
+	const auto good = (file.size() <= App::kImageSizeLimit)
+		&& file.open(QIODevice::ReadOnly);
+	return good ? file.readAll() : QByteArray();
 }
 
-void ImageSource::load(Data::FileOrigin origin) {
-	if (_data.isNull() && !_bytes.isEmpty()) {
-		_data = App::readImage(_bytes, &_format, false);
-	}
+[[nodiscard]] QImage ReadImage(const QByteArray &content) {
+	return App::readImage(content, nullptr, false, nullptr);
 }
 
-void ImageSource::loadEvenCancelled(Data::FileOrigin origin) {
-	load(origin);
+} // namespace
+
+ImageSource::ImageSource(const QString &path)
+: ImageSource(ReadContent(path)) {
+}
+
+ImageSource::ImageSource(const QByteArray &content)
+: ImageSource(ReadImage(content)) {
+}
+
+ImageSource::ImageSource(QImage &&data) : _data(std::move(data)) {
+}
+
+void ImageSource::load() {
 }
 
 QImage ImageSource::takeLoaded() {
-	load({});
 	return _data;
 }
 
-void ImageSource::unload() {
-	if (_bytes.isEmpty() && !_data.isNull()) {
-		if (_format != "JPG") {
-			_format = "PNG";
-		}
-		{
-			QBuffer buffer(&_bytes);
-			_data.save(&buffer, _format);
-		}
-		Assert(!_bytes.isEmpty());
-	}
-	_data = QImage();
-}
-
-bool ImageSource::loading() {
-	return false;
-}
-
-bool ImageSource::displayLoading() {
-	return false;
-}
-
-void ImageSource::cancel() {
-}
-
-float64 ImageSource::progress() {
-	return 1.;
-}
-
-int ImageSource::loadOffset() {
-	return 0;
-}
-
-const StorageImageLocation &ImageSource::location() {
-	return StorageImageLocation::Invalid();
-}
-
-void ImageSource::refreshFileReference(const QByteArray &data) {
-}
-
-Storage::Cache::Key ImageSource::cacheKey() {
-	return Storage::Cache::Key();
-}
-
-void ImageSource::setDelayedStorageLocation(
-	const StorageImageLocation &location) {
-}
-
-void ImageSource::performDelayedLoad(Data::FileOrigin origin) {
-}
-
-void ImageSource::setImageBytes(const QByteArray &bytes) {
-}
-
 int ImageSource::width() {
-	return _width;
+	return _data.width();
 }
 
 int ImageSource::height() {
-	return _height;
-}
-
-int ImageSource::bytesSize() {
-	return _bytes.size();
-}
-
-void ImageSource::setInformation(int size, int width, int height) {
-	if (width && height) {
-		_width = width;
-		_height = height;
-	}
-}
-
-QByteArray ImageSource::bytesForCache() {
-	auto result = QByteArray();
-	{
-		QBuffer buffer(&result);
-		if (!_data.save(&buffer, _format)) {
-			if (_data.save(&buffer, "PNG")) {
-				_format = "PNG";
-			}
-		}
-	}
-	return result;
-}
-
-LocalFileSource::LocalFileSource(
-	const QString &path,
-	const QByteArray &content,
-	const QByteArray &format,
-	QImage &&data)
-: _path(path)
-, _bytes(content)
-, _format(format)
-, _data(std::move(data))
-, _width(_data.width())
-, _height(_data.height()) {
-}
-
-void LocalFileSource::load(Data::FileOrigin origin) {
-	if (!_data.isNull()) {
-		return;
-	}
-	if (_bytes.isEmpty()) {
-		QFile f(_path);
-		if (f.size() <= App::kImageSizeLimit && f.open(QIODevice::ReadOnly)) {
-			_bytes = f.readAll();
-		}
-		if (_bytes.isEmpty()) {
-			_bytes = "(bad)";
-		}
-	}
-	if (_bytes != "(bad)") {
-		_data = App::readImage(_bytes, &_format, false, nullptr);
-	}
-	_width = std::max(_data.width(), 1);
-	_height = std::max(_data.height(), 1);
-}
-
-void LocalFileSource::loadEvenCancelled(Data::FileOrigin origin) {
-	load(origin);
-}
-
-QImage LocalFileSource::takeLoaded() {
-	return std::move(_data);
-}
-
-void LocalFileSource::unload() {
-	_data = QImage();
-}
-
-bool LocalFileSource::loading() {
-	return false;
-}
-
-bool LocalFileSource::displayLoading() {
-	return false;
-}
-
-void LocalFileSource::cancel() {
-}
-
-float64 LocalFileSource::progress() {
-	return 1.;
-}
-
-int LocalFileSource::loadOffset() {
-	return 0;
-}
-
-const StorageImageLocation &LocalFileSource::location() {
-	return StorageImageLocation::Invalid();
-}
-
-void LocalFileSource::refreshFileReference(const QByteArray &data) {
-}
-
-Storage::Cache::Key LocalFileSource::cacheKey() {
-	return Storage::Cache::Key();
-}
-
-void LocalFileSource::setDelayedStorageLocation(
-	const StorageImageLocation &location) {
-}
-
-void LocalFileSource::performDelayedLoad(Data::FileOrigin origin) {
-}
-
-void LocalFileSource::setImageBytes(const QByteArray &bytes) {
-	_bytes = bytes;
-	load({});
-}
-
-int LocalFileSource::width() {
-	ensureDimensionsKnown();
-	return _width;
-}
-
-int LocalFileSource::height() {
-	ensureDimensionsKnown();
-	return _height;
-}
-
-int LocalFileSource::bytesSize() {
-	ensureDimensionsKnown();
-	return _bytes.size();
-}
-
-void LocalFileSource::setInformation(int size, int width, int height) {
-	ensureDimensionsKnown(); // First load _bytes.
-	if (width && height) {
-		_width = width;
-		_height = height;
-	}
-}
-
-void LocalFileSource::ensureDimensionsKnown() {
-	if (!_width || !_height) {
-		load({});
-	}
-}
-
-QByteArray LocalFileSource::bytesForCache() {
-	ensureDimensionsKnown();
-	return (_bytes == "(bad)") ? QByteArray() : _bytes;
-}
-
-QImage RemoteSource::takeLoaded() {
-	if (!_loader || !_loader->finished()) {
-		return QImage();
-	}
-
-	if (_loader->cancelled()) {
-		_cancelled = true;
-		destroyLoader();
-		return QImage();
-	}
-	auto data = _loader->imageData(shrinkBox());
-	if (data.isNull()) {
-		// Bad content in the image.
-		data = Image::Empty()->original();
-	}
-
-	setInformation(_loader->bytes().size(), data.width(), data.height());
-
-	destroyLoader();
-
-	return data;
-}
-
-void RemoteSource::destroyLoader() {
-	if (!_loader) {
-		return;
-	}
-
-	const auto loader = base::take(_loader);
-	if (cancelled()) {
-		loader->cancel();
-	}
-}
-
-void RemoteSource::loadLocal() {
-	if (_loader) {
-		return;
-	}
-
-	_loader = createLoader(Data::FileOrigin(), LoadFromLocalOnly, true);
-	if (_loader) {
-		_loader->start();
-	}
-}
-
-void RemoteSource::setImageBytes(const QByteArray &bytes) {
-	if (bytes.isEmpty()) {
-		return;
-	} else if (_loader) {
-		unload();
-	}
-	_loader = createLoader({}, LoadFromLocalOnly, true);
-	_loader->finishWithBytes(bytes);
-
-	const auto location = this->location();
-	if (location.valid()
-		&& !bytes.isEmpty()
-		&& bytes.size() <= Storage::kMaxFileInMemory) {
-		Auth().data().cache().putIfEmpty(
-			location.file().cacheKey(),
-			Storage::Cache::Database::TaggedValue(
-				base::duplicate(bytes),
-				Data::kImageCacheTag));
-	}
-}
-
-bool RemoteSource::loading() {
-	return (_loader != nullptr);
-}
-
-void RemoteSource::load(Data::FileOrigin origin) {
-	if (!_loader) {
-		_loader = createLoader(origin, LoadFromCloudOrLocal, false);
-	}
-	if (_loader) {
-		_loader->start();
-	}
-}
-
-bool RemoteSource::cancelled() const {
-	return _cancelled;
-}
-
-void RemoteSource::loadEvenCancelled(Data::FileOrigin origin) {
-	_cancelled = false;
-	return load(origin);
-}
-
-bool RemoteSource::displayLoading() {
-	return _loader && (!_loader->loadingLocal() || !_loader->autoLoading());
-}
-
-void RemoteSource::cancel() {
-	if (!_loader) {
-		return;
-	}
-	_cancelled = true;
-	destroyLoader();
-}
-
-void RemoteSource::unload() {
-	base::take(_loader);
-}
-
-float64 RemoteSource::progress() {
-	return _loader ? _loader->currentProgress() : 0.;
-}
-
-int RemoteSource::loadOffset() {
-	return _loader ? _loader->currentOffset() : 0;
-}
-
-RemoteSource::~RemoteSource() {
-	unload();
-}
-
-const StorageImageLocation &RemoteSource::location() {
-	return StorageImageLocation::Invalid();
-}
-
-void RemoteSource::refreshFileReference(const QByteArray &data) {
-}
-
-void RemoteSource::setDelayedStorageLocation(
-	const StorageImageLocation &location) {
-}
-
-void RemoteSource::performDelayedLoad(Data::FileOrigin origin) {
-}
-
-QByteArray RemoteSource::bytesForCache() {
-	return QByteArray();
-}
-
-StorageSource::StorageSource(const StorageImageLocation &location, int size)
-: _location(location)
-, _size(size) {
-}
-
-void StorageSource::refreshFileReference(const QByteArray &data) {
-	_location.refreshFileReference(data);
-}
-
-const StorageImageLocation &StorageSource::location() {
-	return _location;
-}
-
-Storage::Cache::Key StorageSource::cacheKey() {
-	return _location.valid()
-		? _location.file().cacheKey()
-		: Storage::Cache::Key();
-}
-
-int StorageSource::width() {
-	return _location.width();
-}
-
-int StorageSource::height() {
-	return _location.height();
-}
-
-int StorageSource::bytesSize() {
-	return _size;
-}
-
-void StorageSource::setInformation(int size, int width, int height) {
-	if (size) {
-		_size = size;
-	}
-	if (width && height) {
-		_location.setSize(width, height);
-	}
-}
-
-QSize StorageSource::shrinkBox() const {
-	return QSize();
-}
-
-std::unique_ptr<FileLoader> StorageSource::createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) {
-	return _location.valid()
-		? std::make_unique<mtpFileLoader>(
-			_location.file(),
-			origin,
-			UnknownFileLocation,
-			QString(),
-			_size,
-			LoadToCacheAsWell,
-			fromCloud,
-			autoLoading,
-			Data::kImageCacheTag)
-		: nullptr;
-}
-
-WebCachedSource::WebCachedSource(
-	const WebFileLocation &location,
-	QSize box,
-	int size)
-: _location(location)
-, _box(box)
-, _size(size) {
-}
-
-WebCachedSource::WebCachedSource(
-	const WebFileLocation &location,
-	int width,
-	int height,
-	int size)
-: _location(location)
-, _width(width)
-, _height(height)
-, _size(size) {
-}
-
-Storage::Cache::Key WebCachedSource::cacheKey() {
-	return _location.isNull()
-		? Storage::Cache::Key()
-		: Data::WebDocumentCacheKey(_location);
-}
-
-int WebCachedSource::width() {
-	return _width;
-}
-
-int WebCachedSource::height() {
-	return _height;
-}
-
-int WebCachedSource::bytesSize() {
-	return _size;
-}
-
-void WebCachedSource::setInformation(int size, int width, int height) {
-	if (size) {
-		_size = size;
-	}
-	if (width && height) {
-		_width = width;
-		_height = height;
-	}
-}
-
-QSize WebCachedSource::shrinkBox() const {
-	return _box;
-}
-
-std::unique_ptr<FileLoader> WebCachedSource::createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) {
-	return !_location.isNull()
-		? std::make_unique<mtpFileLoader>(
-			_location,
-			_size,
-			fromCloud,
-			autoLoading,
-			Data::kImageCacheTag)
-		: nullptr;
-}
-
-GeoPointSource::GeoPointSource(const GeoPointLocation &location)
-: _location(location) {
-}
-
-Storage::Cache::Key GeoPointSource::cacheKey() {
-	return Data::GeoPointCacheKey(_location);
-}
-
-int GeoPointSource::width() {
-	return _location.width * _location.scale;
-}
-
-int GeoPointSource::height() {
-	return _location.height * _location.scale;
-}
-
-int GeoPointSource::bytesSize() {
-	return _size;
-}
-
-void GeoPointSource::setInformation(int size, int width, int height) {
-	Expects(_location.scale != 0);
-
-	if (size) {
-		_size = size;
-	}
-	if (width && height) {
-		_location.width = width / _location.scale;
-		_location.height = height / _location.scale;
-	}
-}
-
-QSize GeoPointSource::shrinkBox() const {
-	return QSize();
-}
-
-std::unique_ptr<FileLoader> GeoPointSource::createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) {
-	return std::make_unique<mtpFileLoader>(
-		_location,
-		_size,
-		fromCloud,
-		autoLoading,
-		Data::kImageCacheTag);
-}
-
-WebUrlSource::WebUrlSource(const QString &url, QSize box)
-: _url(url)
-, _box(box) {
-}
-
-WebUrlSource::WebUrlSource(const QString &url, int width, int height)
-: _url(url)
-, _width(width)
-, _height(height) {
-}
-
-Storage::Cache::Key WebUrlSource::cacheKey() {
-	return Data::UrlCacheKey(_url);
-}
-
-int WebUrlSource::width() {
-	return _width;
-}
-
-int WebUrlSource::height() {
-	return _height;
-}
-
-int WebUrlSource::bytesSize() {
-	return _size;
-}
-
-void WebUrlSource::setInformation(int size, int width, int height) {
-	if (size) {
-		_size = size;
-	}
-	if (width && height) {
-		_width = width;
-		_height = height;
-	}
-}
-
-QSize WebUrlSource::shrinkBox() const {
-	return _box;
-}
-
-std::unique_ptr<FileLoader> WebUrlSource::createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) {
-	return std::make_unique<webFileLoader>(
-		_url,
-		QString(),
-		fromCloud,
-		autoLoading,
-		Data::kImageCacheTag);
+	return _data.height();
 }
 
 } // namespace Images
diff --git a/Telegram/SourceFiles/ui/image/image_source.h b/Telegram/SourceFiles/ui/image/image_source.h
index 913da40fc..b17ac9465 100644
--- a/Telegram/SourceFiles/ui/image/image_source.h
+++ b/Telegram/SourceFiles/ui/image/image_source.h
@@ -13,244 +13,18 @@ namespace Images {
 
 class ImageSource : public Source {
 public:
-	ImageSource(QImage &&data, const QByteArray &format);
+	explicit ImageSource(const QString &path);
+	explicit ImageSource(const QByteArray &content);
+	explicit ImageSource(QImage &&data);
 
-	void load(Data::FileOrigin origin) override;
-	void loadEvenCancelled(Data::FileOrigin origin) override;
+	void load() override;
 	QImage takeLoaded() override;
-	void unload() override;
-
-	bool loading() override;
-	bool displayLoading() override;
-	void cancel() override;
-	float64 progress() override;
-	int loadOffset() override;
-
-	const StorageImageLocation &location() override;
-	void refreshFileReference(const QByteArray &data) override;
-	Storage::Cache::Key cacheKey() override;
-	void setDelayedStorageLocation(
-		const StorageImageLocation &location) override;
-	void performDelayedLoad(Data::FileOrigin origin) override;
-	void setImageBytes(const QByteArray &bytes) override;
 
 	int width() override;
 	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-	QByteArray bytesForCache() override;
 
 private:
 	QImage _data;
-	QByteArray _format;
-	QByteArray _bytes;
-	int _width = 0;
-	int _height = 0;
-
-};
-
-class LocalFileSource : public Source {
-public:
-	explicit LocalFileSource(
-		const QString &path,
-		const QByteArray &content = QByteArray(),
-		const QByteArray &format = QByteArray(),
-		QImage &&data = QImage());
-
-	void load(Data::FileOrigin origin) override;
-	void loadEvenCancelled(Data::FileOrigin origin) override;
-	QImage takeLoaded() override;
-	void unload() override;
-
-	bool loading() override;
-	bool displayLoading() override;
-	void cancel() override;
-	float64 progress() override;
-	int loadOffset() override;
-
-	const StorageImageLocation &location() override;
-	void refreshFileReference(const QByteArray &data) override;
-	Storage::Cache::Key cacheKey() override;
-	void setDelayedStorageLocation(
-		const StorageImageLocation &location) override;
-	void performDelayedLoad(Data::FileOrigin origin) override;
-	void setImageBytes(const QByteArray &bytes) override;
-
-	int width() override;
-	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-	QByteArray bytesForCache() override;
-
-private:
-	void ensureDimensionsKnown();
-
-	QString _path;
-	QByteArray _bytes;
-	QByteArray _format;
-	QImage _data;
-	int _width = 0;
-	int _height = 0;
-
-};
-
-class RemoteSource : public Source {
-public:
-	void load(Data::FileOrigin origin) override;
-	void loadEvenCancelled(Data::FileOrigin origin) override;
-	QImage takeLoaded() override;
-	void unload() override;
-
-	bool loading() override;
-	bool displayLoading() override;
-	void cancel() override;
-	float64 progress() override;
-	int loadOffset() override;
-
-	const StorageImageLocation &location() override;
-	void refreshFileReference(const QByteArray &data) override;
-	void setDelayedStorageLocation(
-		const StorageImageLocation &location) override;
-	void performDelayedLoad(Data::FileOrigin origin) override;
-	void setImageBytes(const QByteArray &bytes) override;
-
-	QByteArray bytesForCache() override;
-
-	~RemoteSource();
-
-protected:
-	// If after loading the image we need to shrink it to fit into a
-	// specific size, you can return this size here.
-	virtual QSize shrinkBox() const = 0;
-	virtual std::unique_ptr<FileLoader> createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) = 0;
-
-	void loadLocal();
-	FileLoader *currentLoader() const {
-		return _loader.get();
-	}
-
-private:
-	bool cancelled() const;
-	void destroyLoader();
-
-	std::unique_ptr<FileLoader> _loader;
-	bool _cancelled = false;
-
-};
-
-class StorageSource : public RemoteSource {
-public:
-	StorageSource(
-		const StorageImageLocation &location,
-		int size);
-
-	const StorageImageLocation &location() override;
-	Storage::Cache::Key cacheKey() override;
-
-	void refreshFileReference(const QByteArray &data) override;
-
-	int width() override;
-	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-protected:
-	QSize shrinkBox() const override;
-	std::unique_ptr<FileLoader> createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) override;
-
-	StorageImageLocation _location;
-	int _size = 0;
-
-};
-
-class WebCachedSource : public RemoteSource {
-public:
-	WebCachedSource(const WebFileLocation &location, QSize box, int size = 0);
-	WebCachedSource(
-		const WebFileLocation &location,
-		int width,
-		int height,
-		int size = 0);
-
-	Storage::Cache::Key cacheKey() override;
-
-	int width() override;
-	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-protected:
-	QSize shrinkBox() const override;
-	std::unique_ptr<FileLoader> createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) override;
-
-	WebFileLocation _location;
-	QSize _box;
-	int _width = 0;
-	int _height = 0;
-	int _size = 0;
-
-};
-
-class GeoPointSource : public RemoteSource {
-public:
-	GeoPointSource(const GeoPointLocation &location);
-
-	Storage::Cache::Key cacheKey() override;
-
-	int width() override;
-	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-protected:
-	QSize shrinkBox() const override;
-	std::unique_ptr<FileLoader> createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) override;
-
-	GeoPointLocation _location;
-	int _size = 0;
-
-};
-
-class WebUrlSource : public RemoteSource {
-public:
-	// If !box.isEmpty() then resize the image to fit in this box.
-	explicit WebUrlSource(const QString &url, QSize box = QSize());
-	WebUrlSource(const QString &url, int width, int height);
-
-	Storage::Cache::Key cacheKey() override;
-
-	int width() override;
-	int height() override;
-	int bytesSize() override;
-	void setInformation(int size, int width, int height) override;
-
-protected:
-	QSize shrinkBox() const override;
-	std::unique_ptr<FileLoader> createLoader(
-		Data::FileOrigin origin,
-		LoadFromCloudSetting fromCloud,
-		bool autoLoading) override;
-
-private:
-	QString _url;
-	QSize _box;
-	int _size = 0;
-	int _width = 0;
-	int _height = 0;
 
 };