378 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			378 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
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 {
 | 
						|
namespace {
 | 
						|
 | 
						|
QSize GetSizeForDocument(const QVector<MTPDocumentAttribute> &attributes) {
 | 
						|
	for (const auto &attribute : attributes) {
 | 
						|
		if (attribute.type() == mtpc_documentAttributeImageSize) {
 | 
						|
			auto &size = attribute.c_documentAttributeImageSize();
 | 
						|
			return QSize(size.vw().v, size.vh().v);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return QSize();
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
ImageWithLocation FromPhotoSize(
 | 
						|
		not_null<Main::Session*> session,
 | 
						|
		const MTPDphoto &photo,
 | 
						|
		const MTPPhotoSize &size) {
 | 
						|
	if (!photo.vaccess_hash().v && photo.vfile_reference().v.isEmpty()) {
 | 
						|
		// Locally created fake photo.
 | 
						|
		return ImageWithLocation();
 | 
						|
	}
 | 
						|
	return size.match([&](const MTPDphotoSize &data) {
 | 
						|
		return ImageWithLocation{
 | 
						|
			.location = ImageLocation(
 | 
						|
				DownloadLocation{ StorageFileLocation(
 | 
						|
					photo.vdc_id().v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputPhotoFileLocation(
 | 
						|
						photo.vid(),
 | 
						|
						photo.vaccess_hash(),
 | 
						|
						photo.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(
 | 
						|
					photo.vdc_id().v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputPhotoFileLocation(
 | 
						|
						photo.vid(),
 | 
						|
						photo.vaccess_hash(),
 | 
						|
						photo.vfile_reference(),
 | 
						|
						data.vtype())) },
 | 
						|
				data.vw().v,
 | 
						|
				data.vh().v),
 | 
						|
			.bytes = bytes,
 | 
						|
			.bytesCount = int(bytes.size()),
 | 
						|
		};
 | 
						|
	}, [&](const MTPDphotoSizeProgressive &data) {
 | 
						|
		// #TODO layer118
 | 
						|
		if (data.vsizes().v.isEmpty()) {
 | 
						|
			return ImageWithLocation();
 | 
						|
		}
 | 
						|
		return ImageWithLocation{
 | 
						|
			.location = ImageLocation(
 | 
						|
				DownloadLocation{ StorageFileLocation(
 | 
						|
					photo.vdc_id().v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputPhotoFileLocation(
 | 
						|
						photo.vid(),
 | 
						|
						photo.vaccess_hash(),
 | 
						|
						photo.vfile_reference(),
 | 
						|
						data.vtype())) },
 | 
						|
				data.vw().v,
 | 
						|
				data.vh().v),
 | 
						|
			.bytesCount = data.vsizes().v.back().v
 | 
						|
		};
 | 
						|
	}, [&](const MTPDphotoStrippedSize &data) {
 | 
						|
		return ImageWithLocation();
 | 
						|
		//const auto bytes = ExpandInlineBytes(qba(data.vbytes()));
 | 
						|
		//return ImageWithLocation{
 | 
						|
		//	.location = ImageLocation(
 | 
						|
		//		DownloadLocation{ StorageFileLocation(
 | 
						|
		//			photo.vdc_id().v,
 | 
						|
		//			session->userId(),
 | 
						|
		//			MTP_inputPhotoFileLocation(
 | 
						|
		//				photo.vid(),
 | 
						|
		//				photo.vaccess_hash(),
 | 
						|
		//				photo.vfile_reference(),
 | 
						|
		//				data.vtype())) },
 | 
						|
		//		width, // ???
 | 
						|
		//		height), // ???
 | 
						|
		//	.bytes = bytes,
 | 
						|
		//	.bytesCount = bytes.size(),
 | 
						|
		//};
 | 
						|
	}, [&](const MTPDphotoPathSize &) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}, [&](const MTPDphotoSizeEmpty &) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
ImageWithLocation FromProgressiveSize(
 | 
						|
		not_null<Main::Session*> session,
 | 
						|
		const MTPPhotoSize &size,
 | 
						|
		int index) {
 | 
						|
	Expects(size.type() == mtpc_photoSizeProgressive);
 | 
						|
 | 
						|
	const auto &data = size.c_photoSizeProgressive();
 | 
						|
	if (data.vsizes().v.size() <= index) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}
 | 
						|
	return ImageWithLocation{
 | 
						|
		.progressivePartSize = data.vsizes().v[index].v,
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
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),
 | 
						|
			.bytes = bytes,
 | 
						|
			.bytesCount = int(bytes.size()),
 | 
						|
		};
 | 
						|
	}, [&](const MTPDphotoSizeProgressive &data) {
 | 
						|
		if (data.vsizes().v.isEmpty()) {
 | 
						|
			return ImageWithLocation();
 | 
						|
		}
 | 
						|
		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.vsizes().v.back().v
 | 
						|
		};
 | 
						|
	}, [&](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), // ???
 | 
						|
		//	.bytes = bytes,
 | 
						|
		//	.bytesCount = bytes.size(),
 | 
						|
		//};
 | 
						|
	}, [&](const MTPDphotoPathSize &data) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}, [&](const MTPDphotoSizeEmpty &) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
ImageWithLocation FromPhotoSize(
 | 
						|
		not_null<Main::Session*> session,
 | 
						|
		const MTPDstickerSet &set,
 | 
						|
		const MTPPhotoSize &size) {
 | 
						|
	if (!set.vthumb_dc_id() || !set.vthumb_version()) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}
 | 
						|
	return size.match([&](const MTPDphotoSize &data) {
 | 
						|
		return ImageWithLocation{
 | 
						|
			.location = ImageLocation(
 | 
						|
				DownloadLocation{ StorageFileLocation(
 | 
						|
					set.vthumb_dc_id()->v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputStickerSetThumb(
 | 
						|
						MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
 | 
						|
						MTP_int(set.vthumb_version()->v))) },
 | 
						|
				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(
 | 
						|
					set.vthumb_dc_id()->v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputStickerSetThumb(
 | 
						|
						MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
 | 
						|
						MTP_int(set.vthumb_version()->v))) },
 | 
						|
				data.vw().v,
 | 
						|
				data.vh().v),
 | 
						|
			.bytes = bytes,
 | 
						|
			.bytesCount = int(bytes.size()),
 | 
						|
		};
 | 
						|
	}, [&](const MTPDphotoSizeProgressive &data) {
 | 
						|
		if (data.vsizes().v.isEmpty()) {
 | 
						|
			return ImageWithLocation();
 | 
						|
		}
 | 
						|
		return ImageWithLocation{
 | 
						|
			.location = ImageLocation(
 | 
						|
				DownloadLocation{ StorageFileLocation(
 | 
						|
					set.vthumb_dc_id()->v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputStickerSetThumb(
 | 
						|
						MTP_inputStickerSetID(set.vid(), set.vaccess_hash()),
 | 
						|
						MTP_int(set.vthumb_version()->v))) },
 | 
						|
				data.vw().v,
 | 
						|
				data.vh().v),
 | 
						|
			.bytesCount = data.vsizes().v.back().v
 | 
						|
		};
 | 
						|
	}, [&](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), // ???
 | 
						|
		//	.bytes = bytes,
 | 
						|
		//	.bytesCount = bytes.size(),
 | 
						|
		//};
 | 
						|
	}, [&](const MTPDphotoPathSize &data) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}, [&](const MTPDphotoSizeEmpty &) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
ImageWithLocation FromImageInMemory(
 | 
						|
		const QImage &image,
 | 
						|
		const char *format,
 | 
						|
		QByteArray bytes) {
 | 
						|
	if (image.isNull()) {
 | 
						|
		return ImageWithLocation();
 | 
						|
	}
 | 
						|
	if (bytes.isEmpty()) {
 | 
						|
		auto buffer = QBuffer(&bytes);
 | 
						|
		image.save(&buffer, format);
 | 
						|
	}
 | 
						|
	return ImageWithLocation{
 | 
						|
		.location = ImageLocation(
 | 
						|
			DownloadLocation{ InMemoryLocation{ bytes } },
 | 
						|
			image.width(),
 | 
						|
			image.height()),
 | 
						|
		.bytes = bytes,
 | 
						|
		.preloaded = image,
 | 
						|
		.bytesCount = int(bytes.size()),
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
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());
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
ImageWithLocation FromVideoSize(
 | 
						|
		not_null<Main::Session*> session,
 | 
						|
		const MTPDdocument &document,
 | 
						|
		const MTPVideoSize &size) {
 | 
						|
	return size.match([&](const MTPDvideoSize &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,
 | 
						|
		};
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
ImageWithLocation FromVideoSize(
 | 
						|
		not_null<Main::Session*> session,
 | 
						|
		const MTPDphoto &photo,
 | 
						|
		const MTPVideoSize &size) {
 | 
						|
	return size.match([&](const MTPDvideoSize &data) {
 | 
						|
		return ImageWithLocation{
 | 
						|
			.location = ImageLocation(
 | 
						|
				DownloadLocation{ StorageFileLocation(
 | 
						|
					photo.vdc_id().v,
 | 
						|
					session->userId(),
 | 
						|
					MTP_inputPhotoFileLocation(
 | 
						|
						photo.vid(),
 | 
						|
						photo.vaccess_hash(),
 | 
						|
						photo.vfile_reference(),
 | 
						|
						data.vtype())) },
 | 
						|
				data.vw().v,
 | 
						|
				data.vh().v),
 | 
						|
			.bytesCount = data.vsize().v,
 | 
						|
		};
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Images
 |