mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Fix sending of .tgs stickers.
This commit is contained in:
parent
da48a78f7c
commit
7034df49e9
5 changed files with 72 additions and 39 deletions
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/grouped_layout.h"
|
#include "ui/grouped_layout.h"
|
||||||
#include "ui/text_options.h"
|
#include "ui/text_options.h"
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "media/clip/media_clip_reader.h"
|
#include "media/clip/media_clip_reader.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -41,6 +42,7 @@ constexpr auto kMinPreviewWidth = 20;
|
||||||
constexpr auto kShrinkDuration = crl::time(150);
|
constexpr auto kShrinkDuration = crl::time(150);
|
||||||
constexpr auto kDragDuration = crl::time(200);
|
constexpr auto kDragDuration = crl::time(200);
|
||||||
const auto kStickerMimeString = qstr("image/webp");
|
const auto kStickerMimeString = qstr("image/webp");
|
||||||
|
const auto kAnimatedStickerMimeString = qstr("application/x-tgsticker");
|
||||||
|
|
||||||
class SingleMediaPreview : public Ui::RpWidget {
|
class SingleMediaPreview : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -82,6 +84,7 @@ private:
|
||||||
int _previewWidth = 0;
|
int _previewWidth = 0;
|
||||||
int _previewHeight = 0;
|
int _previewHeight = 0;
|
||||||
Media::Clip::ReaderPointer _gifPreview;
|
Media::Clip::ReaderPointer _gifPreview;
|
||||||
|
std::unique_ptr<Lottie::SinglePlayer> _lottiePreview;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -590,7 +593,8 @@ SingleMediaPreview *SingleMediaPreview::Create(
|
||||||
preview.height())) {
|
preview.height())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const auto sticker = (file.information->filemime == kStickerMimeString);
|
const auto sticker = (file.information->filemime == kStickerMimeString)
|
||||||
|
|| (file.information->filemime == kAnimatedStickerMimeString);
|
||||||
return Ui::CreateChild<SingleMediaPreview>(
|
return Ui::CreateChild<SingleMediaPreview>(
|
||||||
parent,
|
parent,
|
||||||
controller,
|
controller,
|
||||||
|
@ -627,7 +631,7 @@ void SingleMediaPreview::preparePreview(
|
||||||
const QString &animatedPreviewPath) {
|
const QString &animatedPreviewPath) {
|
||||||
auto maxW = 0;
|
auto maxW = 0;
|
||||||
auto maxH = 0;
|
auto maxH = 0;
|
||||||
if (_animated) {
|
if (_animated && !_sticker) {
|
||||||
auto limitW = st::sendMediaPreviewSize;
|
auto limitW = st::sendMediaPreviewSize;
|
||||||
auto limitH = st::confirmMaxHeight;
|
auto limitH = st::confirmMaxHeight;
|
||||||
maxW = qMax(preview.width(), 1);
|
maxW = qMax(preview.width(), 1);
|
||||||
|
@ -683,7 +687,17 @@ void SingleMediaPreview::preparePreview(
|
||||||
|
|
||||||
void SingleMediaPreview::prepareAnimatedPreview(
|
void SingleMediaPreview::prepareAnimatedPreview(
|
||||||
const QString &animatedPreviewPath) {
|
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) {
|
auto callback = [=](Media::Clip::Notification notification) {
|
||||||
clipCallback(notification);
|
clipCallback(notification);
|
||||||
};
|
};
|
||||||
|
@ -734,10 +748,21 @@ void SingleMediaPreview::paintEvent(QPaintEvent *e) {
|
||||||
auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
|
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());
|
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);
|
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 {
|
} else {
|
||||||
p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), _preview);
|
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);
|
auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(st::msgDateImgBg);
|
p.setBrush(st::msgDateImgBg);
|
||||||
|
|
|
@ -18,6 +18,7 @@ MimeType::MimeType(Known type) : _type(type) {
|
||||||
QStringList MimeType::globPatterns() const {
|
QStringList MimeType::globPatterns() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case Known::WebP: return QStringList(qsl("*.webp"));
|
case Known::WebP: return QStringList(qsl("*.webp"));
|
||||||
|
case Known::Tgs: return QStringList(qsl("*.tgs"));
|
||||||
case Known::TDesktopTheme: return QStringList(qsl("*.tdesktop-theme"));
|
case Known::TDesktopTheme: return QStringList(qsl("*.tdesktop-theme"));
|
||||||
case Known::TDesktopPalette: return QStringList(qsl("*.tdesktop-palette"));
|
case Known::TDesktopPalette: return QStringList(qsl("*.tdesktop-palette"));
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -28,6 +29,7 @@ QStringList MimeType::globPatterns() const {
|
||||||
QString MimeType::filterString() const {
|
QString MimeType::filterString() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case Known::WebP: return qsl("WebP image (*.webp)");
|
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::TDesktopTheme: return qsl("Theme files (*.tdesktop-theme)");
|
||||||
case Known::TDesktopPalette: return qsl("Palette files (*.tdesktop-palette)");
|
case Known::TDesktopPalette: return qsl("Palette files (*.tdesktop-palette)");
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -38,6 +40,7 @@ QString MimeType::filterString() const {
|
||||||
QString MimeType::name() const {
|
QString MimeType::name() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case Known::WebP: return qsl("image/webp");
|
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::TDesktopTheme: return qsl("application/x-tdesktop-theme");
|
||||||
case Known::TDesktopPalette: return qsl("application/x-tdesktop-palette");
|
case Known::TDesktopPalette: return qsl("application/x-tdesktop-palette");
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -48,6 +51,8 @@ QString MimeType::name() const {
|
||||||
MimeType MimeTypeForName(const QString &mime) {
|
MimeType MimeTypeForName(const QString &mime) {
|
||||||
if (mime == qstr("image/webp")) {
|
if (mime == qstr("image/webp")) {
|
||||||
return MimeType(MimeType::Known::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")) {
|
} else if (mime == qstr("application/x-tdesktop-theme")) {
|
||||||
return MimeType(MimeType::Known::TDesktopTheme);
|
return MimeType(MimeType::Known::TDesktopTheme);
|
||||||
} else if (mime == qstr("application/x-tdesktop-palette")) {
|
} else if (mime == qstr("application/x-tdesktop-palette")) {
|
||||||
|
@ -62,6 +67,8 @@ MimeType MimeTypeForFile(const QFileInfo &file) {
|
||||||
QString path = file.absoluteFilePath();
|
QString path = file.absoluteFilePath();
|
||||||
if (path.endsWith(qstr(".webp"), Qt::CaseInsensitive)) {
|
if (path.endsWith(qstr(".webp"), Qt::CaseInsensitive)) {
|
||||||
return MimeType(MimeType::Known::WebP);
|
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)) {
|
} else if (path.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive)) {
|
||||||
return MimeType(MimeType::Known::TDesktopTheme);
|
return MimeType(MimeType::Known::TDesktopTheme);
|
||||||
} else if (path.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive)) {
|
} else if (path.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive)) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ public:
|
||||||
TDesktopTheme,
|
TDesktopTheme,
|
||||||
TDesktopPalette,
|
TDesktopPalette,
|
||||||
WebP,
|
WebP,
|
||||||
|
Tgs,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit MimeType(const QMimeType &type);
|
explicit MimeType(const QMimeType &type);
|
||||||
|
|
|
@ -78,13 +78,8 @@ PreparedFileThumbnail PrepareFileThumbnail(QImage &&original) {
|
||||||
PreparedFileThumbnail PrepareAnimatedStickerThumbnail(
|
PreparedFileThumbnail PrepareAnimatedStickerThumbnail(
|
||||||
const QString &file,
|
const QString &file,
|
||||||
const QByteArray &bytes) {
|
const QByteArray &bytes) {
|
||||||
return PrepareFileThumbnail(Lottie::ReadThumbnail([&] {
|
return PrepareFileThumbnail(
|
||||||
if (!bytes.isEmpty()) {
|
Lottie::ReadThumbnail(Lottie::ReadContent(bytes, file)));
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
auto f = QFile(file);
|
|
||||||
return f.open(QIODevice::ReadOnly) ? f.readAll() : QByteArray();
|
|
||||||
}()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileThumbnailUploadRequired(const QString &filemime, int32 filesize) {
|
bool FileThumbnailUploadRequired(const QString &filemime, int32 filesize) {
|
||||||
|
@ -683,14 +678,23 @@ bool FileLoadTask::CheckForImage(
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
std::unique_ptr<FileMediaInformation> &result) {
|
std::unique_ptr<FileMediaInformation> &result) {
|
||||||
auto animated = false;
|
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()) {
|
if (!content.isEmpty()) {
|
||||||
return App::readImage(content, nullptr, false, &animated);
|
return App::readImage(content, nullptr, false, &animated);
|
||||||
} else if (!filepath.isEmpty()) {
|
} else if (!filepath.isEmpty()) {
|
||||||
return App::readImage(filepath, nullptr, false, &animated);
|
return App::readImage(filepath, nullptr, false, &animated);
|
||||||
}
|
}
|
||||||
return QImage();
|
return QImage();
|
||||||
})();
|
}();
|
||||||
return FillImageInformation(std::move(image), animated, result);
|
return FillImageInformation(std::move(image), animated, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,6 +716,7 @@ bool FileLoadTask::FillImageInformation(
|
||||||
|
|
||||||
void FileLoadTask::process() {
|
void FileLoadTask::process() {
|
||||||
const auto stickerMime = qsl("image/webp");
|
const auto stickerMime = qsl("image/webp");
|
||||||
|
const auto animatedStickerMime = qsl("application/x-tgsticker");
|
||||||
|
|
||||||
_result = std::make_shared<FileLoadResult>(
|
_result = std::make_shared<FileLoadResult>(
|
||||||
id(),
|
id(),
|
||||||
|
@ -754,7 +759,7 @@ void FileLoadTask::process() {
|
||||||
if (auto image = base::get_if<FileMediaInformation::Image>(
|
if (auto image = base::get_if<FileMediaInformation::Image>(
|
||||||
&_information->media)) {
|
&_information->media)) {
|
||||||
fullimage = base::take(image->data);
|
fullimage = base::take(image->data);
|
||||||
if (auto opaque = (filemime != stickerMime)) {
|
if (filemime != stickerMime && filemime != animatedStickerMime) {
|
||||||
fullimage = Images::prepareOpaque(std::move(fullimage));
|
fullimage = Images::prepareOpaque(std::move(fullimage));
|
||||||
}
|
}
|
||||||
isAnimation = image->animated;
|
isAnimation = image->animated;
|
||||||
|
@ -773,7 +778,7 @@ void FileLoadTask::process() {
|
||||||
}
|
}
|
||||||
const auto mimeType = Core::MimeTypeForData(_content);
|
const auto mimeType = Core::MimeTypeForData(_content);
|
||||||
filemime = mimeType.name();
|
filemime = mimeType.name();
|
||||||
if (filemime != stickerMime) {
|
if (filemime != stickerMime && filemime != animatedStickerMime) {
|
||||||
fullimage = Images::prepareOpaque(std::move(fullimage));
|
fullimage = Images::prepareOpaque(std::move(fullimage));
|
||||||
}
|
}
|
||||||
if (filemime == "image/jpeg") {
|
if (filemime == "image/jpeg") {
|
||||||
|
@ -830,10 +835,6 @@ void FileLoadTask::process() {
|
||||||
QByteArray goodThumbnailBytes;
|
QByteArray goodThumbnailBytes;
|
||||||
|
|
||||||
QVector<MTPDocumentAttribute> attributes(1, MTP_documentAttributeFilename(MTP_string(filename)));
|
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();
|
auto thumbnail = PreparedFileThumbnail();
|
||||||
|
|
||||||
|
@ -872,8 +873,6 @@ void FileLoadTask::process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbnail = PrepareFileThumbnail(std::move(video->thumbnail));
|
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)));
|
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
|
||||||
|
|
||||||
if (ValidateThumbDimensions(w, 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());
|
attributes.push_back(MTP_documentAttributeAnimated());
|
||||||
} else if (_type != SendMediaType::File) {
|
} else if (_type != SendMediaType::File) {
|
||||||
auto thumb = (w > 100 || h > 100) ? fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage;
|
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();
|
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));
|
thumbnail = PrepareFileThumbnail(std::move(fullimage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,7 +934,7 @@ void FileLoadTask::process() {
|
||||||
std::move(thumbnail),
|
std::move(thumbnail),
|
||||||
filemime,
|
filemime,
|
||||||
filesize,
|
filesize,
|
||||||
isSticker || checkAnimatedSticker);
|
isSticker);
|
||||||
|
|
||||||
if (_type == SendMediaType::Photo && photo.type() == mtpc_photoEmpty) {
|
if (_type == SendMediaType::Photo && photo.type() == mtpc_photoEmpty) {
|
||||||
_type = SendMediaType::File;
|
_type = SendMediaType::File;
|
||||||
|
|
|
@ -316,7 +316,10 @@ bool PreparedList::canAddCaption(bool isAlbum, bool compressImages) const {
|
||||||
if (files.empty() || compressImages) {
|
if (files.empty() || compressImages) {
|
||||||
return false;
|
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());
|
return isAlbum || (files.size() == 1 && !isSticker());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue