Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: image switching does not retain settings #184

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/qml/FullImageView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ Item {
id: imageViewer

anchors.fill: parent

onTargetImageChanged: {
delayAnimationTimer.start();
}
onTargetImageReadyChanged: {
delayAnimationTimer.start();
}
}

// 缩放变更时触发显示/隐藏标题栏/底部栏
Expand Down
84 changes: 70 additions & 14 deletions src/qml/ImageDelegate/BaseImageDelegate.qml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,10 @@ Item {
property int type: IV.Types.NullImage

function reset() {
if (targetImage.paintedWidth > 0) {
resetCache();
}
if (targetImage) {
// 匹配缩放处理,对于动图,首次加载传入的 paintedWidth 可能为0
if (targetImage.paintedWidth > 0 && imageInfo.width < targetImage.width && imageInfo.height < targetImage.height) {
targetImage.scale = imageInfo.width / targetImage.paintedWidth;
} else {
targetImage.scale = 1;
}
targetImage.rotation = 0;
}

Expand All @@ -54,9 +51,34 @@ Item {
}
}

function resetCache() {
if (inited || null === targetImage || undefined === targetImage) {
return;
}
if (targetImage.paintedWidth <= 0) {
return;
}

// 重置缩放
if (targetImageInfo.scale <= 0) {
// 匹配缩放处理,对于动图,首次加载传入的 paintedWidth 可能为 0
if (imageInfo.width < targetImage.width && imageInfo.height < targetImage.height) {
targetImage.scale = imageInfo.width / targetImage.paintedWidth;
} else {
targetImage.scale = 1;
}
targetImageInfo.scale = targetImage.scale;
} else {
targetImage.scale = targetImageInfo.scale;
}
targetImage.x = targetImageInfo.x;
targetImage.y = targetImageInfo.y;
inited = true;
}

function updateOffset() {
// 需要考虑缩放时的处理
var realWidth = targetImage.paintedWidth * targetImage.scale;
// 需要考虑缩放时的处理(cache中缓存缩放值时优先采用cache)
var realWidth = targetImage.paintedWidth * (targetImageInfo.scale <= 0 ? targetImageInfo.scale : targetImage.scale);
// 图片加载过程时,图片可能未加载完成,调整默认的缩放比值以获取近似值
if (realWidth <= 0) {
if (imageInfo.width < baseDelegate.width && imageInfo.height < baseDelegate.height) {
Expand Down Expand Up @@ -95,16 +117,34 @@ Item {
// 用于绘制更新后缩放等处理
function onPaintedWidthChanged() {
if (!inited) {
if (targetImage.paintedWidth > 0) {
inited = true;
}
reset();
}
updateOffset();
}

function onScaleChanged() {
updateOffset();

// 更新缓存状态
targetImageInfo.scale = targetImage.scale;
}

function onSourceChanged() {
inited = false;
}

function onStatusChanged() {
if (Image.Ready === targetImage.status) {
resetCache();
}
}

function onXChanged() {
targetImageInfo.x = targetImage.x;
}

function onYChanged() {
targetImageInfo.y = targetImage.y;
}

enabled: undefined !== targetImage
Expand All @@ -117,8 +157,9 @@ Item {

property bool needBlur: false

active: needBlur && Image.Loading === baseDelegate.status
anchors.fill: parent
active: needBlur && (Image.Loading === baseDelegate.status)
height: parent.height
width: parent.width
z: parent.z + 1

sourceComponent: Item {
Expand All @@ -127,11 +168,12 @@ Item {
Image {
id: loadImage

anchors.fill: parent
// cache会缓存数据(即便Loader重新加载),取消此设置以正确在快速旋转/切换时从正确缓存管理中读取
cache: false
fillMode: Image.PreserveAspectFit
height: parent.height
source: "image://ThumbnailLoad/" + delegate.source + "#frame_" + delegate.frameIndex
width: parent.width
}

MultiEffect {
Expand All @@ -144,6 +186,15 @@ Item {
}
}

onActiveChanged: {
if (active) {
// 应用缓存的图像设置
scale = targetImageInfo.scale <= 0 ? 1 : targetImageInfo.scale;
x = targetImageInfo.x;
y = targetImageInfo.y;
}
}

// 短时间完成加载的图片内无需模糊延迟效果
Timer {
interval: 20
Expand All @@ -158,6 +209,11 @@ Item {
IV.ImageInfo {
id: imageInfo

frameIndex: baseDelegate.frameIndex
source: baseDelegate.source

onInfoChanged: {
inited = false;
}
}
}
8 changes: 6 additions & 2 deletions src/qml/ImageDelegate/NormalImageDelegate.qml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ BaseImageDelegate {
}

function updateSource() {
// 由于会 resetSource() 破坏绑定,因此重新设置源数据
image.source = "image://ImageLoad/" + delegate.source + "#frame_" + delegate.frameIndex;
if (delegate.source != "") {
// 由于会 resetSource() 破坏绑定,因此重新设置源数据
image.source = "image://ImageLoad/" + delegate.source + "#frame_" + delegate.frameIndex;
} else {
image.source = "";
}
}

inputHandler: imageInput
Expand Down
3 changes: 0 additions & 3 deletions src/qml/ImageViewer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ import "./Utils"
Item {
id: imageViewer

// current rotate
property int currentRotate: 0

// 记录图像缩放,用于在窗口缩放时,根据前后窗口变化保持图片缩放比例
property bool enableChangeDisplay: true
property real lastDisplayScaleWidth: 0
Expand Down
3 changes: 3 additions & 0 deletions src/qml/ThumbnailListView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ Control {
onFinished: {
if (ret) {
thumbnailView.deleteCurrentImageImpl(true);
} else {
// 取消删除,恢复删除按钮状态
thumbnailView.imageDeleting = false;
}
// 使用后释放对话框
removeDialogLoader.active = false;
Expand Down
54 changes: 52 additions & 2 deletions src/src/imagedata/imageinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
other->size = this->size;
other->frameIndex = this->frameIndex;
other->frameCount = this->frameCount;

other->scale = this->scale;
other->x = this->x;
other->y = this->y;

return other;
}
Expand All @@ -41,6 +45,11 @@
int frameIndex = 0; ///< 当前图片帧号
int frameCount = 0; ///< 当前图片总帧数
bool exist = false; ///< 图片是否存在

// runtime property
qreal scale = -1; ///< 图片缩放比值
qreal x = 0; ///< 相对坐标X轴偏移
qreal y = 0; ///< 相对坐标Y轴偏移
};

class LoadImageInfoRunnable : public QRunnable
Expand All @@ -63,7 +72,7 @@
typedef QPair<QString, int> KeyType;

ImageInfoCache();
~ImageInfoCache();
~ImageInfoCache() override;

ImageInfoData::Ptr find(const QString &path, int frameIndex);
void load(const QString &path, int frameIndex, bool reload = false);
Expand Down Expand Up @@ -212,7 +221,7 @@
localPoolPtr->setMaxThreadCount(qMax(2, QThread::idealThreadCount() / 2));

// 退出时清理线程状态
connect(qApp, &QCoreApplication::aboutToQuit, this, [this](){
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
aboutToQuit = true;
clearCache();

Expand Down Expand Up @@ -315,6 +324,7 @@
ImageInfo::ImageInfo(QObject *parent)
: QObject(parent)
{
// TODO(renbin): 这种方式效率不佳,应调整为记录文件对应的 ImageInfo 对象进行直接调用(均在同一线程)
connect(CacheInstance(), &ImageInfoCache::imageDataChanged, this, &ImageInfo::onLoadFinished);
connect(CacheInstance(), &ImageInfoCache::imageSizeChanged, this, &ImageInfo::onSizeChanged);
}
Expand Down Expand Up @@ -425,6 +435,46 @@
return data ? data->frameCount : 1;
}

/**
@brief 设置图片运行时属性缩放为 \a s ,除缩放外,还有图片组件在界面上的偏移值 x y 。
这些属性不会用于状态的实时同步或抛出信号,仅在初始化图片展示时取缓存数据复位状态。
*/
void ImageInfo::setScale(qreal s)

Check warning on line 442 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'setScale' is never used.

Check warning on line 442 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / static-check / Call-CppCheck

The function 'setScale' is never used.
{
if (data && data->scale != s) {
data->scale = s;
}
}

qreal ImageInfo::scale() const
{
return data ? data->scale : -1;
}

void ImageInfo::setX(qreal x)

Check warning on line 454 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'setX' is never used.

Check warning on line 454 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / static-check / Call-CppCheck

The function 'setX' is never used.
{
if (data) {
data->x = x;
}
}

qreal ImageInfo::x() const
{
return data ? data->x : 0;
}

void ImageInfo::setY(qreal y)

Check warning on line 466 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'setY' is never used.

Check warning on line 466 in src/src/imagedata/imageinfo.cpp

View workflow job for this annotation

GitHub Actions / static-check / Call-CppCheck

The function 'setY' is never used.
{
if (data) {
data->y = y;
}
}

qreal ImageInfo::y() const
{
return data ? data->y : 0;
}

/**
@return 返回当前图片是否存在,图片可能在展示过程中被销毁
*/
Expand Down
13 changes: 13 additions & 0 deletions src/src/imagedata/imageinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class ImageInfo : public QObject
Q_PROPERTY(bool exists READ exists NOTIFY existsChanged)
Q_PROPERTY(bool hasCachedThumbnail READ hasCachedThumbnail)

// runtime properties
Q_PROPERTY(qreal scale READ scale WRITE setScale FINAL)
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
Q_PROPERTY(qreal y READ y WRITE setY FINAL)

public:
explicit ImageInfo(QObject *parent = nullptr);
explicit ImageInfo(const QUrl &source, QObject *parent = nullptr);
Expand Down Expand Up @@ -52,6 +57,14 @@ class ImageInfo : public QObject
int frameCount() const;
Q_SIGNAL void frameCountChanged();

// runtime properties: scale x y
void setScale(qreal s);
qreal scale() const;
void setX(qreal x);
qreal x() const;
void setY(qreal y);
qreal y() const;

bool exists() const;
Q_SIGNAL void existsChanged();
bool hasCachedThumbnail() const;
Expand Down
8 changes: 4 additions & 4 deletions src/src/utils/rotateimagehelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ bool RotateImageHelper::rotateImageImpl(const QString &cachePath, const QString

// NOTE:处理结束,过滤旋转操作文件更新,旋转图像已在软件中缓存且旋转状态同步,不再从文件中更新读取
// 保存文件后发送图片更新更新信号,通过监控文件变更触发。文件更新可能滞后,延时一定时间处理
QTimer::singleShot(10, [ret, path]() {
Q_EMIT RotateImageHelper::instance()->clearRotateStatus(path);
Q_EMIT RotateImageHelper::instance()->rotateImageFinished(path, ret);
});
// 处于子线程中,慎用事件循环(没有初始化)
QThread::msleep(10);
Q_EMIT RotateImageHelper::instance()->clearRotateStatus(path);
Q_EMIT RotateImageHelper::instance()->rotateImageFinished(path, ret);

if (!ret) {
qWarning() << QString("Rotate image file failed!, error: %1").arg(errorMsg);
Expand Down
Loading