Example #1
0
void FileLoadTask::process() {
	const QString stickerMime = qsl("image/webp");

	_result = FileLoadResultPtr(new FileLoadResult(_id, _to, _originalText));

	QString filename, filemime;
	qint64 filesize = 0;
	QByteArray filedata;

	uint64 thumbId = 0;
	QString thumbname = "thumb.jpg";
	QByteArray thumbdata;

	bool animated = false, song = false, gif = false, voice = (_type == PrepareAudio);
	QImage fullimage = _image;

	if (!_filepath.isEmpty()) {
		QFileInfo info(_filepath);
		if (info.isDir()) {
			_result->filesize = -1;
			return;
		}
		filesize = info.size();
		filemime = mimeTypeForFile(info).name();
		filename = info.fileName();
		if (filesize <= MaxUploadPhotoSize && !voice) {
			bool opaque = (filemime != stickerMime);
			fullimage = App::readImage(_filepath, 0, opaque, &animated);
		}
	} else if (!_content.isEmpty()) {
		filesize = _content.size();
		if (voice) {
			filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
			filemime = "audio/ogg";
		} else {
			MimeType mimeType = mimeTypeForData(_content);
			filemime = mimeType.name();
			if (filesize <= MaxUploadPhotoSize && !voice) {
				bool opaque = (filemime != stickerMime);
				fullimage = App::readImage(_content, 0, opaque, &animated);
			}
			if (filemime == "image/jpeg") {
				filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
			} else {
				QString ext;
				QStringList patterns = mimeType.globPatterns();
				if (!patterns.isEmpty()) {
					ext = patterns.front().replace('*', QString());
				}
				filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
			}
		}
	} else if (!_image.isNull()) {
		_image = QImage();

		filemime = mimeTypeForName("image/png").name();
		filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
		{
			QBuffer buffer(&_content);
			fullimage.save(&buffer, "PNG");
		}
		filesize = _content.size();

		if (fullimage.hasAlphaChannel()) {
			QImage solid(fullimage.width(), fullimage.height(), QImage::Format_ARGB32_Premultiplied);
			solid.fill(st::white->c);
			{
				QPainter(&solid).drawImage(0, 0, fullimage);
			}
			fullimage = solid;
		}
	}
	_result->filesize = (int32)qMin(filesize, qint64(INT_MAX));

	if (!filesize || filesize > MaxUploadDocumentSize) {
		return;
	}

	PreparedPhotoThumbs photoThumbs;
	QVector<MTPPhotoSize> photoSizes;
	QPixmap thumb;

	QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));

	MTPPhotoSize thumbSize(MTP_photoSizeEmpty(MTP_string("")));
	MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
	MTPDocument document(MTP_documentEmpty(MTP_long(0)));

	if (!voice) {
		if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
			filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
			filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
			filename.endsWith(qstr(".flac"), Qt::CaseInsensitive)) {
			QImage cover;
			QByteArray coverBytes, coverFormat;
			MTPDocumentAttribute audioAttribute = audioReadSongAttributes(_filepath, _content, cover, coverBytes, coverFormat);
			if (audioAttribute.type() == mtpc_documentAttributeAudio) {
				attributes.push_back(audioAttribute);
				song = true;
				if (!cover.isNull()) { // cover to thumb
					int32 cw = cover.width(), ch = cover.height();
					if (cw < 20 * ch && ch < 20 * cw) {
						QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly);
						{
							QByteArray thumbFormat = "JPG";
							int32 thumbQuality = 87;

							QBuffer buffer(&thumbdata);
							full.save(&buffer, thumbFormat, thumbQuality);
						}

						thumb = full;
						thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

						thumbId = rand_value<uint64>();
					}
				}
			}
		}
		if (filemime == qstr("video/mp4") || filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive) || animated) {
			QImage cover;
			MTPDocumentAttribute animatedAttribute = clipReadAnimatedAttributes(_filepath, _content, cover);
			if (animatedAttribute.type() == mtpc_documentAttributeVideo) {
				int32 cw = cover.width(), ch = cover.height();
				if (cw < 20 * ch && ch < 20 * cw) {
					attributes.push_back(MTP_documentAttributeAnimated());
					attributes.push_back(animatedAttribute);
					gif = true;

					QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly);
					{
						QByteArray thumbFormat = "JPG";
						int32 thumbQuality = 87;

						QBuffer buffer(&thumbdata);
						full.save(&buffer, thumbFormat, thumbQuality);
					}

					thumb = full;
					thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

					thumbId = rand_value<uint64>();

					if (filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive)) {
						filemime = qstr("video/mp4");
					}
				}
			}
		}
	}

	if (!fullimage.isNull() && fullimage.width() > 0 && !song && !gif && !voice) {
		int32 w = fullimage.width(), h = fullimage.height();
		attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));

		if (w < 20 * h && h < 20 * w) {
			if (animated) {
				attributes.push_back(MTP_documentAttributeAnimated());
			} else if (_type != PrepareDocument) {
				QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('s', thumb);
				photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));

				QPixmap medium = (w > 320 || h > 320) ? QPixmap::fromImage(fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('m', medium);
				photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));

				QPixmap full = (w > 1280 || h > 1280) ? QPixmap::fromImage(fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('y', full);
				photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));

				{
					QBuffer buffer(&filedata);
					full.save(&buffer, "JPG", 77);
				}

				photo = MTP_photo(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));
			}

			QByteArray thumbFormat = "JPG";
			int32 thumbQuality = 87;
			if (!animated && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
				attributes.push_back(MTP_documentAttributeSticker(MTP_string(""), MTP_inputStickerSetEmpty()));
				thumbFormat = "webp";
				thumbname = qsl("thumb.webp");
			}

			QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(fullimage.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fullimage, Qt::ColorOnly);

			{
				QBuffer buffer(&thumbdata);
				full.save(&buffer, thumbFormat, thumbQuality);
			}

			thumb = full;
			thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

			thumbId = rand_value<uint64>();
		}
	}

	if (voice) {
		attributes[0] = MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform)));
		attributes.resize(1);
		document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
	} else {
		document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
		if (photo.type() == mtpc_photoEmpty) {
			_type = PrepareDocument;
		}
	}

	_result->type = _type;
	_result->filepath = _filepath;
	_result->content = _content;

	_result->filename = filename;
	_result->filemime = filemime;
	_result->setFileData(filedata);

	_result->thumbId = thumbId;
	_result->thumbname = thumbname;
	_result->setThumbData(thumbdata);
	_result->thumb = thumb;

	_result->photo = photo;
	_result->document = document;
	_result->photoThumbs = photoThumbs;
}
void LocalImageLoaderPrivate::prepareImages() {
	QString file, filename, mime, stickerMime = qsl("image/webp");
    int32 filesize = 0;
	QImage img;
	QByteArray data;
	PeerId peer;
    uint64 id, thumbId = 0;
	int32 duration = 0;
	QString thumbExt = "jpg";
	ToPrepareMediaType type;
	bool animated = false;
	bool ctrlShiftEnter = false;
	MsgId replyTo = 0;
	{
		QMutexLocker lock(loader->toPrepareMutex());
		ToPrepareMedias &list(loader->toPrepareMedias());
		if (list.isEmpty()) return;

		file = list.front().file;
		img = list.front().img;
		data = list.front().data;
		peer = list.front().peer;
		id = list.front().id;
		type = list.front().type;
		duration = list.front().duration;
		ctrlShiftEnter = list.front().ctrlShiftEnter;
		replyTo = list.front().replyTo;
	}

	if (img.isNull()) {
		if (!file.isEmpty()) {
			QFileInfo info(file);
			if (type == ToPrepareAuto) {
				QString lower(file.toLower());
				const QStringList &photoExtensions(cPhotoExtensions());
				for (QStringList::const_iterator i = photoExtensions.cbegin(), e = photoExtensions.cend(); i != e; ++i) {
					if (lower.lastIndexOf(*i) == lower.size() - i->size()) {
						if (info.size() < MaxUploadPhotoSize) {
							type = ToPreparePhoto;
							break;
						}
					}
				}
				if (type == ToPrepareAuto && info.size() < MaxUploadDocumentSize) {
					type = ToPrepareDocument;
				}
			}
			if (type == ToPrepareDocument) {
				mime = mimeTypeForFile(info).name();
			}
			if (type != ToPrepareAuto && info.size() < MaxUploadPhotoSize) {
				bool opaque = (mime != stickerMime);
				img = App::readImage(file, 0, opaque, &animated);
			}
			filename = info.fileName();
			filesize = info.size();
		} else if (!data.isEmpty()) {
			if (type != ToPrepareAudio) {
				img = App::readImage(data, 0, true, &animated);
				if (type == ToPrepareAuto) {
					if (!img.isNull() && data.size() < MaxUploadPhotoSize) {
						type = ToPreparePhoto;
					} else if (data.size() < MaxUploadDocumentSize) {
						type = ToPrepareDocument;
					} else {
						img = QImage();
					}
				}
			}
			MimeType mimeType = mimeTypeForData(data);
			if (type == ToPrepareDocument || type == ToPrepareAudio) {
				mime = mimeType.name();
			}
			if (mime == "image/jpeg") {
				filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
			} else if (type == ToPrepareAudio) {
				filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
				mime = "audio/ogg";
			} else {
				QString ext;
				QStringList patterns = mimeType.globPatterns();
				if (!patterns.isEmpty()) {
					ext = patterns.front().replace('*', QString());
				}
				filename = filedialogDefaultName((type == ToPrepareAudio) ? qsl("audio") : qsl("doc"), ext, QString(), true);
			}
			filesize = data.size();
		}
	} else {
		if (type == ToPrepareDocument) {
			filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
			mime = mimeTypeForName("image/png").name();
			data = QByteArray();
			{
				QBuffer b(&data);
				img.save(&b, "PNG");
			}
			filesize = data.size();
		} else {
			if (img.hasAlphaChannel()) {
				QImage solid(img.width(), img.height(), QImage::Format_ARGB32_Premultiplied);
				solid.fill(st::white->c);
				{
					QPainter(&solid).drawImage(0, 0, img);
				}
				img = solid;
			}
			type = ToPreparePhoto;
			filename = qsl("Untitled.jpg");
			filesize = 0;
		}
	}

	if ((img.isNull() && ((type != ToPrepareDocument && type != ToPrepareAudio) || !filesize)) || type == ToPrepareAuto || (img.isNull() && file.isEmpty() && data.isEmpty())) { // if could not decide what type
		{
			QMutexLocker lock(loader->toPrepareMutex());
			ToPrepareMedias &list(loader->toPrepareMedias());
			list.pop_front();
		}

		QTimer::singleShot(1, this, SLOT(prepareImages()));

		emit imageFailed(id);
	} else {
		PreparedPhotoThumbs photoThumbs;
		QVector<MTPPhotoSize> photoSizes;

		QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));

		MTPPhotoSize thumb(MTP_photoSizeEmpty(MTP_string("")));
		MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
		MTPDocument document(MTP_documentEmpty(MTP_long(0)));
		MTPAudio audio(MTP_audioEmpty(MTP_long(0)));

		QByteArray jpeg;
		if (type == ToPreparePhoto) {
			int32 w = img.width(), h = img.height();

			QPixmap thumb = (w > 100 || h > 100) ? QPixmap::fromImage(img.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img);
			photoThumbs.insert('s', thumb);
			photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));

			QPixmap medium = (w > 320 || h > 320) ? QPixmap::fromImage(img.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img);
			photoThumbs.insert('m', medium);
			photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));

			QPixmap full = (w > 1280 || h > 1280) ? QPixmap::fromImage(img.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img);
			photoThumbs.insert('y', full);
			photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));

			{
				QBuffer jpegBuffer(&jpeg);
				full.save(&jpegBuffer, "JPG", 77);
			}
			if (!filesize) filesize = jpeg.size();
		
			photo = MTP_photo(MTP_long(id), MTP_long(0), MTP_int(user), MTP_int(unixtime()), MTP_geoPointEmpty(), MTP_vector<MTPPhotoSize>(photoSizes));

			thumbId = id;
		} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) {
			int32 w = img.width(), h = img.height();
			QByteArray thumbFormat = "JPG";
			int32 thumbQuality = 87;
			if (animated) {
				attributes.push_back(MTP_documentAttributeAnimated());
			} else if (mime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
				attributes.push_back(MTP_documentAttributeSticker(MTP_string(""), MTP_inputStickerSetEmpty()));
				thumbFormat = "webp";
				thumbExt = qsl("webp");
			}
			attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
			if (w < 20 * h && h < 20 * w) {
				QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img, Qt::ColorOnly);

				{
					QBuffer jpegBuffer(&jpeg);
					full.save(&jpegBuffer, thumbFormat, thumbQuality);
				}

				photoThumbs.insert('0', full);
				thumb = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

				thumbId = MTP::nonce<uint64>();
			}
		}

		if (type == ToPrepareDocument) {
			document = MTP_document(MTP_long(id), MTP_long(0), MTP_int(unixtime()), MTP_string(mime), MTP_int(filesize), thumb, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
		} else if (type == ToPrepareAudio) {
			audio = MTP_audio(MTP_long(id), MTP_long(0), MTP_int(user), MTP_int(unixtime()), MTP_int(duration), MTP_string(mime), MTP_int(filesize), MTP_int(MTP::maindc()));
		}

		{
			QMutexLocker lock(loader->readyMutex());
			loader->readyList().push_back(ReadyLocalMedia(type, file, filename, filesize, data, id, thumbId, thumbExt, peer, photo, audio, photoThumbs, document, jpeg, ctrlShiftEnter, replyTo));
		}

		{
			QMutexLocker lock(loader->toPrepareMutex());
			ToPrepareMedias &list(loader->toPrepareMedias());
			list.pop_front();
		}

		QTimer::singleShot(1, this, SLOT(prepareImages()));

		emit imageReady();
	}
}
Example #3
0
void FileLoadTask::process() {
	const QString stickerMime = qsl("image/webp");

	_result = MakeShared<FileLoadResult>(_id, _to, _caption);

	QString filename, filemime;
	qint64 filesize = 0;
	QByteArray filedata;

	uint64 thumbId = 0;
	QString thumbname = "thumb.jpg";
	QByteArray thumbdata;

	auto animated = false;
	auto song = false;
	auto gif = false;
	auto voice = (_type == SendMediaType::Audio);
	auto fullimage = base::take(_image);
	auto info = _filepath.isEmpty() ? QFileInfo() : QFileInfo(_filepath);
	if (info.exists()) {
		if (info.isDir()) {
			_result->filesize = -1;
			return;
		}
		filesize = info.size();
		filemime = mimeTypeForFile(info).name();
		filename = info.fileName();
		auto opaque = (filemime != stickerMime);
		fullimage = App::readImage(_filepath, 0, opaque, &animated);
	} else if (!_content.isEmpty()) {
		filesize = _content.size();
		if (voice) {
			filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
			filemime = "audio/ogg";
		} else {
			auto mimeType = mimeTypeForData(_content);
			filemime = mimeType.name();
			if (filemime != stickerMime) {
				fullimage = Images::prepareOpaque(std_::move(fullimage));
			}
			if (filemime == "image/jpeg") {
				filename = filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), true);
			} else if (filemime == "image/png") {
				filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
			} else {
				QString ext;
				QStringList patterns = mimeType.globPatterns();
				if (!patterns.isEmpty()) {
					ext = patterns.front().replace('*', QString());
				}
				filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
			}
		}
	} else if (!fullimage.isNull() && fullimage.width() > 0) {
		if (_type == SendMediaType::Photo) {
			auto w = fullimage.width(), h = fullimage.height();
			if (w >= 20 * h || h >= 20 * w) {
				_type = SendMediaType::File;
			} else {
				filesize = -1; // Fill later.
				filemime = mimeTypeForName("image/jpeg").name();
				filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
			}
		}
		if (_type == SendMediaType::File) {
			filemime = mimeTypeForName("image/png").name();
			filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
			{
				QBuffer buffer(&_content);
				fullimage.save(&buffer, "PNG");
			}
			filesize = _content.size();
		}
		fullimage = Images::prepareOpaque(std_::move(fullimage));
	}
	_result->filesize = (int32)qMin(filesize, qint64(INT_MAX));

	if (!filesize || filesize > App::kFileSizeLimit) {
		return;
	}

	PreparedPhotoThumbs photoThumbs;
	QVector<MTPPhotoSize> photoSizes;
	QPixmap thumb;

	QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));

	MTPPhotoSize thumbSize(MTP_photoSizeEmpty(MTP_string("")));
	MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
	MTPDocument document(MTP_documentEmpty(MTP_long(0)));

	if (!voice) {
		if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
			filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
			filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
			filename.endsWith(qstr(".flac"), Qt::CaseInsensitive)) {
			QImage cover;
			QByteArray coverBytes, coverFormat;
			MTPDocumentAttribute audioAttribute = audioReadSongAttributes(_filepath, _content, cover, coverBytes, coverFormat);
			if (audioAttribute.type() == mtpc_documentAttributeAudio) {
				attributes.push_back(audioAttribute);
				song = true;
				if (!cover.isNull()) { // cover to thumb
					int32 cw = cover.width(), ch = cover.height();
					if (cw < 20 * ch && ch < 20 * cw) {
						QPixmap full = (cw > 90 || ch > 90) ? App::pixmapFromImageInPlace(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std_::move(cover));
						{
							QByteArray thumbFormat = "JPG";
							int32 thumbQuality = 87;

							QBuffer buffer(&thumbdata);
							full.save(&buffer, thumbFormat, thumbQuality);
						}

						thumb = full;
						thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

						thumbId = rand_value<uint64>();
					}
				}
			}
		}
		if (filemime == qstr("video/mp4") || filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive) || animated) {
			QImage cover;
			MTPDocumentAttribute animatedAttribute = Media::Clip::readAttributes(_filepath, _content, cover);
			if (animatedAttribute.type() == mtpc_documentAttributeVideo) {
				int32 cw = cover.width(), ch = cover.height();
				if (cw < 20 * ch && ch < 20 * cw) {
					attributes.push_back(MTP_documentAttributeAnimated());
					attributes.push_back(animatedAttribute);
					gif = true;

					QPixmap full = (cw > 90 || ch > 90) ? App::pixmapFromImageInPlace(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : App::pixmapFromImageInPlace(std_::move(cover));
					{
						QByteArray thumbFormat = "JPG";
						int32 thumbQuality = 87;

						QBuffer buffer(&thumbdata);
						full.save(&buffer, thumbFormat, thumbQuality);
					}

					thumb = full;
					thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

					thumbId = rand_value<uint64>();

					if (filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive)) {
						filemime = qstr("video/mp4");
					}
				}
			}
		}
	}

	if (!fullimage.isNull() && fullimage.width() > 0 && !song && !gif && !voice) {
		auto w = fullimage.width(), h = fullimage.height();
		attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));

		if (w < 20 * h && h < 20 * w) {
			if (animated) {
				attributes.push_back(MTP_documentAttributeAnimated());
			} else if (_type != SendMediaType::File) {
				auto thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('s', thumb);
				photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));

				auto medium = (w > 320 || h > 320) ? App::pixmapFromImageInPlace(fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('m', medium);
				photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));

				auto full = (w > 1280 || h > 1280) ? App::pixmapFromImageInPlace(fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
				photoThumbs.insert('y', full);
				photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));

				{
					QBuffer buffer(&filedata);
					full.save(&buffer, "JPG", 87);
				}

				MTPDphoto::Flags photoFlags = 0;
				photo = MTP_photo(MTP_flags(photoFlags), MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_vector<MTPPhotoSize>(photoSizes));

				if (filesize < 0) {
					filesize = _result->filesize = filedata.size();
				}
			}

			QByteArray thumbFormat = "JPG";
			int32 thumbQuality = 87;
			if (!animated && filemime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
				MTPDdocumentAttributeSticker::Flags stickerFlags = 0;
				attributes.push_back(MTP_documentAttributeSticker(MTP_flags(stickerFlags), MTP_string(""), MTP_inputStickerSetEmpty(), MTPMaskCoords()));
				thumbFormat = "webp";
				thumbname = qsl("thumb.webp");
			}

			QPixmap full = (w > 90 || h > 90) ? App::pixmapFromImageInPlace(fullimage.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage, Qt::ColorOnly);

			{
				QBuffer buffer(&thumbdata);
				full.save(&buffer, thumbFormat, thumbQuality);
			}

			thumb = full;
			thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));

			thumbId = rand_value<uint64>();
		}
	}

	if (voice) {
		attributes[0] = MTP_documentAttributeAudio(MTP_flags(MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform)));
		attributes.resize(1);
		document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
	} else if (_type != SendMediaType::Photo) {
		document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
		_type = SendMediaType::File;
	}

	_result->type = _type;
	_result->filepath = _filepath;
	_result->content = _content;

	_result->filename = filename;
	_result->filemime = filemime;
	_result->setFileData(filedata);

	_result->thumbId = thumbId;
	_result->thumbname = thumbname;
	_result->setThumbData(thumbdata);
	_result->thumb = thumb;

	_result->photo = photo;
	_result->document = document;
	_result->photoThumbs = photoThumbs;
}