| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
1 |
#include "thumbnailworker.h" |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
2 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
3 |
#include "thumbnailcache.h" |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
4 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
5 |
#include <QFile> |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
6 |
#include <QImageReader> |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
7 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
8 |
#include <fcntl.h> |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
9 |
#include <unistd.h> |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
10 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
11 |
namespace |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
12 |
{ |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
13 |
constexpr int kDisplaySize = 128; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
14 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
15 |
QImage downscaleForDisplay(const QImage &src) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
16 |
{ |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
17 |
if (src.isNull()) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
18 |
return src; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
19 |
if (src.width() <= kDisplaySize && src.height() <= kDisplaySize) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
20 |
return src; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
21 |
return src.scaled(kDisplaySize, kDisplaySize, |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
22 |
Qt::KeepAspectRatio, |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
23 |
Qt::SmoothTransformation); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
24 |
} |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
25 |
} // namespace |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
26 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
27 |
ThumbnailWorker::ThumbnailWorker(const QByteArray &path, |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
28 |
int row, |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
29 |
ThumbnailCache::Size size, |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
30 |
std::atomic_bool *cancelFlag) |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
31 |
: m_path(path), |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
32 |
m_row(row), |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
33 |
m_size(size), |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
34 |
m_cancelFlag(cancelFlag) |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
35 |
{ |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
36 |
setAutoDelete(true); |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
37 |
} |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
38 |
|
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
39 |
void ThumbnailWorker::run() |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
40 |
{ |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
41 |
if (*m_cancelFlag) |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
42 |
return; |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
43 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
44 |
// Per the spec, never thumbnail files that live inside the cache itself. |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
45 |
if (ThumbnailCache::isInsideCache(m_path)) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
46 |
return; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
47 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
48 |
const int target = static_cast<int>(m_size); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
49 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
50 |
QImage cached = ThumbnailCache::load(m_path, m_size); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
51 |
if (*m_cancelFlag) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
52 |
return; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
53 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
54 |
if (!cached.isNull()) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
55 |
{ |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
56 |
emit finished(m_row, downscaleForDisplay(cached)); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
57 |
return; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
58 |
} |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
59 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
60 |
// Open the file via POSIX open() so that paths with non-UTF-8 bytes |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
61 |
// (e.g. Latin-1 encoded filenames) are handled correctly. |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
62 |
int fd = ::open(m_path.constData(), O_RDONLY | O_CLOEXEC); |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
63 |
if (fd < 0) |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
64 |
return; |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
65 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
66 |
QFile file; |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
67 |
if (!file.open(fd, QIODevice::ReadOnly, QFileDevice::AutoCloseHandle)) |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
68 |
{ |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
69 |
::close(fd); |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
70 |
return; |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
71 |
} |
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
72 |
|
| 80a9926d |
Poul Sander |
2026-05-19 20:28 |
73 |
QImageReader reader(&file); |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
74 |
reader.setAutoTransform(true); |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
75 |
|
| 7889168c |
Poul Sander |
2026-02-26 18:27 |
76 |
// Scale during decoding to avoid hitting the allocation limit |
| 7889168c |
Poul Sander |
2026-02-26 18:27 |
77 |
// on very large images (Qt 6 defaults to 128 MB). |
| 7889168c |
Poul Sander |
2026-02-26 18:27 |
78 |
QSize fullSize = reader.size(); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
79 |
if (fullSize.isValid()) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
80 |
{ |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
81 |
QSize scaled = fullSize.scaled(target, target, Qt::KeepAspectRatio); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
82 |
reader.setScaledSize(scaled); |
| 7889168c |
Poul Sander |
2026-02-26 18:27 |
83 |
} |
| 7889168c |
Poul Sander |
2026-02-26 18:27 |
84 |
|
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
85 |
QImage image = reader.read(); |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
86 |
|
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
87 |
if (*m_cancelFlag) |
| 6fcd6c90 |
Poul Sander |
2026-02-19 21:12 |
88 |
return; |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
89 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
90 |
if (image.isNull()) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
91 |
return; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
92 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
93 |
// Ensure the longest side is exactly the target (the decoder hint may have |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
94 |
// been ignored for some formats). Aspect ratio preserved, no padding canvas. |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
95 |
QImage thumb; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
96 |
if (image.width() > target || image.height() > target) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
97 |
thumb = image.scaled(target, target, |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
98 |
Qt::KeepAspectRatio, |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
99 |
Qt::SmoothTransformation); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
100 |
else |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
101 |
thumb = image; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
102 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
103 |
ThumbnailCache::save(m_path, m_size, thumb); |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
104 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
105 |
if (*m_cancelFlag) |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
106 |
return; |
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
107 |
|
| ac476ca8 |
Poul Sander |
2026-05-18 16:47 |
108 |
emit finished(m_row, downscaleForDisplay(thumb)); |
| cec3b5da |
Poul Sander |
2026-02-19 19:17 |
109 |
} |
|
|
1970-01-01 00:00 |
110 |
|