From 6a1830621e31b4e5ace3cc1a73bf286ef338daac Mon Sep 17 00:00:00 2001 From: renbin Date: Thu, 14 Dec 2023 16:30:18 +0800 Subject: [PATCH] feat: Not reset enhance image after save. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 调整AI修图交互. 保存图片后不再自动恢复原图; AI增强图片覆盖原图后,后续以覆盖图片为基版; 已保存图片切换后不弹出保存提示框. Log: 调整AI修图交互 Change-Id: I543182b85875a1a954cb269a7eb6e8036c09efa4 --- libimageviewer/service/aimodelservice.cpp | 58 +++++++++++++++++------ libimageviewer/service/aimodelservice.h | 9 ++-- libimageviewer/service/aimodelservice_p.h | 12 ++++- libimageviewer/viewpanel/viewpanel.cpp | 11 ++--- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/libimageviewer/service/aimodelservice.cpp b/libimageviewer/service/aimodelservice.cpp index d6330093..d4181693 100644 --- a/libimageviewer/service/aimodelservice.cpp +++ b/libimageviewer/service/aimodelservice.cpp @@ -480,13 +480,26 @@ bool AIModelService::isWaitSave() const return dptr->waitSave; } +/** + @return 返回当前增强图片(若为)是否需要保存,已保存和非增强图片返回 false . + */ +bool AIModelService::imageNeedSave(const QString &filePath) const +{ + auto ptr = dptr->enhanceCache.value(filePath); + if (!ptr.isNull()) { + return !ptr->saved; + } + + return false; +} + /** @brief 弹出对话框提示是否保存当前文件 \a filePath */ -void AIModelService::saveFileDialog(const QString &filePath, QWidget *target) +bool AIModelService::saveFileDialog(const QString &filePath, QWidget *target) { if (isWaitSave()) { - return; + return false; } dptr->waitSave = true; @@ -504,37 +517,39 @@ void AIModelService::saveFileDialog(const QString &filePath, QWidget *target) } }); + bool saveSucc = false; int ret = expiredDialog.exec(); if (ret == suggestRet) { - saveEnhanceFileAs(filePath, target); + saveSucc = saveEnhanceFileAs(filePath, target); } dptr->waitSave = false; + return saveSucc; } /** @brief 保存增强后的图像 \a filePath , 如果非图像增强文件则不进行保存 */ -void AIModelService::saveEnhanceFile(const QString &filePath) +bool AIModelService::saveEnhanceFile(const QString &filePath) { if (!isTemporaryFile(filePath)) { - return; + return false; } // 覆盖原文件 - saveFile(filePath, sourceFilePath(filePath)); + return saveFile(filePath, sourceFilePath(filePath)); } /** @brief 另存增强后的图像 \a filePath , 如果非图像增强文件则不进行保存 */ -void AIModelService::saveEnhanceFileAs(const QString &filePath, QWidget *target) +bool AIModelService::saveEnhanceFileAs(const QString &filePath, QWidget *target) { if (!isTemporaryFile(filePath)) { - return; + return false; } - saveTemporaryAs(filePath, sourceFilePath(filePath), target); + return saveTemporaryAs(filePath, sourceFilePath(filePath), target); } /** @@ -640,6 +655,7 @@ void AIModelService::showWarningDialog(const QString ¬ify, QWidget *target) /** @brief 保存文件 \a filePath 到 \a newPath , 默认覆盖 \a newPath 存在文件时无效, 需要先移除旧文件。 + 通过此处保存的图像增强文件会被设置为已保存状态。 */ bool AIModelService::saveFile(const QString &filePath, const QString &newPath) { @@ -655,6 +671,11 @@ bool AIModelService::saveFile(const QString &filePath, const QString &newPath) bool ret = QFile::copy(filePath, newPath); if (!ret) { qWarning() << QString("Copy temporary file %1 failed").arg(filePath); + } else { + auto ptr = dptr->enhanceCache.value(filePath); + if (!ptr.isNull()) { + ptr->saved = true; + } } return ret; @@ -663,8 +684,9 @@ bool AIModelService::saveFile(const QString &filePath, const QString &newPath) /** @brief 弹出保存框将 \a filePath 保存,建议目录为源文件目录 \a sourcePath */ -void AIModelService::saveTemporaryAs(const QString &filePath, const QString &sourcePath, QWidget *target) +bool AIModelService::saveTemporaryAs(const QString &filePath, const QString &sourcePath, QWidget *target) { + bool saveSucc = false; // 保存文件路径异常会尝试重试 bool retry = false; do { @@ -687,7 +709,7 @@ void AIModelService::saveTemporaryAs(const QString &filePath, const QString &sou if (QDialog::Accepted == mode) { auto files = dialog.selectedFiles(); if (files.isEmpty()) { - return; + return false; } QString newPath = files.value(0); @@ -698,9 +720,11 @@ void AIModelService::saveTemporaryAs(const QString &filePath, const QString &sou continue; } - saveFile(filePath, newPath); + saveSucc = saveFile(filePath, newPath); } } while (retry); + + return saveSucc; } /** @@ -710,9 +734,15 @@ void AIModelService::saveTemporaryAs(const QString &filePath, const QString &sou QString AIModelService::checkConvertFile(const QString &filePath, const QImage &image) const { // 判断图片变更 + QFileInfo info(filePath); QMutexLocker _locker(&dptr->cacheMutex); if (dptr->convertCache.contains(filePath)) { - return dptr->convertCache.value(filePath); + auto &sourceCache = dptr->convertCache[filePath]; + + // 判断文件是否变更(根据修改时间) + if (info.lastModified() == sourceCache.lastModified) { + return dptr->convertCache.value(filePath).cachedImage; + } } if (image.isNull()) { @@ -728,7 +758,7 @@ QString AIModelService::checkConvertFile(const QString &filePath, const QImage & } _locker.relock(); - dptr->convertCache.insert(filePath, cvtFile); + dptr->convertCache.insert(filePath, {info.lastModified(), cvtFile}); return cvtFile; } diff --git a/libimageviewer/service/aimodelservice.h b/libimageviewer/service/aimodelservice.h index 907b53a1..c44b6349 100644 --- a/libimageviewer/service/aimodelservice.h +++ b/libimageviewer/service/aimodelservice.h @@ -41,9 +41,10 @@ class AIModelService : public QObject QString lastProcOutput() const; bool isWaitSave() const; - void saveFileDialog(const QString &filePath, QWidget *target = nullptr); - void saveEnhanceFile(const QString &filePath); - void saveEnhanceFileAs(const QString &filePath, QWidget *target = nullptr); + bool imageNeedSave(const QString &filePath) const; + bool saveFileDialog(const QString &filePath, QWidget *target = nullptr); + bool saveEnhanceFile(const QString &filePath); + bool saveEnhanceFileAs(const QString &filePath, QWidget *target = nullptr); bool detectErrorAndNotify(QWidget *targetWidget, Error error, const QString &output = QString::null); @@ -60,7 +61,7 @@ class AIModelService : public QObject bool checkFileSavable(const QString &newPath, QWidget *target = nullptr); void showWarningDialog(const QString ¬ify, QWidget *target = nullptr); bool saveFile(const QString &filePath, const QString &newPath); - void saveTemporaryAs(const QString &filePath, const QString &sourcePath, QWidget *target = nullptr); + bool saveTemporaryAs(const QString &filePath, const QString &sourcePath, QWidget *target = nullptr); QString checkConvertFile(const QString &filePath, const QImage &image) const; // DBus diff --git a/libimageviewer/service/aimodelservice_p.h b/libimageviewer/service/aimodelservice_p.h index ba06451b..04041b20 100644 --- a/libimageviewer/service/aimodelservice_p.h +++ b/libimageviewer/service/aimodelservice_p.h @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -37,7 +38,9 @@ struct EnhanceInfo const QString output; const QString model; int index = 0; + bool saved = false; // 当前增强图片是否已保存 + // 线程争用 QAtomicInt state = AIModelService::None; // 处理状态,可能有争用 EnhanceInfo(const QString &s, const QString &o, const QString &m) @@ -93,8 +96,13 @@ class AIModelServiceData QHash enhanceCache; // 图像增强缓存信息(仅主线程访问) QMutex cacheMutex; - QTemporaryDir convertTemp; // 图像类型转换文件临时目录 - QHash convertCache; // 缓存的信息,可能多个线程访问 + QTemporaryDir convertTemp; // 图像类型转换文件临时目录 + struct SourceCache + { + QDateTime lastModified; // 文件最后修改时间 + QString cachedImage; // 文件缓存路径 + }; + QHash convertCache; // 缓存的信息,可能多个线程访问 QFutureWatcher enhanceWatcher; diff --git a/libimageviewer/viewpanel/viewpanel.cpp b/libimageviewer/viewpanel/viewpanel.cpp index 9dc90904..9c123034 100644 --- a/libimageviewer/viewpanel/viewpanel.cpp +++ b/libimageviewer/viewpanel/viewpanel.cpp @@ -1669,8 +1669,8 @@ void LibViewPanel::onMenuItemClicked(QAction *action) m_bottomToolbar->setVisible(false); } - // 判断当前是否为AI增强图片,若为则设置为提示是否保存 - if (AIModelService::instance()->isTemporaryFile(m_currentPath) + // 判断当前AI增强图片是否需要保存,若为则提示是否保存 + if (AIModelService::instance()->imageNeedSave(m_currentPath) && !AIModelService::instance()->isWaitSave()) { AIModelService::instance()->saveFileDialog(m_currentPath, this); resetAIEnhanceImage(); @@ -1987,8 +1987,8 @@ void LibViewPanel::resetBottomToolbarGeometry(bool visible) void LibViewPanel::openImg(int index, QString path) { if (AIModelService::instance()->isValid()) { - // 判断当前图片是否为图像增强图片 - bool previousEnhanced = AIModelService::instance()->isTemporaryFile(m_currentPath); + // 判断当前AI增强图片是否需要保存 + bool previousEnhanced = AIModelService::instance()->imageNeedSave(m_currentPath); if (previousEnhanced) { if (AIModelService::instance()->isWaitSave()) { return; @@ -2265,11 +2265,10 @@ void LibViewPanel::createAIBtn() connect(m_AIFloatBar, &AIEnhanceFloatWidget::reset, this, &LibViewPanel::resetAIEnhanceImage); connect(m_AIFloatBar, &AIEnhanceFloatWidget::save, this, [this](){ AIModelService::instance()->saveEnhanceFile(m_currentPath); - resetAIEnhanceImage(); }); connect(m_AIFloatBar, &AIEnhanceFloatWidget::saveAs, this, [this](){ AIModelService::instance()->saveEnhanceFileAs(m_currentPath, this); - resetAIEnhanceImage(); + // 保存文件后不再主动退出当前图片 }); } }