Skip to content

Commit 378e466

Browse files
committed
fix(wallpapercache): use QImageReader scaled decoding to avoid OOM on large images
1. Replace QImage::load() with QImageReader in pixmix effect processing, cap decoded resolution at 8K (7680px) to prevent excessive memory usage 2. Use QImageReader::setScaledSize() for scaleImage thread so decoding outputs directly at target size instead of full-size then downscale 3. Use QImageReader::imageFormat() static method for format detection to avoid instantiating a full reader when only the format is needed 4. Add proper error handling with canRead/isEmpty checks and error strings Log: Optimize wallpaper image decoding to use scaled reading and prevent OOM on large images fix(wallpapercache): 使用 QImageReader 缩放解码避免大图内存溢出 1. 将 pixmix 特效处理中的 QImage::load() 替换为 QImageReader, 限制解码分辨率上限为 8K (7680px),防止内存占用过大 2. 缩放线程使用 QImageReader::setScaledSize() 在解码时直接输出目标尺寸, 避免先全尺寸加载再缩放带来的额外内存开销 3. 格式检测改用 QImageReader::imageFormat() 静态方法, 避免实例化完整 reader 造成不必要的图片加载 4. 增加完善的错误检查,包含 canRead/isEmpty 校验及错误信息输出 Log: 优化壁纸图片解码流程,采用缩放读取方式防止超大图片导致内存溢出 PMS: BUG-359341
1 parent b0c5491 commit 378e466

3 files changed

Lines changed: 53 additions & 18 deletions

File tree

src/plugin-qt/wallpapercache/imageeffectprocessor.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define PIXMIX_OPACITY 90 // Color opacity
1818
#define PIXMIX_SATURATION 50 // Saturation
1919
#define PIXMIX_BRIGHTNESS -60 // Brightness
20+
#define PIXMIX_MAX_DIM 7680 // 8K UHD long side cap
2021

2122
DGUI_USE_NAMESPACE
2223

@@ -67,9 +68,25 @@ ImageEffectProcessor::EffectType ImageEffectProcessor::effectTypeFromString(cons
6768

6869
QImage ImageEffectProcessor::processPixmixEffect(const QString &imagePath)
6970
{
70-
QImage originalImage;
71-
if (!originalImage.load(imagePath)) {
72-
qWarning() << "Failed to load image:" << imagePath;
71+
QImageReader reader(imagePath);
72+
if (!reader.canRead()) {
73+
qWarning() << "Cannot read image:" << imagePath;
74+
return QImage();
75+
}
76+
77+
QSize originalSize = reader.size();
78+
if (!originalSize.isEmpty()
79+
&& (originalSize.width() > PIXMIX_MAX_DIM || originalSize.height() > PIXMIX_MAX_DIM)) {
80+
QSize decodeSize = originalSize;
81+
decodeSize.scale(PIXMIX_MAX_DIM, PIXMIX_MAX_DIM, Qt::KeepAspectRatio);
82+
reader.setScaledSize(decodeSize);
83+
qDebug() << "Decoding image at" << decodeSize
84+
<< "(original:" << originalSize << ")";
85+
}
86+
87+
QImage originalImage = reader.read();
88+
if (originalImage.isNull()) {
89+
qWarning() << "Failed to load image:" << imagePath << reader.errorString();
7390
return QImage();
7491
}
7592

src/plugin-qt/wallpapercache/scaleimagethread.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <QDateTime>
1111
#include <QCoreApplication>
1212
#include <QCryptographicHash>
13+
#include <QImageReader>
1314

1415
ScaleImageThread::ScaleImageThread(QObject *parent)
1516
: QThread(parent)
@@ -142,21 +143,34 @@ void ScaleImageThread::executeTask(const TaskData &task)
142143
QImage ScaleImageThread::scaleImage(const TaskData &task)
143144
{
144145
qDebug() << "scale image info:" << task.originalPath << " targetSize:" << task.targetSize;
145-
QImage image;
146-
image.load(task.originalPath);
146+
147+
QImageReader reader(task.originalPath);
148+
if (!reader.canRead()) {
149+
qWarning() << "Cannot read image:" << task.originalPath;
150+
return QImage();
151+
}
152+
153+
QSize originalSize = reader.size();
154+
if (originalSize.isEmpty()) {
155+
qWarning() << "Cannot get image size:" << task.originalPath;
156+
return QImage();
157+
}
158+
159+
QSize decodeSize = originalSize;
160+
decodeSize.scale(task.targetSize, Qt::KeepAspectRatioByExpanding);
161+
reader.setScaledSize(decodeSize);
162+
163+
QImage image = reader.read();
147164
if (image.isNull()) {
148-
qWarning() << "load image failed:" << task.originalPath;
165+
qWarning() << "load image failed:" << task.originalPath << reader.errorString();
149166
return image;
150167
}
151168

152-
QSize size = task.targetSize;
153-
image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
154-
image = image.copy(QRect((image.width() - size.width()) / 2,
155-
(image.height() - size.height()) / 2,
156-
size.width(),
157-
size.height()));
158-
159-
return image;
169+
const QSize &size = task.targetSize;
170+
return image.copy(QRect((image.width() - size.width()) / 2,
171+
(image.height() - size.height()) / 2,
172+
size.width(),
173+
size.height()));
160174
}
161175

162176
QString ScaleImageThread::cacheImageToDisk(QImage &image, const TaskData &task, const QString &md5String)

src/plugin-qt/wallpapercache/wallpapercacheservice.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,14 @@ QString WallpaperCacheService::saveImageFromFd(const QDBusUnixFileDescriptor &fd
201201
}
202202
originFile.close();
203203

204-
// Detect format and rename with extension
205-
QImageReader reader(originPath);
206-
QString format = reader.format();
207-
QString destinationPath = originPath + QString(".%1").arg(format);
204+
// Detect format using static method to avoid loading entire image
205+
QByteArray format = QImageReader::imageFormat(originPath);
206+
if (format.isEmpty()) {
207+
qWarning() << "Failed to detect image format:" << originPath;
208+
QFile::remove(originPath);
209+
return QString();
210+
}
211+
QString destinationPath = originPath + QString(".%1").arg(QString::fromLatin1(format));
208212
QFile file(originPath);
209213
if (!file.rename(destinationPath)) {
210214
qWarning() << "originPath rename failed";

0 commit comments

Comments
 (0)