Skip to content

Commit

Permalink
fix: Improve image load policy
Browse files Browse the repository at this point in the history
调整图像加载策略,缩略图以实际显示区域动态计算,
而非固定数据长度.
移除无关代码,修改一处创建线程未及时释放.

Log: 修复部分启动问题
Bug: https://pms.uniontech.com/bug-view-254143.html
  • Loading branch information
rb-union committed May 8, 2024
1 parent f162880 commit 414c1f2
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 46 deletions.
6 changes: 4 additions & 2 deletions libimageviewer/service/commonservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
#ifndef COMMONSERVICE_H
#define COMMONSERVICE_H

#include "image-viewer_global.h"

#include <QObject>
#include <QStandardPaths>
#include <QDir>
#include <QMap>
#include <QMutex>
#include "image-viewer_global.h"
#include <QSet>

class LibCommonService : public QObject
{
Expand All @@ -35,7 +37,7 @@ class LibCommonService : public QObject
public:
QStringList m_listAllPath;//全部需要加载的
QStringList m_noLoadingPath;//没有加载的地址
QStringList m_listLoaded;//已经加载的
QSet<QString> m_listLoaded;//已经加载的

signals:
void sigRightMousePress();
Expand Down
49 changes: 32 additions & 17 deletions libimageviewer/service/imagedataservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ LibImageDataService::~LibImageDataService()
bool LibImageDataService::add(const QStringList &paths)
{
QMutexLocker locker(&m_imgDataMutex);
// m_requestQueue.clear();
for (int i = 0; i < paths.size(); i++) {
if (!m_AllImageMap.contains(paths.at(i))) {
m_requestQueue.append(paths.at(i));
// FIXME: 虽然这样修改将后续的数据优先添加,但也会导致边缘变更单独更新的数据被优先读取,变成非中心加载而是偏向一侧加载。
// 反向添加,尾部数据在之后添加,QList两侧都有预留分配,非共享差异不大
std::for_each(paths.rbegin(), paths.rend(), [this](const QString &path){
if (!m_AllImageMap.contains(path)) {
m_requestQueue.prepend(path);
}
}
});

return true;
}

Expand All @@ -56,7 +58,8 @@ bool LibImageDataService::add(const QString &path)
QMutexLocker locker(&m_imgDataMutex);
if (!path.isEmpty()) {
if (!m_AllImageMap.contains(path)) {
m_requestQueue.append(path);
// 后添加的单一数据优先加载
m_requestQueue.prepend(path);
}
}
return true;
Expand All @@ -83,26 +86,38 @@ int LibImageDataService::getCount()
return m_AllImageMap.count();
}

bool LibImageDataService::readThumbnailByPaths(QString thumbnailPath, QStringList files, bool remake)
bool LibImageDataService::readThumbnailByPaths(const QString &thumbnailPath, const QStringList &files, bool remake)
{
qDebug() << "------------files.size = " << files.size();
Q_UNUSED(thumbnailPath)
Q_UNUSED(remake)

LibImageDataService::instance()->add(files);

int needCoreCounts = static_cast<int>(std::thread::hardware_concurrency());
needCoreCounts = needCoreCounts / 2;
if (files.size() < needCoreCounts) {
needCoreCounts = files.size();
int threadCounts = static_cast<int>(readThreadGroup.size());
// 调整占用线程数量
int recommendThreadCounts = QThread::idealThreadCount() / 2;
int needCoreCounts = qBound(1, files.size(), recommendThreadCounts);
int curActivateThreads = 0;

// 激活已有的线程
for (int i = 0; i < threadCounts && i < needCoreCounts; ++i) {
auto thread = readThreadGroup.at(static_cast<uint>(i));
if (!thread->isRunning()) {
thread->start();
curActivateThreads++;
}
}
if (needCoreCounts < 1)
needCoreCounts = 1;
for (int i = 0; i < needCoreCounts; i++) {

// 当前激活的线程不满足文件加载,且当前线程仍有余量,创建更多线程处理
int avaliableThreads = recommendThreadCounts - threadCounts;
int requesetThreads = needCoreCounts - curActivateThreads;
int addThreads = qMin(avaliableThreads, requesetThreads);
for (int i = 0; i < addThreads; ++i) {
LibReadThumbnailThread *thread = new LibReadThumbnailThread;
thread->m_thumbnailPath = thumbnailPath;
thread->m_remake = remake;
thread->start();
readThreadGroup.push_back(thread);
}

return true;
}

Expand Down
12 changes: 6 additions & 6 deletions libimageviewer/service/imagedataservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ class LibImageDataService: public QObject
int getCount();

//读取缩略图到缓存map
bool readThumbnailByPaths(QString thumbnailPath, QStringList files, bool remake);
// bool readThumbnailByPath(QString file);
bool readThumbnailByPaths(const QString &thumbnailPath, const QStringList &files, bool remake);

void addImage(const QString &path, const QImage &image);
QImage getThumnailImageByPath(const QString &path);
Expand Down Expand Up @@ -76,22 +75,23 @@ private slots:
class LibReadThumbnailThread : public QThread
{
Q_OBJECT

public:
LibReadThumbnailThread(QObject *parent = nullptr);
explicit LibReadThumbnailThread(QObject *parent = nullptr);
~LibReadThumbnailThread() override = default;
void readThumbnail(QString m_path);
void setQuit(bool quit);
QString m_thumbnailPath = "";
bool m_remake = false;

//判断图片类型
imageViewerSpace::ImageType getImageType(const QString &imagepath);
//判断路径类型
imageViewerSpace::PathType getPathType(const QString &imagepath);

protected:
void run() override;

private:
std::atomic_bool m_quit;

};

#endif // IMAGEDATASERVICE_H
24 changes: 24 additions & 0 deletions libimageviewer/viewpanel/contents/bottomtoolbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,9 @@ void LibBottomToolbar::resizeEvent(QResizeEvent *event)

emit sigResizeBottom();
m_imgListWidget->moveCenterWidget();

// 计算当前展示的Item数量是否变更
estimatedDisplayCount();
}

void LibBottomToolbar::showEvent(QShowEvent *event)
Expand Down Expand Up @@ -878,3 +881,24 @@ void LibBottomToolbar::setButtonVisible(imageViewerSpace::ButtonType id, bool vi
}
}
}

/**
@return 返回当前缩略图栏显示的item计数,计数 = (显示控件宽度 / 显示的 Item 宽度) + 1,
计数将至少为 1
*/
int LibBottomToolbar::estimatedDisplayCount()
{
int itemWidth = LibImgViewListView::ITEM_NORMAL_WIDTH + LibImgViewListView::ITEM_SPACING;
int estimate = ((m_imgListWidget->width() - LibImgViewListView::ITEM_CURRENT_WH) / itemWidth) + 1;
int curCount = qMax(1, estimate);

bool growup = curCount > m_estimateDisplayCount;
if (curCount != m_estimateDisplayCount) {
m_estimateDisplayCount = curCount;
}
if (growup) {
Q_EMIT displayItemGrowUp(m_estimateDisplayCount);
}

return curCount;
}
7 changes: 7 additions & 0 deletions libimageviewer/viewpanel/contents/bottomtoolbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ class LibBottomToolbar : public DFloatingWidget
//限于目前的代码结构,这个设置仅能在设置隐藏的时候立即生效
void setButtonVisible(imageViewerSpace::ButtonType id, bool visible);

// 当前在缩略图展示的item统计(模糊计算结果)
int estimatedDisplayCount();

signals:
void resetTransform(bool fitWindow);
void rotateClockwise();
Expand All @@ -114,6 +117,8 @@ class LibBottomToolbar : public DFloatingWidget

void sigResizeBottom();

// 当前展示的item增加
void displayItemGrowUp(int estimatedCount);

public slots:
void updateCollectButton();
Expand Down Expand Up @@ -178,6 +183,8 @@ public slots:
bool badaptScreenBtnChecked = false;
QString m_currentpath = "";
bool m_ocrIsExists = false;

int m_estimateDisplayCount = 0;
};

#endif // BOTTOMTOOBAR_H
1 change: 1 addition & 0 deletions libimageviewer/viewpanel/contents/imgviewwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class MyImageListWidget : public QWidget

//获得当前
int getCurrentCount();

signals:
void openImg(int index, QString path);
private:
Expand Down
59 changes: 38 additions & 21 deletions libimageviewer/viewpanel/viewpanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ void LibViewPanel::initConnect()
m_topToolbar->update();
});
#endif

// 展示的item增加时(拖拽、放大等),需要同步更新缩略图
connect(m_bottomToolbar, &LibBottomToolbar::displayItemGrowUp, this, [this](int){
loadThumbnails(m_currentPath);
});
}

void LibViewPanel::initTopBar()
Expand Down Expand Up @@ -1130,33 +1135,45 @@ void LibViewPanel::hideAnimationTopBottom()

void LibViewPanel::loadThumbnails(const QString &path)
{
// LibCommonService::instance()->m_listAllPath = pathList;
// LibCommonService::instance()->m_noLoadingPath = pathList;

int index = LibCommonService::instance()->m_listAllPath.indexOf(path);
int left = index;
int right = index;
if (index + 50 > LibCommonService::instance()->m_listAllPath.count()) {
right = LibCommonService::instance()->m_listAllPath.count();
} else {
right = index + 50;
}
if (index - 50 > 0) {
left = index - 50;
} else {
left = 0;
if (-1 == index) {
return;
}

// 默认的缩略图加载数量
static const int s_DefaultLoadThumbnails = 4;
// 通过当前显示的缩略图栏宽度计算待预加载的缩略图计数,适当调整宽度以预载部分未显示图片
int imageCount = LibCommonService::instance()->m_listAllPath.count();
int needLoadImages = qMax(m_bottomToolbar->estimatedDisplayCount() + 2, s_DefaultLoadThumbnails);
needLoadImages = qMin(needLoadImages, imageCount);

QStringList loadList;
for (int i = left; i < right; i++) {
QString loadPath = LibCommonService::instance()->m_listAllPath[i];
if (LibCommonService::instance()->m_listLoaded.indexOf(loadPath) < 0) {
loadList << loadPath;
LibCommonService::instance()->m_listLoaded << loadPath;
LibCommonService::instance()->m_noLoadingPath.removeOne(loadPath);
auto appendFunc = [&](const QString &addPath){
if (!LibCommonService::instance()->m_listLoaded.contains(addPath)) {
loadList.append(addPath);
LibCommonService::instance()->m_listLoaded.insert(addPath);
LibCommonService::instance()->m_noLoadingPath.removeOne(addPath);
}
};


// 从中间向两侧扩散追加,若一侧已全加载,则另一侧继续添加
int loadImageCount = 0;
int l = index;
int r = index + 1;
while (loadImageCount < needLoadImages) {
if (0 <= l) {
appendFunc(LibCommonService::instance()->m_listAllPath[l]);
loadImageCount++;
--l;
}
if (r < imageCount) {
appendFunc(LibCommonService::instance()->m_listAllPath[r]);
loadImageCount++;
++r;
}
}

// 异步加载数据
ImageEngine::instance()->makeImgThumbnail(LibCommonService::instance()->getImgSavePath(), loadList, loadList.size());
}

Expand Down

0 comments on commit 414c1f2

Please sign in to comment.