mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Save original bytes of a photo on "Save to disk".
This commit is contained in:
parent
c39f15bd71
commit
7718764294
8 changed files with 80 additions and 29 deletions
|
@ -64,7 +64,7 @@ void CloudImage::set(
|
|||
session->data().cache(),
|
||||
kImageCacheTag,
|
||||
[=](FileOrigin origin) { load(session, origin); },
|
||||
[=](QImage preloaded) {
|
||||
[=](QImage preloaded, QByteArray) {
|
||||
if (const auto view = activeView()) {
|
||||
view->set(session, data.preloaded);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ void CloudImage::update(
|
|||
session->data().cache(),
|
||||
kImageCacheTag,
|
||||
[=](FileOrigin origin) { load(session, origin); },
|
||||
[=](QImage preloaded) {
|
||||
[=](QImage preloaded, QByteArray) {
|
||||
if (const auto view = activeView()) {
|
||||
view->set(session, data.preloaded);
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ void CloudImage::load(not_null<Main::Session*> session, FileOrigin origin) {
|
|||
}
|
||||
return !(_file.flags & CloudFile::Flag::Loaded);
|
||||
};
|
||||
const auto done = [=](QImage result) {
|
||||
const auto done = [=](QImage result, QByteArray) {
|
||||
if (const auto active = activeView()) {
|
||||
active->set(session, std::move(result));
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ void UpdateCloudFile(
|
|||
Storage::Cache::Database &cache,
|
||||
uint8 cacheTag,
|
||||
Fn<void(FileOrigin)> restartLoader,
|
||||
Fn<void(QImage)> usePreloaded) {
|
||||
Fn<void(QImage, QByteArray)> usePreloaded) {
|
||||
if (!data.location.valid()) {
|
||||
if (data.progressivePartSize && !file.location.valid()) {
|
||||
file.progressivePartSize = data.progressivePartSize;
|
||||
|
@ -213,7 +213,7 @@ void UpdateCloudFile(
|
|||
if (!data.preloaded.isNull()) {
|
||||
file.loader = nullptr;
|
||||
if (usePreloaded) {
|
||||
usePreloaded(data.preloaded);
|
||||
usePreloaded(data.preloaded, data.bytes);
|
||||
}
|
||||
} else if (file.loader) {
|
||||
const auto origin = base::take(file.loader)->fileOrigin();
|
||||
|
@ -307,7 +307,7 @@ void LoadCloudFile(
|
|||
bool autoLoading,
|
||||
uint8 cacheTag,
|
||||
Fn<bool()> finalCheck,
|
||||
Fn<void(QImage)> done,
|
||||
Fn<void(QImage, QByteArray)> done,
|
||||
Fn<void(bool)> fail,
|
||||
Fn<void()> progress,
|
||||
int downloadFrontPartSize) {
|
||||
|
@ -318,7 +318,7 @@ void LoadCloudFile(
|
|||
onstack(true);
|
||||
}
|
||||
} else if (const auto onstack = done) {
|
||||
onstack(std::move(read));
|
||||
onstack(std::move(read), file.loader->bytes());
|
||||
}
|
||||
};
|
||||
LoadCloudFile(
|
||||
|
|
|
@ -96,7 +96,7 @@ void UpdateCloudFile(
|
|||
Storage::Cache::Database &cache,
|
||||
uint8 cacheTag,
|
||||
Fn<void(FileOrigin)> restartLoader,
|
||||
Fn<void(QImage)> usePreloaded = nullptr);
|
||||
Fn<void(QImage, QByteArray)> usePreloaded = nullptr);
|
||||
|
||||
void LoadCloudFile(
|
||||
not_null<Main::Session*> session,
|
||||
|
@ -106,7 +106,7 @@ void LoadCloudFile(
|
|||
bool autoLoading,
|
||||
uint8 cacheTag,
|
||||
Fn<bool()> finalCheck,
|
||||
Fn<void(QImage)> done,
|
||||
Fn<void(QImage, QByteArray)> done,
|
||||
Fn<void(bool)> fail = nullptr,
|
||||
Fn<void()> progress = nullptr,
|
||||
int downloadFrontPartSize = 0);
|
||||
|
|
|
@ -480,7 +480,7 @@ void DocumentData::updateThumbnails(
|
|||
owner().cache(),
|
||||
Data::kImageCacheTag,
|
||||
[&](Data::FileOrigin origin) { loadThumbnail(origin); },
|
||||
[&](QImage preloaded) {
|
||||
[&](QImage preloaded, QByteArray) {
|
||||
if (const auto media = activeMediaView()) {
|
||||
media->setThumbnail(std::move(preloaded));
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ void DocumentData::loadThumbnail(Data::FileOrigin origin) {
|
|||
}
|
||||
return true;
|
||||
};
|
||||
const auto done = [=](QImage result) {
|
||||
const auto done = [=](QImage result, QByteArray) {
|
||||
if (const auto active = activeMediaView()) {
|
||||
active->setThumbnail(std::move(result));
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ void PhotoData::load(
|
|||
}
|
||||
return true;
|
||||
};
|
||||
const auto done = [=](QImage result) {
|
||||
const auto done = [=](QImage result, QByteArray bytes) {
|
||||
Expects(_images[valid].loader != nullptr);
|
||||
|
||||
// Find out what progressive photo size have we loaded exactly.
|
||||
|
@ -316,7 +316,8 @@ void PhotoData::load(
|
|||
active->set(
|
||||
validSize,
|
||||
goodFor,
|
||||
ValidatePhotoImage(std::move(result), _images[valid]));
|
||||
ValidatePhotoImage(std::move(result), _images[valid]),
|
||||
std::move(bytes));
|
||||
}
|
||||
if (validSize == PhotoSize::Large && goodFor == validSize) {
|
||||
_owner->photoLoadDone(this);
|
||||
|
@ -382,14 +383,15 @@ void PhotoData::updateImages(
|
|||
owner().cache(),
|
||||
Data::kImageCacheTag,
|
||||
[=](Data::FileOrigin origin) { load(size, origin); },
|
||||
[=](QImage preloaded) {
|
||||
[=](QImage preloaded, QByteArray bytes) {
|
||||
if (const auto media = activeMediaView()) {
|
||||
media->set(
|
||||
size,
|
||||
size,
|
||||
ValidatePhotoImage(
|
||||
std::move(preloaded),
|
||||
_images[index]));
|
||||
_images[index]),
|
||||
std::move(bytes));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -49,16 +49,31 @@ Image *PhotoMedia::thumbnailInline() const {
|
|||
}
|
||||
|
||||
Image *PhotoMedia::image(PhotoSize size) const {
|
||||
if (const auto resolved = resolveLoadedImage(size)) {
|
||||
return resolved->data.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QByteArray PhotoMedia::imageBytes(PhotoSize size) const {
|
||||
if (const auto resolved = resolveLoadedImage(size)) {
|
||||
return resolved->bytes;
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
auto PhotoMedia::resolveLoadedImage(PhotoSize size) const
|
||||
-> const PhotoImage * {
|
||||
const auto &original = _images[PhotoSizeIndex(size)];
|
||||
if (const auto image = original.data.get()) {
|
||||
if (original.goodFor >= size) {
|
||||
return image;
|
||||
return &original;
|
||||
}
|
||||
}
|
||||
const auto &valid = _images[_owner->validSizeIndex(size)];
|
||||
if (const auto image = valid.data.get()) {
|
||||
if (valid.goodFor >= size) {
|
||||
return image;
|
||||
return &valid;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -80,7 +95,11 @@ QSize PhotoMedia::size(PhotoSize size) const {
|
|||
return { location.width(), location.height() };
|
||||
}
|
||||
|
||||
void PhotoMedia::set(PhotoSize size, PhotoSize goodFor, QImage image) {
|
||||
void PhotoMedia::set(
|
||||
PhotoSize size,
|
||||
PhotoSize goodFor,
|
||||
QImage image,
|
||||
QByteArray bytes) {
|
||||
const auto index = PhotoSizeIndex(size);
|
||||
const auto limit = PhotoData::SideLimit();
|
||||
if (image.width() > limit || image.height() > limit) {
|
||||
|
@ -92,6 +111,7 @@ void PhotoMedia::set(PhotoSize size, PhotoSize goodFor, QImage image) {
|
|||
}
|
||||
_images[index] = PhotoImage{
|
||||
.data = std::make_unique<Image>(std::move(image)),
|
||||
.bytes = std::move(bytes),
|
||||
.goodFor = goodFor,
|
||||
};
|
||||
_owner->session().notifyDownloaderTaskFinished();
|
||||
|
|
|
@ -24,9 +24,14 @@ public:
|
|||
[[nodiscard]] Image *thumbnailInline() const;
|
||||
|
||||
[[nodiscard]] Image *image(PhotoSize size) const;
|
||||
[[nodiscard]] QByteArray imageBytes(PhotoSize size) const;
|
||||
[[nodiscard]] QSize size(PhotoSize size) const;
|
||||
void wanted(PhotoSize size, Data::FileOrigin origin);
|
||||
void set(PhotoSize size, PhotoSize goodFor, QImage image);
|
||||
void set(
|
||||
PhotoSize size,
|
||||
PhotoSize goodFor,
|
||||
QImage image,
|
||||
QByteArray bytes);
|
||||
|
||||
[[nodiscard]] QByteArray videoContent() const;
|
||||
[[nodiscard]] QSize videoSize() const;
|
||||
|
@ -45,9 +50,12 @@ public:
|
|||
private:
|
||||
struct PhotoImage {
|
||||
std::unique_ptr<Image> data;
|
||||
QByteArray bytes;
|
||||
PhotoSize goodFor = PhotoSize();
|
||||
};
|
||||
|
||||
const PhotoImage *resolveLoadedImage(PhotoSize size) const;
|
||||
|
||||
// NB! Right now DocumentMedia can outlive Main::Session!
|
||||
// In DocumentData::collectLocalData a shared_ptr is sent on_main.
|
||||
// In case this is a problem the ~Gif code should be rewritten.
|
||||
|
|
|
@ -1605,9 +1605,12 @@ void OverlayWidget::saveAs() {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto image = _photoMedia->image(Data::PhotoSize::Large)->original();
|
||||
const auto image = _photoMedia->image(
|
||||
Data::PhotoSize::Large)->original();
|
||||
const auto bytes = _photoMedia->imageBytes(Data::PhotoSize::Large);
|
||||
const auto photo = _photo;
|
||||
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
|
||||
const auto filter = qsl("JPEG Image (*.jpg);;")
|
||||
+ FileDialog::AllFilesFilter();
|
||||
FileDialog::GetWritePath(
|
||||
_widget.get(),
|
||||
tr::lng_save_photo(tr::now),
|
||||
|
@ -1620,7 +1623,7 @@ void OverlayWidget::saveAs() {
|
|||
_photo->date),
|
||||
crl::guard(_widget, [=](const QString &result) {
|
||||
if (!result.isEmpty() && _photo == photo) {
|
||||
image.save(result, "JPG");
|
||||
saveToFile(result, bytes, image);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -1691,9 +1694,7 @@ void OverlayWidget::downloadMedia() {
|
|||
QDir().mkpath(path);
|
||||
}
|
||||
toName = filedialogDefaultName(qsl("photo"), qsl(".mp4"), path);
|
||||
QFile f(toName);
|
||||
if (!f.open(QIODevice::WriteOnly)
|
||||
|| f.write(bytes) != bytes.size()) {
|
||||
if (!saveToFile(toName, bytes, QImage())) {
|
||||
toName = QString();
|
||||
}
|
||||
} else {
|
||||
|
@ -1705,14 +1706,15 @@ void OverlayWidget::downloadMedia() {
|
|||
_saveVisible = contentCanBeSaved();
|
||||
update(_saveNav);
|
||||
} else {
|
||||
const auto image = _photoMedia->image(
|
||||
Data::PhotoSize::Large)->original();
|
||||
|
||||
if (!QDir().exists(path)) {
|
||||
QDir().mkpath(path);
|
||||
}
|
||||
toName = filedialogDefaultName(qsl("photo"), qsl(".jpg"), path);
|
||||
if (!image.save(toName, "JPG")) {
|
||||
const auto saved = saveToFile(
|
||||
toName,
|
||||
_photoMedia->imageBytes(Data::PhotoSize::Large),
|
||||
_photoMedia->image(Data::PhotoSize::Large)->original());
|
||||
if (!saved) {
|
||||
toName = QString();
|
||||
}
|
||||
}
|
||||
|
@ -1725,6 +1727,20 @@ void OverlayWidget::downloadMedia() {
|
|||
}
|
||||
}
|
||||
|
||||
bool OverlayWidget::saveToFile(
|
||||
const QString &path,
|
||||
const QByteArray &bytes,
|
||||
const QImage &fallback) {
|
||||
if (!bytes.isEmpty()) {
|
||||
QFile f(path);
|
||||
return f.open(QIODevice::WriteOnly)
|
||||
&& (f.write(bytes) == bytes.size());
|
||||
} else if (!fallback.isNull()) {
|
||||
return fallback.save(path, "JPG");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OverlayWidget::saveCancel() {
|
||||
if (_document && _document->loading()) {
|
||||
_document->cancel();
|
||||
|
|
|
@ -417,6 +417,11 @@ private:
|
|||
|
||||
void applyHideWindowWorkaround();
|
||||
|
||||
bool saveToFile(
|
||||
const QString &path,
|
||||
const QByteArray &bytes,
|
||||
const QImage &fallback);
|
||||
|
||||
Window::SessionController *findWindow(bool switchTo = true) const;
|
||||
|
||||
bool _opengl = false;
|
||||
|
|
Loading…
Add table
Reference in a new issue