git repos / SagoImageBrowser

blame: src/thumbnailworker.cpp

normal view · raw

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