diff --git a/Telegram/SourceFiles/data/data_cloud_file.cpp b/Telegram/SourceFiles/data/data_cloud_file.cpp index 1e793e95b..49b0fa8fa 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.cpp +++ b/Telegram/SourceFiles/data/data_cloud_file.cpp @@ -214,14 +214,14 @@ void LoadCloudFile( Fn progress, int downloadFrontPartSize = 0) { const auto loadSize = downloadFrontPartSize - ? downloadFrontPartSize + ? std::min(downloadFrontPartSize, file.byteSize) : file.byteSize; if (file.loader) { if (fromCloud == LoadFromCloudOrLocal) { file.loader->permitLoadFromCloud(); } - if (file.loader->fullSize() < loadSize) { - file.loader->increaseLoadSize(loadSize); + if (file.loader->loadSize() < loadSize) { + file.loader->increaseLoadSize(loadSize, autoLoading); } return; } else if ((file.flags & CloudFile::Flag::Failed) @@ -236,6 +236,7 @@ void LoadCloudFile( origin, QString(), loadSize, + file.byteSize, UnknownFileLocation, LoadToCacheAsWell, fromCloud, diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 995139c2e..cbcdd6478 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -1013,6 +1013,7 @@ void DocumentData::save( &session(), _urlLocation, size, + size, fromCloud, autoLoading, cacheTag()); @@ -1039,6 +1040,7 @@ void DocumentData::save( locationType(), toFile, size, + size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading, diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index b748dadb8..6a80d0f05 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -104,7 +104,7 @@ bool PhotoData::loading(PhotoSize size) const { } else if (valid == existing) { return true; } - return (_images[valid].loader->fullSize() + return (_images[valid].loader->loadSize() >= _images[existing].progressivePartSize); } @@ -113,6 +113,10 @@ bool PhotoData::failed(PhotoSize size) const { return (flags & Data::CloudFile::Flag::Failed); } +void PhotoData::clearFailed(PhotoSize size) { + _images[validSizeIndex(size)].flags &= ~Data::CloudFile::Flag::Failed; +} + const ImageLocation &PhotoData::location(PhotoSize size) const { return _images[validSizeIndex(size)].location; } @@ -144,10 +148,11 @@ int PhotoData::imageByteSize(PhotoSize size) const { bool PhotoData::displayLoading() const { const auto index = PhotoSizeIndex(PhotoSize::Large); - return _images[index].loader - ? (!_images[index].loader->loadingLocal() - || !_images[index].loader->autoLoading()) - : (uploading() && !waitingForAlbum()); + if (const auto loader = _images[index].loader.get()) { + return !loader->finished() + && (!loader->loadingLocal() || !loader->autoLoading()); + } + return (uploading() && !waitingForAlbum()); } void PhotoData::cancel() { @@ -262,7 +267,6 @@ void PhotoData::load( // Could've changed, if the requested size didn't have a location. const auto validSize = static_cast(valid); - const auto existingSize = static_cast(existing); const auto finalCheck = [=] { if (const auto active = activeMediaView()) { return !active->image(size); @@ -270,10 +274,25 @@ void PhotoData::load( return true; }; const auto done = [=](QImage result) { - if (const auto active = activeMediaView()) { - active->set(validSize, existingSize, std::move(result)); + Expects(_images[valid].loader != nullptr); + + // Find out what progressive photo size have we loaded exactly. + auto goodFor = validSize; + const auto loadSize = _images[valid].loader->loadSize(); + if (valid > 0 && _images[valid].byteSize > loadSize) { + for (auto i = valid; i != 0;) { + --i; + const auto required = _images[i].progressivePartSize; + if (required > 0 && required <= loadSize) { + goodFor = static_cast(i); + break; + } + } } - if (validSize == PhotoSize::Large) { + if (const auto active = activeMediaView()) { + active->set(validSize, goodFor, std::move(result)); + } + if (validSize == PhotoSize::Large && goodFor == validSize) { _owner->photoLoadDone(this); } }; @@ -453,6 +472,7 @@ void PhotoSaveClickHandler::onClickImpl() const { if (!data->date) { return; } else { + data->clearFailed(PhotoSize::Large); data->load(context()); } } diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index c7442551d..2c2a60066 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -111,6 +111,7 @@ public: [[nodiscard]] bool hasExact(Data::PhotoSize size) const; [[nodiscard]] bool loading(Data::PhotoSize size) const; [[nodiscard]] bool failed(Data::PhotoSize size) const; + void clearFailed(Data::PhotoSize size); void load( Data::PhotoSize size, Data::FileOrigin origin, diff --git a/Telegram/SourceFiles/data/data_photo_media.cpp b/Telegram/SourceFiles/data/data_photo_media.cpp index 1bfc160f2..19035b346 100644 --- a/Telegram/SourceFiles/data/data_photo_media.cpp +++ b/Telegram/SourceFiles/data/data_photo_media.cpp @@ -51,11 +51,15 @@ Image *PhotoMedia::thumbnailInline() const { Image *PhotoMedia::image(PhotoSize size) const { const auto &original = _images[PhotoSizeIndex(size)]; if (const auto image = original.data.get()) { - return (original.goodFor >= size) ? image : nullptr; + if (original.goodFor >= size) { + return image; + } } const auto &valid = _images[_owner->validSizeIndex(size)]; if (const auto image = valid.data.get()) { - return (valid.goodFor >= size) ? image : nullptr; + if (valid.goodFor >= size) { + return image; + } } return nullptr; } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 8811b7b4c..127f93e00 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2147,7 +2147,10 @@ not_null Session::processPhoto( const auto i = find(levels); return (i == thumbs.end()) ? ImageWithLocation() - : Images::FromImageInMemory(i->second, "JPG"); + : Images::FromImageInMemory( + i->second.image, + "JPG", + i->second.bytes); }; const auto small = image(SmallLevels); const auto thumbnail = image(ThumbnailLevels); @@ -2271,7 +2274,7 @@ void Session::photoApplyFields( return 0; }); }; - const auto found = ranges::max_element(sizes, std::greater<>(), area); + const auto found = ranges::max_element(sizes, std::less<>(), area); return (found == sizes.end() || found->type() != mtpc_photoSizeProgressive) ? sizes.end() diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index 4f06cbea0..7b0360b1a 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -287,7 +287,11 @@ using PollId = uint64; using WallPaperId = uint64; constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL); -using PreparedPhotoThumbs = base::flat_map; +struct PreparedPhotoThumb { + QImage image; + QByteArray bytes; +}; +using PreparedPhotoThumbs = base::flat_map; // [0] == -1 -- counting, [0] == -2 -- could not count using VoiceWaveform = QVector; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 0c224817b..1bf7d697d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2137,7 +2137,7 @@ void OverlayWidget::displayDocument( _themeCloudData = cloud; _radial.stop(); - _touchbarDisplay.fire(TouchBarItemType::None); + _touchbarDisplay.fire(TouchBarItemType::None); refreshMediaViewer(); if (_document) { @@ -4161,6 +4161,9 @@ void OverlayWidget::setVisibleHook(bool visible) { _userPhotosData = std::nullopt; _collage = nullptr; _collageData = std::nullopt; + assignMediaPointer(nullptr); + _preloadPhotos.clear(); + _preloadDocuments.clear(); if (_menu) _menu->hideMenu(true); _controlsHideTimer.stop(); _controlsState = ControlsShown; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index 5274b998a..46a1a4b9c 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -1751,6 +1751,7 @@ void FormController::loadFile(File &file) { SecureFileLocation, QString(), file.size, + file.size, LoadToCacheAsWell, LoadFromCloudOrLocal, false, diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 53e070193..d0473049f 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -32,7 +32,8 @@ public: not_null session, const QByteArray &data, const QString &toFile, - int32 size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, @@ -53,7 +54,8 @@ FromMemoryLoader::FromMemoryLoader( not_null session, const QByteArray &data, const QString &toFile, - int32 size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, @@ -62,7 +64,8 @@ FromMemoryLoader::FromMemoryLoader( ) : FileLoader( session, toFile, - size, + loadSize, + fullSize, locationType, toCache, fromCloud, @@ -91,7 +94,8 @@ void FromMemoryLoader::startLoading() { FileLoader::FileLoader( not_null session, const QString &toFile, - int32 size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, @@ -104,9 +108,11 @@ FileLoader::FileLoader( , _file(_filename) , _toCache(toCache) , _fromCloud(fromCloud) -, _size(size) +, _loadSize(loadSize) +, _fullSize(fullSize) , _locationType(locationType) { - Expects(!_filename.isEmpty() || (_size <= Storage::kMaxFileInMemory)); + Expects(_loadSize <= _fullSize); + Expects(!_filename.isEmpty() || (_fullSize <= Storage::kMaxFileInMemory)); } FileLoader::~FileLoader() { @@ -169,13 +175,11 @@ Data::FileOrigin FileLoader::fileOrigin() const { } float64 FileLoader::currentProgress() const { - if (_finished) return 1.; - if (!fullSize()) return 0.; - return snap(float64(currentOffset()) / fullSize(), 0., 1.); -} - -int FileLoader::fullSize() const { - return _size; + return _finished + ? 1. + : !_loadSize + ? 0. + : std::clamp(float64(currentOffset()) / _loadSize, 0., 1.); } bool FileLoader::setFileName(const QString &fileName) { @@ -191,10 +195,12 @@ void FileLoader::permitLoadFromCloud() { _fromCloud = LoadFromCloudOrLocal; } -void FileLoader::increaseLoadSize(int size) { - Expects(size > _size); +void FileLoader::increaseLoadSize(int size, bool autoLoading) { + Expects(size > _loadSize); + Expects(size <= _fullSize); - _size = size; + _loadSize = size; + _autoLoading = autoLoading; } void FileLoader::notifyAboutProgress() { @@ -211,10 +217,12 @@ void FileLoader::localLoaded( start(); return; } - if (result.data.size() < _size) { + const auto partial = result.data.startsWith("partial:"); + constexpr auto kPrefix = 8; + if (partial && result.data.size() < _loadSize + kPrefix) { _localStatus = LocalStatus::NotFound; if (checkForOpen()) { - startLoadingWithData(result.data); + startLoadingWithPartial(result.data); } return; } @@ -222,7 +230,11 @@ void FileLoader::localLoaded( _imageFormat = imageFormat; _imageData = imageData; } - finishWithBytes(result.data); + finishWithBytes(partial + ? QByteArray::fromRawData( + result.data.data() + kPrefix, + result.data.size() - kPrefix) + : result.data); } void FileLoader::start() { @@ -272,7 +284,7 @@ void FileLoader::loadLocal(const Storage::Cache::Key &key) { }; _session->data().cache().get(key, [=, callback = std::move(done)]( QByteArray &&value) mutable { - if (readImage) { + if (readImage && !value.startsWith("partial:")) { crl::async([ value = std::move(value), done = std::move(callback) @@ -452,7 +464,9 @@ bool FileLoader::finalizeResult() { _session->data().cache().put( cacheKey(), Storage::Cache::Database::TaggedValue( - base::duplicate(_data), + base::duplicate((!_fullSize || _data.size() == _fullSize) + ? _data + : ("partial:" + _data)), _cacheTag)); } } @@ -466,7 +480,8 @@ std::unique_ptr CreateFileLoader( const DownloadLocation &location, Data::FileOrigin origin, const QString &toFile, - int size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, @@ -480,7 +495,8 @@ std::unique_ptr CreateFileLoader( origin, locationType, toFile, - size, + loadSize, + fullSize, toCache, fromCloud, autoLoading, @@ -489,7 +505,8 @@ std::unique_ptr CreateFileLoader( result = std::make_unique( session, data, - size, + loadSize, + fullSize, fromCloud, autoLoading, cacheTag); @@ -497,7 +514,8 @@ std::unique_ptr CreateFileLoader( result = std::make_unique( session, data, - size, + loadSize, + fullSize, fromCloud, autoLoading, cacheTag); @@ -514,7 +532,8 @@ std::unique_ptr CreateFileLoader( session, data.bytes, toFile, - size, + loadSize, + fullSize, locationType, toCache, LoadFromCloudOrLocal, diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index 9a2c929de..21a00af6a 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -57,7 +57,8 @@ public: FileLoader( not_null session, const QString &toFile, - int32 size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, @@ -88,11 +89,16 @@ public: [[nodiscard]] virtual Data::FileOrigin fileOrigin() const; [[nodiscard]] float64 currentProgress() const; [[nodiscard]] virtual int currentOffset() const; - [[nodiscard]] int fullSize() const; + [[nodiscard]] int fullSize() const { + return _fullSize; + } + [[nodiscard]] int loadSize() const { + return _loadSize; + } bool setFileName(const QString &filename); // set filename for loaders to cache void permitLoadFromCloud(); - void increaseLoadSize(int size); + void increaseLoadSize(int size, bool autoLoading); void start(); void cancel(); @@ -134,7 +140,7 @@ protected: virtual std::optional fileLocationKey() const = 0; virtual void cancelHook() = 0; virtual void startLoading() = 0; - virtual void startLoadingWithData(const QByteArray &data) { + virtual void startLoadingWithPartial(const QByteArray &data) { startLoading(); } @@ -163,7 +169,8 @@ protected: QByteArray _data; - int _size = 0; + int _loadSize = 0; + int _fullSize = 0; int _skippedBytes = 0; LocationType _locationType = LocationType(); @@ -181,7 +188,8 @@ protected: const DownloadLocation &location, Data::FileOrigin origin, const QString &toFile, - int size, + int loadSize, + int fullSize, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, diff --git a/Telegram/SourceFiles/storage/file_download_mtproto.cpp b/Telegram/SourceFiles/storage/file_download_mtproto.cpp index 1ec361a1d..85b3656ee 100644 --- a/Telegram/SourceFiles/storage/file_download_mtproto.cpp +++ b/Telegram/SourceFiles/storage/file_download_mtproto.cpp @@ -23,7 +23,8 @@ mtpFileLoader::mtpFileLoader( Data::FileOrigin origin, LocationType type, const QString &to, - int32 size, + int loadSize, + int fullSize, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading, @@ -31,7 +32,8 @@ mtpFileLoader::mtpFileLoader( : FileLoader( session, to, - size, + loadSize, + fullSize, type, toCache, fromCloud, @@ -43,14 +45,16 @@ mtpFileLoader::mtpFileLoader( mtpFileLoader::mtpFileLoader( not_null session, const WebFileLocation &location, - int32 size, + int loadSize, + int fullSize, LoadFromCloudSetting fromCloud, bool autoLoading, uint8 cacheTag) : FileLoader( session, QString(), - size, + loadSize, + fullSize, UnknownFileLocation, LoadToCacheAsWell, fromCloud, @@ -65,14 +69,16 @@ mtpFileLoader::mtpFileLoader( mtpFileLoader::mtpFileLoader( not_null session, const GeoPointLocation &location, - int32 size, + int loadSize, + int fullSize, LoadFromCloudSetting fromCloud, bool autoLoading, uint8 cacheTag) : FileLoader( session, QString(), - size, + loadSize, + fullSize, UnknownFileLocation, LoadToCacheAsWell, fromCloud, @@ -101,8 +107,8 @@ uint64 mtpFileLoader::objId() const { bool mtpFileLoader::readyToRequest() const { return !_finished && !_lastComplete - && (_size != 0 || !haveSentRequests()) - && (!_size || _nextRequestOffset < _size); + && (_fullSize != 0 || !haveSentRequests()) + && (!_fullSize || _nextRequestOffset < _loadSize); } int mtpFileLoader::takeNextRequestOffset() { @@ -114,9 +120,7 @@ int mtpFileLoader::takeNextRequestOffset() { } bool mtpFileLoader::feedPart(int offset, const QByteArray &bytes) { - const auto buffer = (_size > 0 && offset + bytes.size() > _size) - ? bytes::make_span(bytes).subspan(0, _size - offset) - : bytes::make_span(bytes); + const auto buffer = bytes::make_span(bytes); if (!writeResultPart(offset, buffer)) { return false; } @@ -124,7 +128,7 @@ bool mtpFileLoader::feedPart(int offset, const QByteArray &bytes) { _lastComplete = true; } const auto finished = !haveSentRequests() - && (_lastComplete || (_size && _nextRequestOffset >= _size)); + && (_lastComplete || (_fullSize && _nextRequestOffset >= _loadSize)); if (finished) { removeFromQueue(); if (!finalizeResult()) { @@ -141,13 +145,13 @@ void mtpFileLoader::cancelOnFail() { } bool mtpFileLoader::setWebFileSizeHook(int size) { - if (!_size || _size == size) { - _size = size; + if (!_fullSize || _fullSize == size) { + _fullSize = _loadSize = size; return true; } LOG(("MTP Error: " "Bad size provided by bot for webDocument: %1, real: %2" - ).arg(_size + ).arg(_fullSize ).arg(size)); cancel(true); return false; @@ -157,12 +161,15 @@ void mtpFileLoader::startLoading() { addToQueue(); } -void mtpFileLoader::startLoadingWithData(const QByteArray &data) { - const auto parts = data.size() / Storage::kDownloadPartSize; +void mtpFileLoader::startLoadingWithPartial(const QByteArray &data) { + Expects(data.startsWith("partial:")); + + constexpr auto kPrefix = 8; + const auto parts = (data.size() - kPrefix) / Storage::kDownloadPartSize; const auto use = parts * Storage::kDownloadPartSize; if (use > 0) { _nextRequestOffset = use; - feedPart(0, QByteArray::fromRawData(data.data(), use)); + feedPart(0, QByteArray::fromRawData(data.data() + kPrefix, use)); } startLoading(); } diff --git a/Telegram/SourceFiles/storage/file_download_mtproto.h b/Telegram/SourceFiles/storage/file_download_mtproto.h index b29fda1f1..3205b5a72 100644 --- a/Telegram/SourceFiles/storage/file_download_mtproto.h +++ b/Telegram/SourceFiles/storage/file_download_mtproto.h @@ -20,7 +20,8 @@ public: Data::FileOrigin origin, LocationType type, const QString &toFile, - int32 size, + int loadSize, + int fullSize, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading, @@ -28,14 +29,16 @@ public: mtpFileLoader( not_null session, const WebFileLocation &location, - int32 size, + int loadSize, + int fullSize, LoadFromCloudSetting fromCloud, bool autoLoading, uint8 cacheTag); mtpFileLoader( not_null session, const GeoPointLocation &location, - int32 size, + int loadSize, + int fullSize, LoadFromCloudSetting fromCloud, bool autoLoading, uint8 cacheTag); @@ -48,7 +51,7 @@ private: Storage::Cache::Key cacheKey() const override; std::optional fileLocationKey() const override; void startLoading() override; - void startLoadingWithData(const QByteArray &data) override; + void startLoadingWithPartial(const QByteArray &data) override; void cancelHook() override; bool readyToRequest() const override; diff --git a/Telegram/SourceFiles/storage/file_download_web.cpp b/Telegram/SourceFiles/storage/file_download_web.cpp index 3c3dfe93b..b0a8b87f5 100644 --- a/Telegram/SourceFiles/storage/file_download_web.cpp +++ b/Telegram/SourceFiles/storage/file_download_web.cpp @@ -446,6 +446,7 @@ webFileLoader::webFileLoader( session, QString(), 0, + 0, UnknownFileLocation, LoadToCacheAsWell, fromCloud, @@ -489,7 +490,7 @@ int webFileLoader::currentOffset() const { } void webFileLoader::loadProgress(qint64 ready, qint64 total) { - _size = total; + _fullSize = _loadSize = total; _ready = ready; notifyAboutProgress(); } diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index 430c48c20..9ae16b848 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -311,8 +311,9 @@ void Uploader::uploadMedia( : session().data().processDocument( media.document, Images::FromImageInMemory( - media.photoThumbs.front().second, - "JPG")); + media.photoThumbs.front().second.image, + "JPG", + media.photoThumbs.front().second.bytes)); if (!media.data.isEmpty()) { document->setDataAndCache(media.data); if (media.type == SendMediaType::ThemeFile) { @@ -345,7 +346,8 @@ void Uploader::upload( file->document, Images::FromImageInMemory( file->thumb, - ThumbnailFormat(file->filemime))); + ThumbnailFormat(file->filemime), + file->thumbbytes)); document->uploadingData = std::make_unique( document->size); if (const auto active = document->activeMediaView()) { diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index 8659a2f28..706f35009 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "app.h" #include +#include namespace { @@ -202,17 +203,23 @@ SendMediaReady PreparePeerPhoto(MTP::DcId dcId, PeerId peerId, QImage &&image) { Qt::KeepAspectRatio, Qt::SmoothTransformation); }; - const auto push = [&](const char *type, QImage &&image) { + const auto push = [&]( + const char *type, + QImage &&image, + QByteArray bytes = QByteArray()) { photoSizes.push_back(MTP_photoSize( MTP_string(type), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(image.width()), MTP_int(image.height()), MTP_int(0))); - photoThumbs.emplace(type[0], std::move(image)); + photoThumbs.emplace(type[0], PreparedPhotoThumb{ + .image = std::move(image), + .bytes = std::move(bytes) + }); }; push("a", scaled(160)); push("b", scaled(320)); - push("c", std::move(image)); + push("c", std::move(image), jpeg); const auto id = rand_value(); const auto photo = MTP_photo( @@ -467,6 +474,7 @@ void FileLoadResult::setFileData(const QByteArray &filedata) { void FileLoadResult::setThumbData(const QByteArray &thumbdata) { if (!thumbdata.isEmpty()) { + thumbbytes = thumbdata; int32 size = thumbdata.size(); for (int32 i = 0, part = 0; i < size; i += kPhotoUploadPartSize, ++part) { thumbparts.insert(part, thumbdata.mid(i, kPhotoUploadPartSize)); @@ -864,17 +872,22 @@ void FileLoadTask::process() { attributes.push_back(MTP_documentAttributeAnimated()); } else if (_type != SendMediaType::File) { auto medium = (w > 320 || h > 320) ? fullimage.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage; - photoThumbs.emplace('m', medium); - photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); - auto full = (w > 1280 || h > 1280) ? fullimage.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation) : fullimage; - photoThumbs.emplace('y', full); - photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); - { QBuffer buffer(&filedata); - full.save(&buffer, "JPG", 87); + QImageWriter writer(&buffer, "JPEG"); + writer.setQuality(87); + writer.setProgressiveScanWrite(true); + writer.write(full); } + photoThumbs.emplace('m', PreparedPhotoThumb{ .image = medium }); + photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0))); + + photoThumbs.emplace('y', PreparedPhotoThumb{ + .image = full, + .bytes = filedata + }); + photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0))); photo = MTP_photo( MTP_flags(0), diff --git a/Telegram/SourceFiles/storage/localimageloader.h b/Telegram/SourceFiles/storage/localimageloader.h index 200e46d0a..b7a40711d 100644 --- a/Telegram/SourceFiles/storage/localimageloader.h +++ b/Telegram/SourceFiles/storage/localimageloader.h @@ -219,6 +219,7 @@ struct FileLoadResult { uint64 thumbId = 0; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos) QString thumbname; UploadFileParts thumbparts; + QByteArray thumbbytes; QByteArray thumbmd5; QImage thumb; diff --git a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp index f0b1e3a5d..edff06b25 100644 --- a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp +++ b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp @@ -42,6 +42,7 @@ StreamedFileDownloader::StreamedFileDownloader( session, toFile, size, + size, locationType, toCache, fromCloud, @@ -107,7 +108,7 @@ void StreamedFileDownloader::requestPart() { } QByteArray StreamedFileDownloader::readLoadedPart(int offset) { - Expects(offset >= 0 && offset < _size); + Expects(offset >= 0 && offset < _fullSize); Expects(!(offset % kPartSize)); const auto index = (offset / kPartSize); diff --git a/Telegram/SourceFiles/ui/image/image_location_factory.cpp b/Telegram/SourceFiles/ui/image/image_location_factory.cpp index 4de02e635..bc86b8c91 100644 --- a/Telegram/SourceFiles/ui/image/image_location_factory.cpp +++ b/Telegram/SourceFiles/ui/image/image_location_factory.cpp @@ -270,13 +270,15 @@ ImageWithLocation FromPhotoSize( ImageWithLocation FromImageInMemory( const QImage &image, - const char *format) { + const char *format, + QByteArray bytes) { if (image.isNull()) { return ImageWithLocation(); } - auto bytes = QByteArray(); - auto buffer = QBuffer(&bytes); - image.save(&buffer, format); + if (bytes.isEmpty()) { + auto buffer = QBuffer(&bytes); + image.save(&buffer, format); + } return ImageWithLocation{ .location = ImageLocation( DownloadLocation{ InMemoryLocation{ bytes } }, diff --git a/Telegram/SourceFiles/ui/image/image_location_factory.h b/Telegram/SourceFiles/ui/image/image_location_factory.h index 9e27cd4dc..035c19f33 100644 --- a/Telegram/SourceFiles/ui/image/image_location_factory.h +++ b/Telegram/SourceFiles/ui/image/image_location_factory.h @@ -41,7 +41,8 @@ namespace Images { const MTPVideoSize &size); [[nodiscard]] ImageWithLocation FromImageInMemory( const QImage &image, - const char *format); + const char *format, + QByteArray bytes = QByteArray()); [[nodiscard]] ImageLocation FromWebDocument(const MTPWebDocument &document); } // namespace Images diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index 164c683b8..5f8015059 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -462,7 +462,9 @@ SendMediaReady PrepareWallPaper(MTP::DcId dcId, const QImage &image) { MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(image.width()), MTP_int(image.height()), MTP_int(0))); - thumbnails.emplace(type[0], std::move(image)); + thumbnails.emplace( + type[0], + PreparedPhotoThumb{ .image = std::move(image) }); }; push("s", scaled(320)); diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp index 4afde74c4..4555575b0 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp @@ -426,15 +426,21 @@ SendMediaReady PrepareThemeMedia( thumbnail.save(&buffer, "JPG", 87); } - const auto push = [&](const char *type, QImage &&image) { + const auto push = [&]( + const char *type, + QImage &&image, + QByteArray bytes = QByteArray()) { sizes.push_back(MTP_photoSize( MTP_string(type), MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), MTP_int(image.width()), MTP_int(image.height()), MTP_int(0))); - thumbnails.emplace(type[0], std::move(image)); + thumbnails.emplace(type[0], PreparedPhotoThumb{ + .image = std::move(image), + .bytes = std::move(bytes) + }); }; - push("s", std::move(thumbnail)); + push("s", std::move(thumbnail), thumbnailBytes); const auto filename = base::FileNameFromUserString(name) + qsl(".tdesktop-theme");