#include "wallpapercache.hpp" #include #include #include #include #include #include #include #include #include #include namespace ZShell::wallpaper { namespace { QString connectionName() { return QStringLiteral("wallpaper-cache-%1") .arg(quintptr(QThread::currentThreadId())); } QSqlDatabase openDatabase(const QString& databasePath) { const QString connection = connectionName(); QSqlDatabase database = QSqlDatabase::contains(connection) ? QSqlDatabase::database(connection, false) : QSqlDatabase::addDatabase("QSQLITE", connection); if (database.databaseName() != databasePath) { if (database.isOpen()) database.close(); database.setDatabaseName(databasePath); } if (!database.isOpen() && !database.open()) return {}; return database; } } // namespace void WallpaperCache::setDbPath(const QString& path) { std::lock_guard lock(m_mtx); m_dbPath = path; } QString WallpaperCache::dbPath() const { std::lock_guard lock(m_mtx); return m_dbPath; } QByteArray WallpaperCache::cachedBlob(const QString& path) const { if (path.isEmpty()) return {}; const QString databasePath = dbPath(); if (databasePath.isEmpty()) return {}; const QFileInfo info(path); QSqlDatabase database = openDatabase(databasePath); if (!database.isOpen()) return {}; QSqlQuery query(database); query.prepare("SELECT cache, size, mtime FROM wallpapers WHERE path = ?"); query.addBindValue(info.absoluteFilePath()); if (!query.exec() || !query.next()) return {}; const QByteArray blob = query.value(0).toByteArray(); if (blob.isEmpty()) return {}; const qint64 mtime = info.lastModified().toMSecsSinceEpoch() / 1000; if (query.value(1).toLongLong() != info.size() || query.value(2).toLongLong() != mtime) { return {}; } return blob; } QImage WallpaperCache::decodeImage( const QString& path, const QSize& decodeSize) const { if (path.isEmpty()) return {}; QImageReader probe(path); const QSize source = probe.size(); QSize required = source.isEmpty() ? decodeSize : source; if (!source.isEmpty() && !decodeSize.isEmpty()) { const QSize cover = source.scaled(decodeSize, Qt::KeepAspectRatioByExpanding); if (cover.width() <= source.width() && cover.height() <= source.height()) required = cover; } const QByteArray blob = cachedBlob(path); if (!blob.isEmpty()) { QImage image = QImage::fromData(blob, "JPEG"); if (!image.isNull() && image.width() >= required.width() && image.height() >= required.height()) { return image.convertToFormat(QImage::Format_RGBA8888); } } QImageReader reader(path); reader.setAutoTransform(true); if (!decodeSize.isEmpty() && !source.isEmpty()) reader.setScaledSize( source.scaled(decodeSize, Qt::KeepAspectRatioByExpanding)); QImage image = reader.read(); if (image.isNull()) return {}; return image.convertToFormat(QImage::Format_RGBA8888); } QByteArray WallpaperCache::posterBlob(const QString& path) const { if (path.isEmpty()) return {}; const QString databasePath = dbPath(); if (databasePath.isEmpty()) return {}; const QFileInfo info(path); QSqlDatabase database = openDatabase(databasePath); if (!database.isOpen()) return {}; QSqlQuery query(database); query.prepare("SELECT poster, size, mtime FROM wallpapers WHERE path = ?"); query.addBindValue(info.absoluteFilePath()); if (!query.exec() || !query.next()) return {}; const QByteArray blob = query.value(0).toByteArray(); if (blob.isEmpty()) return {}; const qint64 mtime = info.lastModified().toMSecsSinceEpoch() / 1000; if (query.value(1).toLongLong() != info.size() || query.value(2).toLongLong() != mtime) { return {}; } return blob; } QVariantMap WallpaperCache::cropsForPath(const QString& path) const { if (path.isEmpty()) return {}; const QString databasePath = dbPath(); if (databasePath.isEmpty()) return {}; const QFileInfo info(path); QSqlDatabase database = openDatabase(databasePath); if (!database.isOpen()) return {}; QSqlQuery query(database); query.prepare("SELECT crop FROM wallpapers WHERE path = ?"); query.addBindValue(info.absoluteFilePath()); if (!query.exec() || !query.next()) return {}; const QByteArray json = query.value(0).toByteArray(); if (json.isEmpty()) return {}; const auto doc = QJsonDocument::fromJson(json); if (!doc.isObject()) return {}; return doc.object().toVariantMap(); } } // namespace ZShell::wallpaper