Added ability to edit GIFs.

- Added to Media::Clip::MakeReader new constructor to create
 animated preview with remoteContent.
This commit is contained in:
23rd 2019-04-08 21:13:18 +03:00 committed by John Preston
parent 49681525ed
commit fb847135b5
5 changed files with 78 additions and 31 deletions

View File

@ -4659,6 +4659,9 @@ void ApiWrap::editUploadedFile(
if (!item) { if (!item) {
return; return;
} }
if (!item->media()) {
return;
}
auto sentEntities = TextUtilities::EntitiesToMTP( auto sentEntities = TextUtilities::EntitiesToMTP(
item->originalText().entities, item->originalText().entities,
@ -4669,21 +4672,31 @@ void ApiWrap::editUploadedFile(
flagsEditMsg |= MTPmessages_EditMessage::Flag::f_entities; flagsEditMsg |= MTPmessages_EditMessage::Flag::f_entities;
flagsEditMsg |= MTPmessages_EditMessage::Flag::f_media; flagsEditMsg |= MTPmessages_EditMessage::Flag::f_media;
MTPinputMedia media = MTP_inputMediaEmpty(); const auto media = [&]() -> std::optional<MTPInputMedia> {
if (!isDocument) {
if (!item->media()->photo()) {
return std::nullopt;
}
return MTP_inputMediaUploadedPhoto(
MTP_flags(0),
file,
MTPVector<MTPInputDocument>(),
MTP_int(0));
}
if (isDocument) {
const auto document = item->media()->document(); const auto document = item->media()->document();
if (!document) { if (!document) {
return; return std::nullopt;
} }
const auto flags = MTPDinputMediaUploadedDocument::Flags(0) const auto flags = MTPDinputMediaUploadedDocument::Flags(0)
| (thumb | (thumb
? MTPDinputMediaUploadedDocument::Flag::f_thumb ? MTPDinputMediaUploadedDocument::Flag::f_thumb
: MTPDinputMediaUploadedDocument::Flag(0)) : MTPDinputMediaUploadedDocument::Flag(0))
// Never edit video as gif. | (item->groupId()
| MTPDinputMediaUploadedDocument::Flag::f_nosound_video; ? MTPDinputMediaUploadedDocument::Flag::f_nosound_video
media = MTP_inputMediaUploadedDocument( : MTPDinputMediaUploadedDocument::Flag(0));
return MTP_inputMediaUploadedDocument(
MTP_flags(flags), MTP_flags(flags),
file, file,
thumb ? *thumb : MTPInputFile(), thumb ? *thumb : MTPInputFile(),
@ -4691,16 +4704,10 @@ void ApiWrap::editUploadedFile(
ComposeSendingDocumentAttributes(document), ComposeSendingDocumentAttributes(document),
MTPVector<MTPInputDocument>(), MTPVector<MTPInputDocument>(),
MTP_int(0)); MTP_int(0));
} else { }();
const auto photo = item->media()->photo();
if (!photo) { if (!media) {
return; return;
}
media = MTP_inputMediaUploadedPhoto(
MTP_flags(0),
file,
MTPVector<MTPInputDocument>(),
MTP_int(0));
} }
request(MTPmessages_EditMessage( request(MTPmessages_EditMessage(
@ -4708,7 +4715,7 @@ void ApiWrap::editUploadedFile(
item->history()->peer->input, item->history()->peer->input,
MTP_int(item->id), MTP_int(item->id),
MTP_string(item->originalText().text), MTP_string(item->originalText().text),
media, *media,
MTPReplyMarkup(), MTPReplyMarkup(),
sentEntities sentEntities
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {

View File

@ -298,10 +298,10 @@ void EditCaptionBox::updateEmojiPanelGeometry() {
} }
void EditCaptionBox::prepareGifPreview(DocumentData* document) { void EditCaptionBox::prepareGifPreview(DocumentData* document) {
const auto newPath = getNewMediaPath(); const auto isListEmpty = _preparedList.files.empty();
if (_gifPreview) { if (_gifPreview) {
return; return;
} else if (!document && newPath.isEmpty()) { } else if (!document && isListEmpty) {
return; return;
} }
const auto callback = [=](Media::Clip::Notification notification) { const auto callback = [=](Media::Clip::Notification notification) {
@ -312,10 +312,17 @@ void EditCaptionBox::prepareGifPreview(DocumentData* document) {
document, document,
_msgId, _msgId,
callback); callback);
} else if (!newPath.isEmpty()) { } else if (!isListEmpty) {
_gifPreview = Media::Clip::MakeReader( const auto file = &_preparedList.files.front();
newPath, if (file->path.isEmpty()) {
callback); _gifPreview = Media::Clip::MakeReader(
file->content,
callback);
} else {
_gifPreview = Media::Clip::MakeReader(
file->path,
callback);
}
} }
if (_gifPreview) _gifPreview->setAutoplay(); if (_gifPreview) _gifPreview->setAutoplay();
} }
@ -329,6 +336,23 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
} }
if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) { if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
const auto calculateGifDimensions = [&]() {
const auto scaled = QSize(
_gifPreview->width(),
_gifPreview->height()).scaled(
st::sendMediaPreviewSize * cIntRetinaFactor(),
st::confirmMaxHeight * cIntRetinaFactor(),
Qt::KeepAspectRatio);
_thumbw = _gifw = scaled.width();
_thumbh = _gifh = scaled.height();
_thumbx = _gifx = (st::boxWideWidth - _gifw) / 2;
updateBoxSize();
};
// If gif file is not mp4,
// Its dimension values will be known only after reading.
if (_gifw <= 0 || _gifh <= 0) {
calculateGifDimensions();
}
const auto s = QSize(_gifw, _gifh); const auto s = QSize(_gifw, _gifh);
_gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None); _gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None);
} }
@ -362,17 +386,19 @@ void EditCaptionBox::updateEditPreview() {
_thumbw = _thumbh = _thumbx = 0; _thumbw = _thumbh = _thumbx = 0;
_gifw = _gifh = _gifx = 0; _gifw = _gifh = _gifx = 0;
auto isGif = false;
auto shouldAsDoc = true; auto shouldAsDoc = true;
if (const auto image = base::get_if<Info::Image>(fileMedia)) { if (const auto image = base::get_if<Info::Image>(fileMedia)) {
shouldAsDoc = !Storage::ValidateThumbDimensions( shouldAsDoc = !Storage::ValidateThumbDimensions(
image->data.width(), image->data.width(),
image->data.height()); image->data.height());
_photo = !shouldAsDoc; isGif = image->animated;
_animated = isGif;
_photo = !isGif && !shouldAsDoc;
_isImage = true; _isImage = true;
} else if (const auto video = base::get_if<Info::Video>(fileMedia)) { } else if (const auto video = base::get_if<Info::Video>(fileMedia)) {
isGif = video->isGifv;
_animated = true; _animated = true;
// Never edit video as gif.
video->isGifv = false;
shouldAsDoc = false; shouldAsDoc = false;
} }
if (shouldAsDoc) { if (shouldAsDoc) {
@ -405,6 +431,12 @@ void EditCaptionBox::updateEditPreview() {
_thumbw = _thumb.width() / cIntRetinaFactor(); _thumbw = _thumb.width() / cIntRetinaFactor();
_thumbh = _thumb.height() / cIntRetinaFactor(); _thumbh = _thumb.height() / cIntRetinaFactor();
_thumbx = (st::boxWideWidth - _thumbw) / 2; _thumbx = (st::boxWideWidth - _thumbw) / 2;
if (isGif) {
_gifw = _thumbw;
_gifh = _thumbh;
_gifx = _thumbx;
prepareGifPreview();
}
} }
updateEditMediaButton(); updateEditMediaButton();
captionResized(); captionResized();
@ -427,8 +459,7 @@ void EditCaptionBox::createEditMediaButton() {
} }
const auto isValidFile = [](QString mimeType) { const auto isValidFile = [](QString mimeType) {
if (mimeType == qstr("image/webp") if (mimeType == qstr("image/webp")) {
|| mimeType == qstr("image/gif")) {
Ui::show( Ui::show(
Box<InformBox>(lang(lng_edit_media_invalid_file)), Box<InformBox>(lang(lng_edit_media_invalid_file)),
LayerOption::KeepOther); LayerOption::KeepOther);
@ -477,8 +508,10 @@ void EditCaptionBox::createEditMediaButton() {
const auto valid = media->match([&](const Info::Image &data) { const auto valid = media->match([&](const Info::Image &data) {
return Storage::ValidateThumbDimensions( return Storage::ValidateThumbDimensions(
data.data.width(), data.data.width(),
data.data.height()); data.data.height())
}, [&](const Info::Video &data) { && !data.animated;
}, [&](Info::Video &data) {
data.isGifv = false;
return true; return true;
}, [](auto &&other) { }, [](auto &&other) {
return false; return false;

View File

@ -665,7 +665,6 @@ bool MediaFile::allowsEditCaption() const {
bool MediaFile::allowsEditMedia() const { bool MediaFile::allowsEditMedia() const {
return !_document->isVideoMessage() return !_document->isVideoMessage()
&& !_document->sticker() && !_document->sticker()
&& !_document->isGifv()
&& !_document->isVoiceMessage(); && !_document->isVoiceMessage();
} }

View File

@ -98,6 +98,13 @@ Reader::Reader(not_null<DocumentData*> document, FullMsgId msgId, Callback &&cal
init(document->location(), document->data()); init(document->location(), document->data());
} }
Reader::Reader(const QByteArray &data, Callback &&callback, Mode mode, crl::time seekMs)
: _callback(std::move(callback))
, _mode(mode)
, _seekPositionMs(seekMs) {
init(FileLocation(QString()), data);
}
void Reader::init(const FileLocation &location, const QByteArray &data) { void Reader::init(const FileLocation &location, const QByteArray &data) {
if (threads.size() < ClipThreadsCount) { if (threads.size() < ClipThreadsCount) {
_threadIndex = threads.size(); _threadIndex = threads.size();

View File

@ -51,6 +51,7 @@ public:
Reader(const QString &filepath, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); Reader(const QString &filepath, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0);
Reader(not_null<DocumentData*> document, FullMsgId msgId, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); Reader(not_null<DocumentData*> document, FullMsgId msgId, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0);
Reader(const QByteArray &data, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0);
// Reader can be already deleted. // Reader can be already deleted.
static void callback(Reader *reader, qint32 threadIndex, qint32 notification); static void callback(Reader *reader, qint32 threadIndex, qint32 notification);