Support different location types for thumbnails.
This commit is contained in:
		
							parent
							
								
									37aabc0da9
								
							
						
					
					
						commit
						3797753d16
					
				
					 19 changed files with 491 additions and 148 deletions
				
			
		|  | @ -924,6 +924,8 @@ PRIVATE | ||||||
|     ui/image/image.h |     ui/image/image.h | ||||||
|     ui/image/image_location.cpp |     ui/image/image_location.cpp | ||||||
|     ui/image/image_location.h |     ui/image/image_location.h | ||||||
|  |     ui/image/image_location_factory.cpp | ||||||
|  |     ui/image/image_location_factory.h | ||||||
|     ui/image/image_source.cpp |     ui/image/image_source.cpp | ||||||
|     ui/image/image_source.h |     ui/image/image_source.h | ||||||
|     ui/widgets/continuous_sliders.cpp |     ui/widgets/continuous_sliders.cpp | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "main/main_session.h" | #include "main/main_session.h" | ||||||
| #include "data/data_session.h" | #include "data/data_session.h" | ||||||
| #include "data/data_document.h" | #include "data/data_document.h" | ||||||
|  | #include "ui/image/image_location_factory.h" | ||||||
| #include "storage/localimageloader.h" | #include "storage/localimageloader.h" | ||||||
| #include "base/unixtime.h" | #include "base/unixtime.h" | ||||||
| #include "apiwrap.h" | #include "apiwrap.h" | ||||||
|  | @ -112,7 +113,7 @@ void DicePack::tryGenerateLocalZero() { | ||||||
| 	Assert(result != nullptr); | 	Assert(result != nullptr); | ||||||
| 	const auto document = _session->data().processDocument( | 	const auto document = _session->data().processDocument( | ||||||
| 		result->document, | 		result->document, | ||||||
| 		std::move(result->thumb)); | 		Images::FromImageInMemory(result->thumb, "PNG")); | ||||||
| 	document->setLocation(FileLocation(path)); | 	document->setLocation(FileLocation(path)); | ||||||
| 
 | 
 | ||||||
| 	_map.emplace(0, document); | 	_map.emplace(0, document); | ||||||
|  |  | ||||||
|  | @ -606,16 +606,17 @@ bool DocumentData::checkWallPaperProperties() { | ||||||
| 
 | 
 | ||||||
| void DocumentData::updateThumbnails( | void DocumentData::updateThumbnails( | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnail) { | 		const ImageWithLocation &thumbnail) { | ||||||
| 	if (!inlineThumbnailBytes.isEmpty() | 	if (!inlineThumbnailBytes.isEmpty() | ||||||
| 		&& _inlineThumbnailBytes.isEmpty()) { | 		&& _inlineThumbnailBytes.isEmpty()) { | ||||||
| 		_inlineThumbnailBytes = inlineThumbnailBytes; | 		_inlineThumbnailBytes = inlineThumbnailBytes; | ||||||
| 	} | 	} | ||||||
| 	if (thumbnail.valid() | 	if (thumbnail.location.valid() | ||||||
| 		&& (!_thumbnailLocation.valid() | 		&& (!_thumbnailLocation.valid() | ||||||
| 			|| _thumbnailLocation.width() < thumbnail.width() | 			|| _thumbnailLocation.width() < thumbnail.location.width() | ||||||
| 			|| _thumbnailLocation.height() < thumbnail.height())) { | 			|| _thumbnailLocation.height() < thumbnail.location.height())) { | ||||||
| 		_thumbnailLocation = thumbnail; | 		_thumbnailLocation = thumbnail.location; | ||||||
|  | 		_thumbnailByteSize = thumbnail.bytesCount; | ||||||
| 		if (_thumbnailLoader) { | 		if (_thumbnailLoader) { | ||||||
| 			const auto origin = base::take(_thumbnailLoader)->fileOrigin(); | 			const auto origin = base::take(_thumbnailLoader)->fileOrigin(); | ||||||
| 			loadThumbnail(origin); | 			loadThumbnail(origin); | ||||||
|  | @ -624,7 +625,7 @@ void DocumentData::updateThumbnails( | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const StorageImageLocation &DocumentData::thumbnailLocation() const { | const ImageLocation &DocumentData::thumbnailLocation() const { | ||||||
| 	return _thumbnailLocation; | 	return _thumbnailLocation; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -659,16 +660,17 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	const auto autoLoading = false; | 	const auto autoLoading = false; | ||||||
| 	_thumbnailLoader = std::make_unique<mtpFileLoader>( | 	_thumbnailLoader = CreateFileLoader( | ||||||
| 		_thumbnailLocation.file(), | 		_thumbnailLocation.file(), | ||||||
| 		origin, | 		origin, | ||||||
| 		UnknownFileLocation, |  | ||||||
| 		QString(), | 		QString(), | ||||||
| 		_thumbnailSize, | 		_thumbnailByteSize, | ||||||
|  | 		UnknownFileLocation, | ||||||
| 		LoadToCacheAsWell, | 		LoadToCacheAsWell, | ||||||
| 		LoadFromCloudOrLocal, | 		LoadFromCloudOrLocal, | ||||||
| 		autoLoading, | 		autoLoading, | ||||||
| 		Data::kImageCacheTag); | 		Data::kImageCacheTag); | ||||||
|  | 
 | ||||||
| 	_thumbnailLoader->updates( | 	_thumbnailLoader->updates( | ||||||
| 	) | rpl::start_with_error_done([=](bool started) { | 	) | rpl::start_with_error_done([=](bool started) { | ||||||
| 		_thumbnailLoader = nullptr; | 		_thumbnailLoader = nullptr; | ||||||
|  | @ -683,6 +685,7 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) { | ||||||
| 		} | 		} | ||||||
| 		_thumbnailLoader = nullptr; | 		_thumbnailLoader = nullptr; | ||||||
| 	}) | rpl::release(); | 	}) | rpl::release(); | ||||||
|  | 
 | ||||||
| 	_thumbnailLoader->start(); | 	_thumbnailLoader->start(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -161,8 +161,8 @@ public: | ||||||
| 	void loadThumbnail(Data::FileOrigin origin); | 	void loadThumbnail(Data::FileOrigin origin); | ||||||
| 	void updateThumbnails( | 	void updateThumbnails( | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnail); | 		const ImageWithLocation &thumbnail); | ||||||
| 	const StorageImageLocation &thumbnailLocation() const; | 	const ImageLocation &thumbnailLocation() const; | ||||||
| 
 | 
 | ||||||
| 	[[nodiscard]] QByteArray inlineThumbnailBytes() const { | 	[[nodiscard]] QByteArray inlineThumbnailBytes() const { | ||||||
| 		return _inlineThumbnailBytes; | 		return _inlineThumbnailBytes; | ||||||
|  | @ -301,9 +301,9 @@ private: | ||||||
| 	WebFileLocation _urlLocation; | 	WebFileLocation _urlLocation; | ||||||
| 
 | 
 | ||||||
| 	QByteArray _inlineThumbnailBytes; | 	QByteArray _inlineThumbnailBytes; | ||||||
| 	StorageImageLocation _thumbnailLocation; | 	ImageLocation _thumbnailLocation; | ||||||
| 	std::unique_ptr<FileLoader> _thumbnailLoader; | 	std::unique_ptr<FileLoader> _thumbnailLoader; | ||||||
| 	int _thumbnailSize = 0; | 	int _thumbnailByteSize = 0; | ||||||
| 	std::unique_ptr<Data::ReplyPreview> _replyPreview; | 	std::unique_ptr<Data::ReplyPreview> _replyPreview; | ||||||
| 	std::weak_ptr<Data::DocumentMedia> _media; | 	std::weak_ptr<Data::DocumentMedia> _media; | ||||||
| 	PhotoData *_goodThumbnailPhoto = nullptr; | 	PhotoData *_goodThumbnailPhoto = nullptr; | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "core/crash_reports.h" // CrashReports::SetAnnotation
 | #include "core/crash_reports.h" // CrashReports::SetAnnotation
 | ||||||
| #include "ui/image/image.h" | #include "ui/image/image.h" | ||||||
| #include "ui/image/image_source.h" // Images::LocalFileSource
 | #include "ui/image/image_source.h" // Images::LocalFileSource
 | ||||||
|  | #include "ui/image/image_location_factory.h" // Images::FromPhotoSize
 | ||||||
| #include "export/export_controller.h" | #include "export/export_controller.h" | ||||||
| #include "export/view/export_view_panel_controller.h" | #include "export/view/export_view_panel_controller.h" | ||||||
| #include "window/notifications_manager.h" | #include "window/notifications_manager.h" | ||||||
|  | @ -2355,14 +2356,11 @@ not_null<DocumentData*> Session::document(DocumentId id) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| not_null<DocumentData*> Session::processDocument(const MTPDocument &data) { | not_null<DocumentData*> Session::processDocument(const MTPDocument &data) { | ||||||
| 	switch (data.type()) { | 	return data.match([&](const MTPDdocument &data) { | ||||||
| 	case mtpc_document: | 		return processDocument(data); | ||||||
| 		return processDocument(data.c_document()); | 	}, [&](const MTPDdocumentEmpty &data) { | ||||||
| 
 | 		return document(data.vid().v); | ||||||
| 	case mtpc_documentEmpty: | 	}); | ||||||
| 		return document(data.c_documentEmpty().vid().v); |  | ||||||
| 	} |  | ||||||
| 	Unexpected("Type in Session::document()."); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| not_null<DocumentData*> Session::processDocument(const MTPDdocument &data) { | not_null<DocumentData*> Session::processDocument(const MTPDdocument &data) { | ||||||
|  | @ -2373,33 +2371,22 @@ not_null<DocumentData*> Session::processDocument(const MTPDdocument &data) { | ||||||
| 
 | 
 | ||||||
| not_null<DocumentData*> Session::processDocument( | not_null<DocumentData*> Session::processDocument( | ||||||
| 		const MTPdocument &data, | 		const MTPdocument &data, | ||||||
| 		QImage &&thumb) { | 		const ImageWithLocation &thumbnail) { | ||||||
| 	switch (data.type()) { | 	return data.match([&](const MTPDdocument &data) { | ||||||
| 	case mtpc_documentEmpty: |  | ||||||
| 		return document(data.c_documentEmpty().vid().v); |  | ||||||
| 
 |  | ||||||
| 	case mtpc_document: { |  | ||||||
| 		const auto &fields = data.c_document(); |  | ||||||
| 		const auto mime = qs(fields.vmime_type()); |  | ||||||
| 		// #TODO optimize
 |  | ||||||
| 		const auto format = Core::IsMimeSticker(mime) |  | ||||||
| 			? "WEBP" |  | ||||||
| 			: "JPG"; |  | ||||||
| 		Images::Create(std::move(thumb), format); |  | ||||||
| 		return document( | 		return document( | ||||||
| 			fields.vid().v, | 			data.vid().v, | ||||||
| 			fields.vaccess_hash().v, | 			data.vaccess_hash().v, | ||||||
| 			fields.vfile_reference().v, | 			data.vfile_reference().v, | ||||||
| 			fields.vdate().v, | 			data.vdate().v, | ||||||
| 			fields.vattributes().v, | 			data.vattributes().v, | ||||||
| 			mime, | 			qs(data.vmime_type()), | ||||||
| 			QByteArray(), | 			QByteArray(), | ||||||
| 			StorageImageLocation(), | 			thumbnail, | ||||||
| 			fields.vdc_id().v, | 			data.vdc_id().v, | ||||||
| 			fields.vsize().v); | 			data.vsize().v); | ||||||
| 	} break; | 	}, [&](const MTPDdocumentEmpty &data) { | ||||||
| 	} | 		return document(data.vid().v); | ||||||
| 	Unexpected("Type in Session::document() with thumb."); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| not_null<DocumentData*> Session::document( | not_null<DocumentData*> Session::document( | ||||||
|  | @ -2410,7 +2397,7 @@ not_null<DocumentData*> Session::document( | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes, | 		const QVector<MTPDocumentAttribute> &attributes, | ||||||
| 		const QString &mime, | 		const QString &mime, | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnailLocation, | 		const ImageWithLocation &thumbnail, | ||||||
| 		int32 dc, | 		int32 dc, | ||||||
| 		int32 size) { | 		int32 size) { | ||||||
| 	const auto result = document(id); | 	const auto result = document(id); | ||||||
|  | @ -2422,7 +2409,7 @@ not_null<DocumentData*> Session::document( | ||||||
| 		attributes, | 		attributes, | ||||||
| 		mime, | 		mime, | ||||||
| 		inlineThumbnailBytes, | 		inlineThumbnailBytes, | ||||||
| 		thumbnailLocation, | 		thumbnail, | ||||||
| 		dc, | 		dc, | ||||||
| 		size); | 		size); | ||||||
| 	return result; | 	return result; | ||||||
|  | @ -2473,22 +2460,15 @@ void Session::documentConvert( | ||||||
| 
 | 
 | ||||||
| DocumentData *Session::documentFromWeb( | DocumentData *Session::documentFromWeb( | ||||||
| 		const MTPWebDocument &data, | 		const MTPWebDocument &data, | ||||||
| 		ImagePtr thumb) { | 		const ImageLocation &thumbnailLocation) { | ||||||
| 	switch (data.type()) { | 	return data.match([&](const auto &data) { | ||||||
| 	case mtpc_webDocument: | 		return documentFromWeb(data, thumbnailLocation); | ||||||
| 		return documentFromWeb(data.c_webDocument(), thumb); | 	}); | ||||||
| 
 |  | ||||||
| 	case mtpc_webDocumentNoProxy: |  | ||||||
| 		return documentFromWeb(data.c_webDocumentNoProxy(), thumb); |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	Unexpected("Type in Session::documentFromWeb."); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DocumentData *Session::documentFromWeb( | DocumentData *Session::documentFromWeb( | ||||||
| 		const MTPDwebDocument &data, | 		const MTPDwebDocument &data, | ||||||
| 		ImagePtr thumb) { | 		const ImageLocation &thumbnailLocation) { | ||||||
| 	// #TODO optimize thumb
 |  | ||||||
| 	const auto result = document( | 	const auto result = document( | ||||||
| 		rand_value<DocumentId>(), | 		rand_value<DocumentId>(), | ||||||
| 		uint64(0), | 		uint64(0), | ||||||
|  | @ -2497,7 +2477,7 @@ DocumentData *Session::documentFromWeb( | ||||||
| 		data.vattributes().v, | 		data.vattributes().v, | ||||||
| 		data.vmime_type().v, | 		data.vmime_type().v, | ||||||
| 		QByteArray(), | 		QByteArray(), | ||||||
| 		StorageImageLocation(), | 		ImageWithLocation{ .location = thumbnailLocation }, | ||||||
| 		MTP::maindc(), | 		MTP::maindc(), | ||||||
| 		int32(0)); // data.vsize().v
 | 		int32(0)); // data.vsize().v
 | ||||||
| 	result->setWebLocation(WebFileLocation( | 	result->setWebLocation(WebFileLocation( | ||||||
|  | @ -2508,8 +2488,7 @@ DocumentData *Session::documentFromWeb( | ||||||
| 
 | 
 | ||||||
| DocumentData *Session::documentFromWeb( | DocumentData *Session::documentFromWeb( | ||||||
| 		const MTPDwebDocumentNoProxy &data, | 		const MTPDwebDocumentNoProxy &data, | ||||||
| 		ImagePtr thumb) { | 		const ImageLocation &thumbnailLocation) { | ||||||
| 	// #TODO optimize thumb
 |  | ||||||
| 	const auto result = document( | 	const auto result = document( | ||||||
| 		rand_value<DocumentId>(), | 		rand_value<DocumentId>(), | ||||||
| 		uint64(0), | 		uint64(0), | ||||||
|  | @ -2518,7 +2497,7 @@ DocumentData *Session::documentFromWeb( | ||||||
| 		data.vattributes().v, | 		data.vattributes().v, | ||||||
| 		data.vmime_type().v, | 		data.vmime_type().v, | ||||||
| 		QByteArray(), | 		QByteArray(), | ||||||
| 		StorageImageLocation(), | 		ImageWithLocation{ .location = thumbnailLocation }, | ||||||
| 		MTP::maindc(), | 		MTP::maindc(), | ||||||
| 		int32(0)); // data.vsize().v
 | 		int32(0)); // data.vsize().v
 | ||||||
| 	result->setContentUrl(qs(data.vurl())); | 	result->setContentUrl(qs(data.vurl())); | ||||||
|  | @ -2538,8 +2517,10 @@ void Session::documentApplyFields( | ||||||
| 		const MTPDdocument &data) { | 		const MTPDdocument &data) { | ||||||
| 	const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data); | 	const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data); | ||||||
| 	const auto thumbnailSize = FindDocumentThumbnail(data); | 	const auto thumbnailSize = FindDocumentThumbnail(data); | ||||||
| 	// #TODO optimize
 | 	const auto prepared = Images::FromPhotoSize( | ||||||
| 	const auto thumbnail = Images::Create(data, thumbnailSize)->location(); | 		_session, | ||||||
|  | 		data, | ||||||
|  | 		thumbnailSize); | ||||||
| 	documentApplyFields( | 	documentApplyFields( | ||||||
| 		document, | 		document, | ||||||
| 		data.vaccess_hash().v, | 		data.vaccess_hash().v, | ||||||
|  | @ -2548,7 +2529,7 @@ void Session::documentApplyFields( | ||||||
| 		data.vattributes().v, | 		data.vattributes().v, | ||||||
| 		qs(data.vmime_type()), | 		qs(data.vmime_type()), | ||||||
| 		inlineThumbnailBytes, | 		inlineThumbnailBytes, | ||||||
| 		thumbnail, | 		prepared, | ||||||
| 		data.vdc_id().v, | 		data.vdc_id().v, | ||||||
| 		data.vsize().v); | 		data.vsize().v); | ||||||
| } | } | ||||||
|  | @ -2561,7 +2542,7 @@ void Session::documentApplyFields( | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes, | 		const QVector<MTPDocumentAttribute> &attributes, | ||||||
| 		const QString &mime, | 		const QString &mime, | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnailLocation, | 		const ImageWithLocation &thumbnail, | ||||||
| 		int32 dc, | 		int32 dc, | ||||||
| 		int32 size) { | 		int32 size) { | ||||||
| 	if (!date) { | 	if (!date) { | ||||||
|  | @ -2569,7 +2550,7 @@ void Session::documentApplyFields( | ||||||
| 	} | 	} | ||||||
| 	document->date = date; | 	document->date = date; | ||||||
| 	document->setMimeString(mime); | 	document->setMimeString(mime); | ||||||
| 	document->updateThumbnails(inlineThumbnailBytes, thumbnailLocation); | 	document->updateThumbnails(inlineThumbnailBytes, thumbnail); | ||||||
| 	document->size = size; | 	document->size = size; | ||||||
| 	document->setattributes(attributes); | 	document->setattributes(attributes); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -490,7 +490,7 @@ public: | ||||||
| 	not_null<DocumentData*> processDocument(const MTPDdocument &data); | 	not_null<DocumentData*> processDocument(const MTPDdocument &data); | ||||||
| 	not_null<DocumentData*> processDocument( | 	not_null<DocumentData*> processDocument( | ||||||
| 		const MTPdocument &data, | 		const MTPdocument &data, | ||||||
| 		QImage &&thumb); | 		const ImageWithLocation &thumbnail); | ||||||
| 	[[nodiscard]] not_null<DocumentData*> document( | 	[[nodiscard]] not_null<DocumentData*> document( | ||||||
| 		DocumentId id, | 		DocumentId id, | ||||||
| 		const uint64 &access, | 		const uint64 &access, | ||||||
|  | @ -499,7 +499,7 @@ public: | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes, | 		const QVector<MTPDocumentAttribute> &attributes, | ||||||
| 		const QString &mime, | 		const QString &mime, | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnailLocation, | 		const ImageWithLocation &thumbnail, | ||||||
| 		int32 dc, | 		int32 dc, | ||||||
| 		int32 size); | 		int32 size); | ||||||
| 	void documentConvert( | 	void documentConvert( | ||||||
|  | @ -507,7 +507,7 @@ public: | ||||||
| 		const MTPDocument &data); | 		const MTPDocument &data); | ||||||
| 	[[nodiscard]] DocumentData *documentFromWeb( | 	[[nodiscard]] DocumentData *documentFromWeb( | ||||||
| 		const MTPWebDocument &data, | 		const MTPWebDocument &data, | ||||||
| 		ImagePtr thumb); | 		const ImageLocation &thumbnailLocation); | ||||||
| 
 | 
 | ||||||
| 	[[nodiscard]] not_null<WebPageData*> webpage(WebPageId id); | 	[[nodiscard]] not_null<WebPageData*> webpage(WebPageId id); | ||||||
| 	not_null<WebPageData*> processWebpage(const MTPWebPage &data); | 	not_null<WebPageData*> processWebpage(const MTPWebPage &data); | ||||||
|  | @ -753,15 +753,15 @@ private: | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes, | 		const QVector<MTPDocumentAttribute> &attributes, | ||||||
| 		const QString &mime, | 		const QString &mime, | ||||||
| 		const QByteArray &inlineThumbnailBytes, | 		const QByteArray &inlineThumbnailBytes, | ||||||
| 		const StorageImageLocation &thumbnailLocation, | 		const ImageWithLocation &thumbnail, | ||||||
| 		int32 dc, | 		int32 dc, | ||||||
| 		int32 size); | 		int32 size); | ||||||
| 	DocumentData *documentFromWeb( | 	DocumentData *documentFromWeb( | ||||||
| 		const MTPDwebDocument &data, | 		const MTPDwebDocument &data, | ||||||
| 		ImagePtr thumb); | 		const ImageLocation &thumbnailLocation); | ||||||
| 	DocumentData *documentFromWeb( | 	DocumentData *documentFromWeb( | ||||||
| 		const MTPDwebDocumentNoProxy &data, | 		const MTPDwebDocumentNoProxy &data, | ||||||
| 		ImagePtr thumb); | 		const ImageLocation &thumbnailLocation); | ||||||
| 
 | 
 | ||||||
| 	void webpageApplyFields( | 	void webpageApplyFields( | ||||||
| 		not_null<WebPageData*> page, | 		not_null<WebPageData*> page, | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "core/file_utilities.h" | #include "core/file_utilities.h" | ||||||
| #include "core/mime_type.h" | #include "core/mime_type.h" | ||||||
| #include "ui/image/image.h" | #include "ui/image/image.h" | ||||||
|  | #include "ui/image/image_location_factory.h" | ||||||
| #include "mainwidget.h" | #include "mainwidget.h" | ||||||
| #include "main/main_session.h" | #include "main/main_session.h" | ||||||
| 
 | 
 | ||||||
|  | @ -40,7 +41,9 @@ QString GetContentUrl(const MTPWebDocument &document) { | ||||||
| Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creator.type) { | Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creator.type) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) { | std::unique_ptr<Result> Result::create( | ||||||
|  | 		uint64 queryId, | ||||||
|  | 		const MTPBotInlineResult &mtpData) { | ||||||
| 	using StringToTypeMap = QMap<QString, Result::Type>; | 	using StringToTypeMap = QMap<QString, Result::Type>; | ||||||
| 	static StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* { | 	static StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* { | ||||||
| 		auto result = std::make_unique<StringToTypeMap>(); | 		auto result = std::make_unique<StringToTypeMap>(); | ||||||
|  | @ -94,7 +97,9 @@ std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult | ||||||
| 			} else { | 			} else { | ||||||
| 				result->_document = Auth().data().documentFromWeb( | 				result->_document = Auth().data().documentFromWeb( | ||||||
| 					result->adjustAttributes(*content), | 					result->adjustAttributes(*content), | ||||||
| 					result->_thumb); | 					(r.vthumb() | ||||||
|  | 						? Images::FromWebDocument(*r.vthumb()) | ||||||
|  | 						: ImageLocation())); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		message = &r.vsend_message(); | 		message = &r.vsend_message(); | ||||||
|  |  | ||||||
|  | @ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "mainwindow.h" | #include "mainwindow.h" | ||||||
| #include "core/application.h" | #include "core/application.h" | ||||||
| #include "storage/localstorage.h" | #include "storage/localstorage.h" | ||||||
|  | #include "storage/file_download_mtproto.h" | ||||||
|  | #include "storage/file_download_web.h" | ||||||
| #include "platform/platform_file_utilities.h" | #include "platform/platform_file_utilities.h" | ||||||
| #include "main/main_session.h" | #include "main/main_session.h" | ||||||
| #include "apiwrap.h" | #include "apiwrap.h" | ||||||
|  | @ -23,6 +25,67 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "facades.h" | #include "facades.h" | ||||||
| #include "app.h" | #include "app.h" | ||||||
| 
 | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | class FromMemoryLoader final : public FileLoader { | ||||||
|  | public: | ||||||
|  | 	FromMemoryLoader( | ||||||
|  | 		const QByteArray &data, | ||||||
|  | 		const QString &toFile, | ||||||
|  | 		int32 size, | ||||||
|  | 		LocationType locationType, | ||||||
|  | 		LoadToCacheSetting toCache, | ||||||
|  | 		LoadFromCloudSetting fromCloud, | ||||||
|  | 		bool autoLoading, | ||||||
|  | 		uint8 cacheTag); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	Storage::Cache::Key cacheKey() const override; | ||||||
|  | 	std::optional<MediaKey> fileLocationKey() const override; | ||||||
|  | 	void cancelHook() override; | ||||||
|  | 	void startLoading() override; | ||||||
|  | 
 | ||||||
|  | 	QByteArray _data; | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | FromMemoryLoader::FromMemoryLoader( | ||||||
|  | 	const QByteArray &data, | ||||||
|  | 	const QString &toFile, | ||||||
|  | 	int32 size, | ||||||
|  | 	LocationType locationType, | ||||||
|  | 	LoadToCacheSetting toCache, | ||||||
|  | 	LoadFromCloudSetting fromCloud, | ||||||
|  | 	bool autoLoading, | ||||||
|  | 	uint8 cacheTag | ||||||
|  | ) : FileLoader( | ||||||
|  | 	toFile, | ||||||
|  | 	size, | ||||||
|  | 	locationType, | ||||||
|  | 	toCache, | ||||||
|  | 	fromCloud, | ||||||
|  | 	autoLoading, | ||||||
|  | 	cacheTag) | ||||||
|  | , _data(data) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Storage::Cache::Key FromMemoryLoader::cacheKey() const { | ||||||
|  | 	return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::optional<MediaKey> FromMemoryLoader::fileLocationKey() const { | ||||||
|  | 	return std::nullopt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FromMemoryLoader::cancelHook() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FromMemoryLoader::startLoading() { | ||||||
|  | 	finishWithBytes(_data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
| FileLoader::FileLoader( | FileLoader::FileLoader( | ||||||
| 	const QString &toFile, | 	const QString &toFile, | ||||||
| 	int32 size, | 	int32 size, | ||||||
|  | @ -220,14 +283,14 @@ bool FileLoader::tryLoadLocal() { | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const auto weak = base::make_weak(this); |  | ||||||
| 	if (_toCache == LoadToCacheAsWell) { | 	if (_toCache == LoadToCacheAsWell) { | ||||||
| 		loadLocal(cacheKey()); | 		const auto key = cacheKey(); | ||||||
| 		notifyAboutProgress(); | 		if (key.low || key.high) { | ||||||
|  | 			loadLocal(key); | ||||||
|  | 			notifyAboutProgress(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	if (!weak) { | 	if (_localStatus != LocalStatus::NotTried) { | ||||||
| 		return false; |  | ||||||
| 	} else if (_localStatus != LocalStatus::NotTried) { |  | ||||||
| 		return _finished; | 		return _finished; | ||||||
| 	} else if (_localLoading) { | 	} else if (_localLoading) { | ||||||
| 		_localStatus = LocalStatus::Loading; | 		_localStatus = LocalStatus::Loading; | ||||||
|  | @ -361,8 +424,10 @@ bool FileLoader::finalizeResult() { | ||||||
| 				Local::writeFileLocation(*key, FileLocation(_filename)); | 				Local::writeFileLocation(*key, FileLocation(_filename)); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		const auto key = cacheKey(); | ||||||
| 		if ((_toCache == LoadToCacheAsWell) | 		if ((_toCache == LoadToCacheAsWell) | ||||||
| 			&& (_data.size() <= Storage::kMaxFileInMemory)) { | 			&& (_data.size() <= Storage::kMaxFileInMemory) | ||||||
|  | 			&& (key.low || key.high)) { | ||||||
| 			_session->data().cache().put( | 			_session->data().cache().put( | ||||||
| 				cacheKey(), | 				cacheKey(), | ||||||
| 				Storage::Cache::Database::TaggedValue( | 				Storage::Cache::Database::TaggedValue( | ||||||
|  | @ -374,3 +439,62 @@ bool FileLoader::finalizeResult() { | ||||||
| 	_updates.fire_done(); | 	_updates.fire_done(); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<FileLoader> CreateFileLoader( | ||||||
|  | 		const DownloadLocation &location, | ||||||
|  | 		Data::FileOrigin origin, | ||||||
|  | 		const QString &toFile, | ||||||
|  | 		int size, | ||||||
|  | 		LocationType locationType, | ||||||
|  | 		LoadToCacheSetting toCache, | ||||||
|  | 		LoadFromCloudSetting fromCloud, | ||||||
|  | 		bool autoLoading, | ||||||
|  | 		uint8 cacheTag) { | ||||||
|  | 	auto result = std::unique_ptr<FileLoader>(); | ||||||
|  | 	location.data.match([&](const StorageFileLocation &data) { | ||||||
|  | 		result = std::make_unique<mtpFileLoader>( | ||||||
|  | 			data, | ||||||
|  | 			origin, | ||||||
|  | 			locationType, | ||||||
|  | 			toFile, | ||||||
|  | 			size, | ||||||
|  | 			toCache, | ||||||
|  | 			fromCloud, | ||||||
|  | 			autoLoading, | ||||||
|  | 			cacheTag); | ||||||
|  | 	}, [&](const WebFileLocation &data) { | ||||||
|  | 		result = std::make_unique<mtpFileLoader>( | ||||||
|  | 			data, | ||||||
|  | 			size, | ||||||
|  | 			fromCloud, | ||||||
|  | 			autoLoading, | ||||||
|  | 			cacheTag); | ||||||
|  | 	}, [&](const GeoPointLocation &data) { | ||||||
|  | 		result = std::make_unique<mtpFileLoader>( | ||||||
|  | 			data, | ||||||
|  | 			size, | ||||||
|  | 			fromCloud, | ||||||
|  | 			autoLoading, | ||||||
|  | 			cacheTag); | ||||||
|  | 	}, [&](const PlainUrlLocation &data) { | ||||||
|  | 		result = std::make_unique<webFileLoader>( | ||||||
|  | 			data.url, | ||||||
|  | 			toFile, | ||||||
|  | 			fromCloud, | ||||||
|  | 			autoLoading, | ||||||
|  | 			cacheTag); | ||||||
|  | 	}, [&](const InMemoryLocation &data) { | ||||||
|  | 		result = std::make_unique<FromMemoryLoader>( | ||||||
|  | 			data.bytes, | ||||||
|  | 			toFile, | ||||||
|  | 			size, | ||||||
|  | 			locationType, | ||||||
|  | 			toCache, | ||||||
|  | 			fromCloud, | ||||||
|  | 			autoLoading, | ||||||
|  | 			cacheTag); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	Ensures(result != nullptr); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -164,3 +164,14 @@ protected: | ||||||
| 	mutable QImage _imageData; | 	mutable QImage _imageData; | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | [[nodiscard]] std::unique_ptr<FileLoader> CreateFileLoader( | ||||||
|  | 	const DownloadLocation &location, | ||||||
|  | 	Data::FileOrigin origin, | ||||||
|  | 	const QString &toFile, | ||||||
|  | 	int size, | ||||||
|  | 	LocationType locationType, | ||||||
|  | 	LoadToCacheSetting toCache, | ||||||
|  | 	LoadFromCloudSetting fromCloud, | ||||||
|  | 	bool autoLoading, | ||||||
|  | 	uint8 cacheTag); | ||||||
|  |  | ||||||
|  | @ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "data/data_document_media.h" | #include "data/data_document_media.h" | ||||||
| #include "data/data_photo.h" | #include "data/data_photo.h" | ||||||
| #include "data/data_session.h" | #include "data/data_session.h" | ||||||
|  | #include "ui/image/image_location_factory.h" | ||||||
|  | #include "core/mime_type.h" | ||||||
| #include "main/main_session.h" | #include "main/main_session.h" | ||||||
| 
 | 
 | ||||||
| namespace Storage { | namespace Storage { | ||||||
|  | @ -44,6 +46,10 @@ constexpr auto kUploadRequestInterval = crl::time(500); | ||||||
| // How much time without upload causes additional session kill.
 | // How much time without upload causes additional session kill.
 | ||||||
| constexpr auto kKillSessionTimeout = 15 * crl::time(000); | constexpr auto kKillSessionTimeout = 15 * crl::time(000); | ||||||
| 
 | 
 | ||||||
|  | [[nodiscard]] const char *ThumbnailFormat(const QString &mime) { | ||||||
|  | 	return Core::IsMimeSticker(mime) ? "WEBP" : "JPG"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
| struct Uploader::File { | struct Uploader::File { | ||||||
|  | @ -160,7 +166,9 @@ void Uploader::uploadMedia( | ||||||
| 			? Auth().data().processDocument(media.document) | 			? Auth().data().processDocument(media.document) | ||||||
| 			: Auth().data().processDocument( | 			: Auth().data().processDocument( | ||||||
| 				media.document, | 				media.document, | ||||||
| 				base::duplicate(media.photoThumbs.front().second)); | 				Images::FromImageInMemory( | ||||||
|  | 					media.photoThumbs.front().second, | ||||||
|  | 					"JPG")); | ||||||
| 		if (!media.data.isEmpty()) { | 		if (!media.data.isEmpty()) { | ||||||
| 			document->setDataAndCache(media.data); | 			document->setDataAndCache(media.data); | ||||||
| 			if (media.type == SendMediaType::ThemeFile) { | 			if (media.type == SendMediaType::ThemeFile) { | ||||||
|  | @ -191,13 +199,18 @@ void Uploader::upload( | ||||||
| 			? Auth().data().processDocument(file->document) | 			? Auth().data().processDocument(file->document) | ||||||
| 			: Auth().data().processDocument( | 			: Auth().data().processDocument( | ||||||
| 				file->document, | 				file->document, | ||||||
| 				std::move(file->thumb)); | 				Images::FromImageInMemory( | ||||||
|  | 					file->thumb, | ||||||
|  | 					ThumbnailFormat(file->filemime))); | ||||||
| 		document->uploadingData = std::make_unique<Data::UploadState>( | 		document->uploadingData = std::make_unique<Data::UploadState>( | ||||||
| 			document->size); | 			document->size); | ||||||
| 		if (!file->goodThumbnail.isNull()) { | 		if (const auto active = document->activeMediaView()) { | ||||||
| 			if (const auto active = document->activeMediaView()) { | 			if (!file->goodThumbnail.isNull()) { | ||||||
| 				active->setGoodThumbnail(std::move(file->goodThumbnail)); | 				active->setGoodThumbnail(std::move(file->goodThumbnail)); | ||||||
| 			} | 			} | ||||||
|  | 			if (!file->thumb.isNull()) { | ||||||
|  | 				active->setThumbnail(file->thumb); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		if (!file->goodThumbnailBytes.isEmpty()) { | 		if (!file->goodThumbnailBytes.isEmpty()) { | ||||||
| 			document->owner().cache().putIfEmpty( | 			document->owner().cache().putIfEmpty( | ||||||
|  | @ -208,13 +221,13 @@ void Uploader::upload( | ||||||
| 		} | 		} | ||||||
| 		if (!file->content.isEmpty()) { | 		if (!file->content.isEmpty()) { | ||||||
| 			document->setDataAndCache(file->content); | 			document->setDataAndCache(file->content); | ||||||
| 			if (file->type == SendMediaType::ThemeFile) { |  | ||||||
| 				document->checkWallPaperProperties(); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		if (!file->filepath.isEmpty()) { | 		if (!file->filepath.isEmpty()) { | ||||||
| 			document->setLocation(FileLocation(file->filepath)); | 			document->setLocation(FileLocation(file->filepath)); | ||||||
| 		} | 		} | ||||||
|  | 		if (file->type == SendMediaType::ThemeFile) { | ||||||
|  | 			document->checkWallPaperProperties(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	queue.emplace(msgId, File(file)); | 	queue.emplace(msgId, File(file)); | ||||||
| 	sendNext(); | 	sendNext(); | ||||||
|  |  | ||||||
|  | @ -3945,7 +3945,7 @@ void importOldRecentStickers() { | ||||||
| 			attributes, | 			attributes, | ||||||
| 			mime, | 			mime, | ||||||
| 			QByteArray(), | 			QByteArray(), | ||||||
| 			StorageImageLocation(), | 			ImageWithLocation(), | ||||||
| 			dc, | 			dc, | ||||||
| 			size); | 			size); | ||||||
| 		if (!doc->sticker()) { | 		if (!doc->sticker()) { | ||||||
|  |  | ||||||
|  | @ -96,6 +96,34 @@ std::optional<StorageImageLocation> readStorageImageLocation( | ||||||
| 		: std::nullopt; | 		: std::nullopt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int imageLocationSize(const ImageLocation &location) { | ||||||
|  | 	// Modern image location tag + (size + content) of the serialization.
 | ||||||
|  | 	return sizeof(qint32) * 2 + location.serializeSize(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void writeImageLocation(QDataStream &stream, const ImageLocation &location) { | ||||||
|  | 	stream << kModernImageLocationTag << location.serialize(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::optional<ImageLocation> readImageLocation( | ||||||
|  | 		int streamAppVersion, | ||||||
|  | 		QDataStream &stream) { | ||||||
|  | 	const auto legacy = readLegacyStorageImageLocationOrTag( | ||||||
|  | 		streamAppVersion, | ||||||
|  | 		stream); | ||||||
|  | 	if (legacy) { | ||||||
|  | 		return ImageLocation( | ||||||
|  | 			DownloadLocation{ legacy->file() }, | ||||||
|  | 			legacy->width(), | ||||||
|  | 			legacy->height()); | ||||||
|  | 	} | ||||||
|  | 	auto serialized = QByteArray(); | ||||||
|  | 	stream >> serialized; | ||||||
|  | 	return (stream.status() == QDataStream::Ok) | ||||||
|  | 		? ImageLocation::FromSerialized(serialized) | ||||||
|  | 		: std::nullopt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| uint32 peerSize(not_null<PeerData*> peer) { | uint32 peerSize(not_null<PeerData*> peer) { | ||||||
| 	uint32 result = sizeof(quint64) | 	uint32 result = sizeof(quint64) | ||||||
| 		+ sizeof(quint64) | 		+ sizeof(quint64) | ||||||
|  |  | ||||||
|  | @ -102,6 +102,15 @@ std::optional<StorageImageLocation> readStorageImageLocation( | ||||||
| 	int streamAppVersion, | 	int streamAppVersion, | ||||||
| 	QDataStream &stream); | 	QDataStream &stream); | ||||||
| 
 | 
 | ||||||
|  | int imageLocationSize(const ImageLocation &location); | ||||||
|  | void writeImageLocation(QDataStream &stream, const ImageLocation &location); | ||||||
|  | 
 | ||||||
|  | // NB! This method can return StorageFileLocation with Type::Generic!
 | ||||||
|  | // The reader should discard it or convert to one of the valid modern types.
 | ||||||
|  | std::optional<ImageLocation> readImageLocation( | ||||||
|  | 	int streamAppVersion, | ||||||
|  | 	QDataStream &stream); | ||||||
|  | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| inline T read(QDataStream &stream) { | inline T read(QDataStream &stream) { | ||||||
| 	auto result = T(); | 	auto result = T(); | ||||||
|  |  | ||||||
|  | @ -46,11 +46,10 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) { | ||||||
| 			stream << qint32(StickerSetTypeEmpty); | 			stream << qint32(StickerSetTypeEmpty); | ||||||
| 		} break; | 		} break; | ||||||
| 		} | 		} | ||||||
| 		writeStorageImageLocation(stream, document->_thumbnailLocation); |  | ||||||
| 	} else { | 	} else { | ||||||
| 		stream << qint32(document->getDuration()); | 		stream << qint32(document->getDuration()); | ||||||
| 		writeStorageImageLocation(stream, document->thumbnailLocation()); |  | ||||||
| 	} | 	} | ||||||
|  | 	writeImageLocation(stream, document->thumbnailLocation()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &stream, const StickerSetInfo *info) { | DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &stream, const StickerSetInfo *info) { | ||||||
|  | @ -77,14 +76,11 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	qint32 duration = -1; | 	qint32 duration = -1; | ||||||
| 	std::optional<StorageImageLocation> thumb; | 	std::optional<ImageLocation> thumb; | ||||||
| 	if (type == StickerDocument) { | 	if (type == StickerDocument) { | ||||||
| 		QString alt; | 		QString alt; | ||||||
| 		qint32 typeOfSet; | 		qint32 typeOfSet; | ||||||
| 		stream >> alt >> typeOfSet; | 		stream >> alt >> typeOfSet; | ||||||
| 
 |  | ||||||
| 		thumb = readStorageImageLocation(streamAppVersion, stream); |  | ||||||
| 
 |  | ||||||
| 		if (typeOfSet == StickerSetTypeEmpty) { | 		if (typeOfSet == StickerSetTypeEmpty) { | ||||||
| 			attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords())); | 			attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords())); | ||||||
| 		} else if (info) { | 		} else if (info) { | ||||||
|  | @ -113,8 +109,8 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & | ||||||
| 		if (type == AnimatedDocument) { | 		if (type == AnimatedDocument) { | ||||||
| 			attributes.push_back(MTP_documentAttributeAnimated()); | 			attributes.push_back(MTP_documentAttributeAnimated()); | ||||||
| 		} | 		} | ||||||
| 		thumb = readStorageImageLocation(streamAppVersion, stream); |  | ||||||
| 	} | 	} | ||||||
|  | 	thumb = readImageLocation(streamAppVersion, stream); | ||||||
| 	if (width > 0 && height > 0) { | 	if (width > 0 && height > 0) { | ||||||
| 		if (duration >= 0) { | 		if (duration >= 0) { | ||||||
| 			auto flags = MTPDdocumentAttributeVideo::Flags(0); | 			auto flags = MTPDdocumentAttributeVideo::Flags(0); | ||||||
|  | @ -127,9 +123,12 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	const auto storage = base::get_if<StorageFileLocation>( | ||||||
|  | 		&thumb->file().data); | ||||||
| 	if ((!dc && !access) | 	if ((!dc && !access) | ||||||
| 		|| !thumb | 		|| !thumb | ||||||
| 		|| (thumb->valid() && !thumb->file().isDocumentThumbnail())) { | 		|| (thumb->valid() | ||||||
|  | 			&& (!storage || !storage->isDocumentThumbnail()))) { | ||||||
| 		stream.setStatus(QDataStream::ReadCorruptData); | 		stream.setStatus(QDataStream::ReadCorruptData); | ||||||
| 		// We can't convert legacy thumbnail location to modern, because
 | 		// We can't convert legacy thumbnail location to modern, because
 | ||||||
| 		// size letter ('s' or 'm') is lost, it was not saved in legacy.
 | 		// size letter ('s' or 'm') is lost, it was not saved in legacy.
 | ||||||
|  | @ -143,7 +142,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & | ||||||
| 		attributes, | 		attributes, | ||||||
| 		mime, | 		mime, | ||||||
| 		QByteArray(), | 		QByteArray(), | ||||||
| 		*thumb, | 		ImageWithLocation{ .location = *thumb }, | ||||||
| 		dc, | 		dc, | ||||||
| 		size); | 		size); | ||||||
| } | } | ||||||
|  | @ -176,7 +175,7 @@ int Document::sizeInStream(DocumentData *document) { | ||||||
| 		result += sizeof(qint32); | 		result += sizeof(qint32); | ||||||
| 	} | 	} | ||||||
| 	// + thumb loc
 | 	// + thumb loc
 | ||||||
| 	result += Serialize::storageImageLocationSize(document->thumbnailLocation()); | 	result += Serialize::imageLocationSize(document->thumbnailLocation()); | ||||||
| 
 | 
 | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -61,54 +61,57 @@ uint64 SinglePixKey(Options options) { | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
| QImage FromInlineBytes(const QByteArray &bytes) { | QByteArray ExpandInlineBytes(const QByteArray &bytes) { | ||||||
| 	if (bytes.size() < 3 || bytes[0] != '\x01') { | 	if (bytes.size() < 3 || bytes[0] != '\x01') { | ||||||
| 		return QImage(); | 		return QByteArray(); | ||||||
| 	} | 	} | ||||||
| 	const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49" | 	const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49" | ||||||
| "\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c" | 		"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c" | ||||||
| "\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37" | 		"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37" | ||||||
| "\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3" | 		"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3" | ||||||
| "\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff" | 		"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff" | ||||||
| "\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35" | 		"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35" | ||||||
| "\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | 		"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | ||||||
| "\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | 		"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | ||||||
| "\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | 		"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8" | ||||||
| "\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00" | 		"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00" | ||||||
| "\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01" | 		"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01" | ||||||
| "\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" | 		"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" | ||||||
| "\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05" | 		"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05" | ||||||
| "\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06" | 		"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06" | ||||||
| "\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52" | 		"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52" | ||||||
| "\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28" | 		"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28" | ||||||
| "\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53" | 		"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53" | ||||||
| "\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75" | 		"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75" | ||||||
| "\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96" | 		"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96" | ||||||
| "\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" | 		"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" | ||||||
| "\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6" | 		"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6" | ||||||
| "\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4" | 		"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4" | ||||||
| "\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01" | 		"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01" | ||||||
| "\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" | 		"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" | ||||||
| "\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05" | 		"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05" | ||||||
| "\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41" | 		"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41" | ||||||
| "\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33" | 		"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33" | ||||||
| "\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26" | 		"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26" | ||||||
| "\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a" | 		"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a" | ||||||
| "\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74" | 		"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74" | ||||||
| "\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94" | 		"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94" | ||||||
| "\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4" | 		"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4" | ||||||
| "\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4" | 		"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4" | ||||||
| "\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4" | 		"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4" | ||||||
| "\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00" | 		"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00" | ||||||
| "\x3f\x00"; | 		"\x3f\x00"; | ||||||
| 	const char footer[] = "\xff\xd9"; | 	const char footer[] = "\xff\xd9"; | ||||||
| 	auto real = QByteArray(header, sizeof(header) - 1); | 	auto real = QByteArray(header, sizeof(header) - 1); | ||||||
| 	real[164] = bytes[1]; | 	real[164] = bytes[1]; | ||||||
| 	real[166] = bytes[2]; | 	real[166] = bytes[2]; | ||||||
| 	const auto ready = real | 	return real | ||||||
| 		+ bytes.mid(3) | 		+ bytes.mid(3) | ||||||
| 		+ QByteArray::fromRawData(footer, sizeof(footer) - 1); | 		+ QByteArray::fromRawData(footer, sizeof(footer) - 1); | ||||||
| 	return App::readImage(ready); | } | ||||||
|  | 
 | ||||||
|  | QImage FromInlineBytes(const QByteArray &bytes) { | ||||||
|  | 	return App::readImage(ExpandInlineBytes(bytes)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClearRemote() { | void ClearRemote() { | ||||||
|  | @ -364,7 +367,7 @@ ImagePtr Create(const MTPDdocument &document, const MTPPhotoSize &size) { | ||||||
| 	return CreateFromPhotoSize(create, size); | 	return CreateFromPhotoSize(create, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) { | QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) { | ||||||
| 	for (const auto &attribute : attributes) { | 	for (const auto &attribute : attributes) { | ||||||
| 		if (attribute.type() == mtpc_documentAttributeImageSize) { | 		if (attribute.type() == mtpc_documentAttributeImageSize) { | ||||||
| 			auto &size = attribute.c_documentAttributeImageSize(); | 			auto &size = attribute.c_documentAttributeImageSize(); | ||||||
|  | @ -375,7 +378,7 @@ QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ImagePtr Create(const MTPDwebDocument &document) { | ImagePtr Create(const MTPDwebDocument &document) { | ||||||
| 	const auto size = getImageSize(document.vattributes().v); | 	const auto size = GetSizeForDocument(document.vattributes().v); | ||||||
| 	if (size.isEmpty()) { | 	if (size.isEmpty()) { | ||||||
| 		return ImagePtr(); | 		return ImagePtr(); | ||||||
| 	} | 	} | ||||||
|  | @ -393,7 +396,7 @@ ImagePtr Create(const MTPDwebDocument &document) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ImagePtr Create(const MTPDwebDocumentNoProxy &document) { | ImagePtr Create(const MTPDwebDocumentNoProxy &document) { | ||||||
| 	const auto size = getImageSize(document.vattributes().v); | 	const auto size = GetSizeForDocument(document.vattributes().v); | ||||||
| 	if (size.isEmpty()) { | 	if (size.isEmpty()) { | ||||||
| 		return ImagePtr(); | 		return ImagePtr(); | ||||||
| 	} | 	} | ||||||
|  | @ -402,7 +405,7 @@ ImagePtr Create(const MTPDwebDocumentNoProxy &document) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ImagePtr Create(const MTPDwebDocument &document, QSize box) { | ImagePtr Create(const MTPDwebDocument &document, QSize box) { | ||||||
| 	//const auto size = getImageSize(document.vattributes().v);
 | 	//const auto size = GetSizeForDocument(document.vattributes().v);
 | ||||||
| 	//if (size.isEmpty()) {
 | 	//if (size.isEmpty()) {
 | ||||||
| 	//	return ImagePtr();
 | 	//	return ImagePtr();
 | ||||||
| 	//}
 | 	//}
 | ||||||
|  | @ -419,7 +422,7 @@ ImagePtr Create(const MTPDwebDocument &document, QSize box) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ImagePtr Create(const MTPDwebDocumentNoProxy &document, QSize box) { | ImagePtr Create(const MTPDwebDocumentNoProxy &document, QSize box) { | ||||||
| 	//const auto size = getImageSize(document.vattributes().v);
 | 	//const auto size = GetSizeForDocument(document.vattributes().v);
 | ||||||
| 	//if (size.isEmpty()) {
 | 	//if (size.isEmpty()) {
 | ||||||
| 	//	return ImagePtr();
 | 	//	return ImagePtr();
 | ||||||
| 	//}
 | 	//}
 | ||||||
|  |  | ||||||
|  | @ -13,11 +13,15 @@ class HistoryItem; | ||||||
| 
 | 
 | ||||||
| namespace Images { | namespace Images { | ||||||
| 
 | 
 | ||||||
|  | [[nodiscard]] QByteArray ExpandInlineBytes(const QByteArray &bytes); | ||||||
| [[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes); | [[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes); | ||||||
| 
 | 
 | ||||||
| void ClearRemote(); | void ClearRemote(); | ||||||
| void ClearAll(); | void ClearAll(); | ||||||
| 
 | 
 | ||||||
|  | [[nodiscard]] QSize GetSizeForDocument( | ||||||
|  | 	const QVector<MTPDocumentAttribute> &attributes); | ||||||
|  | 
 | ||||||
| ImagePtr Create(const QString &file, QByteArray format); | ImagePtr Create(const QString &file, QByteArray format); | ||||||
| ImagePtr Create(const QString &url, QSize box); | ImagePtr Create(const QString &url, QSize box); | ||||||
| ImagePtr Create(const QString &url, int width, int height); | ImagePtr Create(const QString &url, int width, int height); | ||||||
|  |  | ||||||
|  | @ -504,6 +504,13 @@ private: | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct ImageWithLocation { | ||||||
|  | 	ImageLocation location; | ||||||
|  | 	int bytesCount = 0; | ||||||
|  | 	QByteArray bytes; | ||||||
|  | 	QImage preloaded; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class Image; | class Image; | ||||||
| class ImagePtr { | class ImagePtr { | ||||||
| public: | public: | ||||||
|  | @ -599,7 +606,9 @@ private: | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| inline bool operator==(const FileLocation &a, const FileLocation &b) { | inline bool operator==(const FileLocation &a, const FileLocation &b) { | ||||||
| 	return (a.name() == b.name()) && (a.modified == b.modified) && (a.size == b.size); | 	return (a.name() == b.name()) | ||||||
|  | 		&& (a.modified == b.modified) | ||||||
|  | 		&& (a.size == b.size); | ||||||
| } | } | ||||||
| inline bool operator!=(const FileLocation &a, const FileLocation &b) { | inline bool operator!=(const FileLocation &a, const FileLocation &b) { | ||||||
| 	return !(a == b); | 	return !(a == b); | ||||||
|  |  | ||||||
							
								
								
									
										124
									
								
								Telegram/SourceFiles/ui/image/image_location_factory.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								Telegram/SourceFiles/ui/image/image_location_factory.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | ||||||
|  | /*
 | ||||||
|  | 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
 | ||||||
|  | */ | ||||||
|  | #include "ui/image/image_location_factory.h" | ||||||
|  | 
 | ||||||
|  | #include "ui/image/image.h" | ||||||
|  | #include "main/main_session.h" | ||||||
|  | 
 | ||||||
|  | #include <QtCore/QBuffer> | ||||||
|  | 
 | ||||||
|  | namespace Images { | ||||||
|  | 
 | ||||||
|  | ImageWithLocation FromPhotoSize( | ||||||
|  | 		not_null<Main::Session*> session, | ||||||
|  | 		const MTPDdocument &document, | ||||||
|  | 		const MTPPhotoSize &size) { | ||||||
|  | 	return size.match([&](const MTPDphotoSize &data) { | ||||||
|  | 		return ImageWithLocation{ | ||||||
|  | 			.location = ImageLocation( | ||||||
|  | 				DownloadLocation{ StorageFileLocation( | ||||||
|  | 					document.vdc_id().v, | ||||||
|  | 					session->userId(), | ||||||
|  | 					MTP_inputDocumentFileLocation( | ||||||
|  | 						document.vid(), | ||||||
|  | 						document.vaccess_hash(), | ||||||
|  | 						document.vfile_reference(), | ||||||
|  | 						data.vtype())) }, | ||||||
|  | 				data.vw().v, | ||||||
|  | 				data.vh().v), | ||||||
|  | 			.bytesCount = data.vsize().v | ||||||
|  | 		}; | ||||||
|  | 	}, [&](const MTPDphotoCachedSize &data) { | ||||||
|  | 		const auto bytes = qba(data.vbytes()); | ||||||
|  | 		return ImageWithLocation{ | ||||||
|  | 			.location = ImageLocation( | ||||||
|  | 				DownloadLocation{ StorageFileLocation( | ||||||
|  | 					document.vdc_id().v, | ||||||
|  | 					session->userId(), | ||||||
|  | 					MTP_inputDocumentFileLocation( | ||||||
|  | 						document.vid(), | ||||||
|  | 						document.vaccess_hash(), | ||||||
|  | 						document.vfile_reference(), | ||||||
|  | 						data.vtype())) }, | ||||||
|  | 				data.vw().v, | ||||||
|  | 				data.vh().v), | ||||||
|  | 			.bytesCount = bytes.size(), | ||||||
|  | 			.bytes = bytes | ||||||
|  | 		}; | ||||||
|  | 	}, [&](const MTPDphotoStrippedSize &data) { | ||||||
|  | 		return ImageWithLocation(); | ||||||
|  | 		//const auto bytes = ExpandInlineBytes(qba(data.vbytes()));
 | ||||||
|  | 		//return ImageWithLocation{
 | ||||||
|  | 		//	.location = ImageLocation(
 | ||||||
|  | 		//		DownloadLocation{ StorageFileLocation(
 | ||||||
|  | 		//			document.vdc_id().v,
 | ||||||
|  | 		//			session->userId(),
 | ||||||
|  | 		//			MTP_inputDocumentFileLocation(
 | ||||||
|  | 		//				document.vid(),
 | ||||||
|  | 		//				document.vaccess_hash(),
 | ||||||
|  | 		//				document.vfile_reference(),
 | ||||||
|  | 		//				data.vtype())) },
 | ||||||
|  | 		//		width, // ???
 | ||||||
|  | 		//		height), // ???
 | ||||||
|  | 		//	.bytesCount = bytes.size(),
 | ||||||
|  | 		//	.bytes = bytes
 | ||||||
|  | 		//};
 | ||||||
|  | 	}, [&](const MTPDphotoSizeEmpty &) { | ||||||
|  | 		return ImageWithLocation(); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ImageWithLocation FromImageInMemory( | ||||||
|  | 		const QImage &image, | ||||||
|  | 		const char *format) { | ||||||
|  | 	if (image.isNull()) { | ||||||
|  | 		return ImageWithLocation(); | ||||||
|  | 	} | ||||||
|  | 	auto bytes = QByteArray(); | ||||||
|  | 	auto buffer = QBuffer(&bytes); | ||||||
|  | 	image.save(&buffer, format); | ||||||
|  | 	return ImageWithLocation{ | ||||||
|  | 		.location = ImageLocation( | ||||||
|  | 			DownloadLocation{ InMemoryLocation{ bytes } }, | ||||||
|  | 			image.width(), | ||||||
|  | 			image.height()), | ||||||
|  | 		.bytesCount = bytes.size(), | ||||||
|  | 		.bytes = bytes, | ||||||
|  | 		.preloaded = image | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ImageLocation FromWebDocument(const MTPWebDocument &document) { | ||||||
|  | 	return document.match([](const MTPDwebDocument &data) { | ||||||
|  | 		const auto size = GetSizeForDocument(data.vattributes().v); | ||||||
|  | 
 | ||||||
|  | 		// We don't use size from WebDocument, because it is not reliable.
 | ||||||
|  | 		// It can be > 0 and different from the real size
 | ||||||
|  | 		// that we get in upload.WebFile result.
 | ||||||
|  | 		//auto filesize = 0; // data.vsize().v;
 | ||||||
|  | 		return ImageLocation( | ||||||
|  | 			DownloadLocation{ WebFileLocation( | ||||||
|  | 				data.vurl().v, | ||||||
|  | 				data.vaccess_hash().v) }, | ||||||
|  | 			size.width(), | ||||||
|  | 			size.height()); | ||||||
|  | 	}, [](const MTPDwebDocumentNoProxy &data) { | ||||||
|  | 		const auto size = GetSizeForDocument(data.vattributes().v); | ||||||
|  | 
 | ||||||
|  | 		// We don't use size from WebDocument, because it is not reliable.
 | ||||||
|  | 		// It can be > 0 and different from the real size
 | ||||||
|  | 		// that we get in upload.WebFile result.
 | ||||||
|  | 		//auto filesize = 0; // data.vsize().v;
 | ||||||
|  | 		return ImageLocation( | ||||||
|  | 			DownloadLocation{ PlainUrlLocation{ qs(data.vurl()) } }, | ||||||
|  | 			size.width(), | ||||||
|  | 			size.height()); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Images
 | ||||||
							
								
								
									
										27
									
								
								Telegram/SourceFiles/ui/image/image_location_factory.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Telegram/SourceFiles/ui/image/image_location_factory.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | /*
 | ||||||
|  | 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 "ui/image/image_location.h" | ||||||
|  | 
 | ||||||
|  | namespace Main { | ||||||
|  | class Session; | ||||||
|  | } // namespace Main
 | ||||||
|  | 
 | ||||||
|  | namespace Images { | ||||||
|  | 
 | ||||||
|  | [[nodiscard]] ImageWithLocation FromPhotoSize( | ||||||
|  | 	not_null<Main::Session*> session, | ||||||
|  | 	const MTPDdocument &document, | ||||||
|  | 	const MTPPhotoSize &size); | ||||||
|  | [[nodiscard]] ImageWithLocation FromImageInMemory( | ||||||
|  | 	const QImage &image, | ||||||
|  | 	const char *format); | ||||||
|  | [[nodiscard]] ImageLocation FromWebDocument(const MTPWebDocument &document); | ||||||
|  | 
 | ||||||
|  | } // namespace Images
 | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston