Fix sending of .tgs stickers.

This commit is contained in:
John Preston 2019-07-03 13:03:01 +02:00
parent da48a78f7c
commit 7034df49e9
5 changed files with 72 additions and 39 deletions

View File

@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/grouped_layout.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "lottie/lottie_single_player.h"
#include "data/data_document.h"
#include "media/clip/media_clip_reader.h"
#include "window/window_session_controller.h"
@ -41,6 +42,7 @@ constexpr auto kMinPreviewWidth = 20;
constexpr auto kShrinkDuration = crl::time(150);
constexpr auto kDragDuration = crl::time(200);
const auto kStickerMimeString = qstr("image/webp");
const auto kAnimatedStickerMimeString = qstr("application/x-tgsticker");
class SingleMediaPreview : public Ui::RpWidget {
public:
@ -82,6 +84,7 @@ private:
int _previewWidth = 0;
int _previewHeight = 0;
Media::Clip::ReaderPointer _gifPreview;
std::unique_ptr<Lottie::SinglePlayer> _lottiePreview;
};
@ -590,7 +593,8 @@ SingleMediaPreview *SingleMediaPreview::Create(
preview.height())) {
return nullptr;
}
const auto sticker = (file.information->filemime == kStickerMimeString);
const auto sticker = (file.information->filemime == kStickerMimeString)
|| (file.information->filemime == kAnimatedStickerMimeString);
return Ui::CreateChild<SingleMediaPreview>(
parent,
controller,
@ -627,7 +631,7 @@ void SingleMediaPreview::preparePreview(
const QString &animatedPreviewPath) {
auto maxW = 0;
auto maxH = 0;
if (_animated) {
if (_animated && !_sticker) {
auto limitW = st::sendMediaPreviewSize;
auto limitH = st::confirmMaxHeight;
maxW = qMax(preview.width(), 1);
@ -683,7 +687,17 @@ void SingleMediaPreview::preparePreview(
void SingleMediaPreview::prepareAnimatedPreview(
const QString &animatedPreviewPath) {
if (!animatedPreviewPath.isEmpty()) {
if (_sticker && _animated) {
const auto box = QSize(_previewWidth, _previewHeight)
* cIntRetinaFactor();
_lottiePreview = std::make_unique<Lottie::SinglePlayer>(
Lottie::ReadContent(QByteArray(), animatedPreviewPath),
Lottie::FrameRequest{ box });
_lottiePreview->updates(
) | rpl::start_with_next([=] {
update();
}, lifetime());
} else if (!animatedPreviewPath.isEmpty()) {
auto callback = [=](Media::Clip::Notification notification) {
clipCallback(notification);
};
@ -734,10 +748,21 @@ void SingleMediaPreview::paintEvent(QPaintEvent *e) {
auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now());
p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), frame);
} else if (_lottiePreview && _lottiePreview->ready()) {
const auto frame = _lottiePreview->frame();
const auto size = frame.size() / cIntRetinaFactor();
p.drawImage(
QRect(
_previewLeft + (_previewWidth - size.width()) / 2,
st::boxPhotoPadding.top() + (_previewHeight - size.height()) / 2,
size.width(),
size.height()),
frame);
_lottiePreview->markFrameShown();
} else {
p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), _preview);
}
if (_animated && !_gifPreview) {
if (_animated && !_gifPreview && !_lottiePreview) {
auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
p.setBrush(st::msgDateImgBg);

View File

@ -18,6 +18,7 @@ MimeType::MimeType(Known type) : _type(type) {
QStringList MimeType::globPatterns() const {
switch (_type) {
case Known::WebP: return QStringList(qsl("*.webp"));
case Known::Tgs: return QStringList(qsl("*.tgs"));
case Known::TDesktopTheme: return QStringList(qsl("*.tdesktop-theme"));
case Known::TDesktopPalette: return QStringList(qsl("*.tdesktop-palette"));
default: break;
@ -28,6 +29,7 @@ QStringList MimeType::globPatterns() const {
QString MimeType::filterString() const {
switch (_type) {
case Known::WebP: return qsl("WebP image (*.webp)");
case Known::Tgs: return qsl("Telegram sticker (*.tgs)");
case Known::TDesktopTheme: return qsl("Theme files (*.tdesktop-theme)");
case Known::TDesktopPalette: return qsl("Palette files (*.tdesktop-palette)");
default: break;
@ -38,6 +40,7 @@ QString MimeType::filterString() const {
QString MimeType::name() const {
switch (_type) {
case Known::WebP: return qsl("image/webp");
case Known::Tgs: return qsl("application/x-tgsticker");
case Known::TDesktopTheme: return qsl("application/x-tdesktop-theme");
case Known::TDesktopPalette: return qsl("application/x-tdesktop-palette");
default: break;
@ -48,6 +51,8 @@ QString MimeType::name() const {
MimeType MimeTypeForName(const QString &mime) {
if (mime == qstr("image/webp")) {
return MimeType(MimeType::Known::WebP);
} else if (mime == qstr("application/x-tgsticker")) {
return MimeType(MimeType::Known::Tgs);
} else if (mime == qstr("application/x-tdesktop-theme")) {
return MimeType(MimeType::Known::TDesktopTheme);
} else if (mime == qstr("application/x-tdesktop-palette")) {
@ -62,6 +67,8 @@ MimeType MimeTypeForFile(const QFileInfo &file) {
QString path = file.absoluteFilePath();
if (path.endsWith(qstr(".webp"), Qt::CaseInsensitive)) {
return MimeType(MimeType::Known::WebP);
} else if (path.endsWith(qstr(".tgs"), Qt::CaseInsensitive)) {
return MimeType(MimeType::Known::Tgs);
} else if (path.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive)) {
return MimeType(MimeType::Known::TDesktopTheme);
} else if (path.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive)) {

View File

@ -20,6 +20,7 @@ public:
TDesktopTheme,
TDesktopPalette,
WebP,
Tgs,
};
explicit MimeType(const QMimeType &type);

View File

@ -78,13 +78,8 @@ PreparedFileThumbnail PrepareFileThumbnail(QImage &&original) {
PreparedFileThumbnail PrepareAnimatedStickerThumbnail(
const QString &file,
const QByteArray &bytes) {
return PrepareFileThumbnail(Lottie::ReadThumbnail([&] {
if (!bytes.isEmpty()) {
return bytes;
}
auto f = QFile(file);
return f.open(QIODevice::ReadOnly) ? f.readAll() : QByteArray();
}()));
return PrepareFileThumbnail(
Lottie::ReadThumbnail(Lottie::ReadContent(bytes, file)));
}
bool FileThumbnailUploadRequired(const QString &filemime, int32 filesize) {
@ -683,14 +678,23 @@ bool FileLoadTask::CheckForImage(
const QByteArray &content,
std::unique_ptr<FileMediaInformation> &result) {
auto animated = false;
auto image = ([&filepath, &content, &animated] {
auto image = [&] {
if (filepath.endsWith(qstr(".tgs"), Qt::CaseInsensitive)) {
auto image = Lottie::ReadThumbnail(
Lottie::ReadContent(content, filepath));
if (!image.isNull()) {
animated = true;
result->filemime = qstr("application/x-tgsticker");
}
return image;
}
if (!content.isEmpty()) {
return App::readImage(content, nullptr, false, &animated);
} else if (!filepath.isEmpty()) {
return App::readImage(filepath, nullptr, false, &animated);
}
return QImage();
})();
}();
return FillImageInformation(std::move(image), animated, result);
}
@ -712,6 +716,7 @@ bool FileLoadTask::FillImageInformation(
void FileLoadTask::process() {
const auto stickerMime = qsl("image/webp");
const auto animatedStickerMime = qsl("application/x-tgsticker");
_result = std::make_shared<FileLoadResult>(
id(),
@ -754,7 +759,7 @@ void FileLoadTask::process() {
if (auto image = base::get_if<FileMediaInformation::Image>(
&_information->media)) {
fullimage = base::take(image->data);
if (auto opaque = (filemime != stickerMime)) {
if (filemime != stickerMime && filemime != animatedStickerMime) {
fullimage = Images::prepareOpaque(std::move(fullimage));
}
isAnimation = image->animated;
@ -773,7 +778,7 @@ void FileLoadTask::process() {
}
const auto mimeType = Core::MimeTypeForData(_content);
filemime = mimeType.name();
if (filemime != stickerMime) {
if (filemime != stickerMime && filemime != animatedStickerMime) {
fullimage = Images::prepareOpaque(std::move(fullimage));
}
if (filemime == "image/jpeg") {
@ -830,10 +835,6 @@ void FileLoadTask::process() {
QByteArray goodThumbnailBytes;
QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));
const auto checkAnimatedSticker = filename.endsWith(qstr(".tgs"), Qt::CaseInsensitive);
if (checkAnimatedSticker) {
filemime = "application/x-tgsticker";
}
auto thumbnail = PreparedFileThumbnail();
@ -872,8 +873,6 @@ void FileLoadTask::process() {
}
thumbnail = PrepareFileThumbnail(std::move(video->thumbnail));
} else if (checkAnimatedSticker) {
thumbnail = PrepareAnimatedStickerThumbnail(_filepath, _content);
}
}
@ -882,7 +881,20 @@ void FileLoadTask::process() {
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
if (ValidateThumbDimensions(w, h)) {
if (isAnimation) {
isSticker = (filemime == stickerMime
|| filemime == animatedStickerMime)
&& (w > 0)
&& (h > 0)
&& (w <= StickerMaxSize)
&& (h <= StickerMaxSize)
&& (filesize < Storage::kMaxStickerInMemory);
if (isSticker) {
attributes.push_back(MTP_documentAttributeSticker(
MTP_flags(0),
MTP_string(QString()),
MTP_inputStickerSetEmpty(),
MTPMaskCoords()));
} else if (isAnimation) {
attributes.push_back(MTP_documentAttributeAnimated());
} else if (_type != SendMediaType::File) {
auto thumb = (w > 100 || h > 100) ? fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
@ -915,21 +927,6 @@ void FileLoadTask::process() {
filesize = _result->filesize = filedata.size();
}
}
isSticker = !isAnimation
&& (filemime == stickerMime)
&& (w > 0)
&& (h > 0)
&& (w <= StickerMaxSize)
&& (h <= StickerMaxSize)
&& (filesize < Storage::kMaxStickerInMemory);
if (isSticker) {
attributes.push_back(MTP_documentAttributeSticker(
MTP_flags(0),
MTP_string(QString()),
MTP_inputStickerSetEmpty(),
MTPMaskCoords()));
}
thumbnail = PrepareFileThumbnail(std::move(fullimage));
}
}
@ -937,7 +934,7 @@ void FileLoadTask::process() {
std::move(thumbnail),
filemime,
filesize,
isSticker || checkAnimatedSticker);
isSticker);
if (_type == SendMediaType::Photo && photo.type() == mtpc_photoEmpty) {
_type = SendMediaType::File;

View File

@ -316,7 +316,10 @@ bool PreparedList::canAddCaption(bool isAlbum, bool compressImages) const {
if (files.empty() || compressImages) {
return false;
}
return (files.front().mime == qstr("image/webp"));
return (files.front().mime == qstr("image/webp"))
|| files.front().path.endsWith(
qstr(".tgs"),
Qt::CaseInsensitive);
};
return isAlbum || (files.size() == 1 && !isSticker());
}