diff --git a/src/qtquick/PDFCoverImageProvider.cpp b/src/qtquick/PDFCoverImageProvider.cpp index fccb4da..653014f 100644 --- a/src/qtquick/PDFCoverImageProvider.cpp +++ b/src/qtquick/PDFCoverImageProvider.cpp @@ -1,109 +1,175 @@ /* * Copyright (C) 2016 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "PDFCoverImageProvider.h" +#include + #include #include #include #include #include #include +#include #include #include class PDFCoverImageProvider::Private { public: Private() { QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); thumbDir = QDir(path); QString subpath("thumbcache"); if(!thumbDir.exists(subpath)) { thumbDir.mkpath(subpath); } thumbDir.cd(subpath); } QDir thumbDir; + QThreadPool pool; }; PDFCoverImageProvider::PDFCoverImageProvider() - : QQuickImageProvider(QQuickImageProvider::Pixmap, QQmlImageProviderBase::ForceAsynchronousImageLoading) + : QQuickAsyncImageProvider() , d(new Private) { } PDFCoverImageProvider::~PDFCoverImageProvider() { delete d; } -QPixmap PDFCoverImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) +class PDFCoverResponse : public QQuickImageResponse +{ + public: + PDFCoverResponse(const QString &id, const QSize &requestedSize, const QDir& thumbDir, QThreadPool *pool) + { + m_runnable = new PDFCoverRunnable(id, requestedSize, thumbDir); + connect(m_runnable, &PDFCoverRunnable::done, this, &PDFCoverResponse::handleDone); + pool->start(m_runnable); + } + + void handleDone(QImage image) { + m_image = image; + emit finished(); + } + + QQuickTextureFactory *textureFactory() const override + { + return QQuickTextureFactory::textureFactoryForImage(m_image); + } + + void cancel() override + { + m_runnable->abort(); + } + + PDFCoverRunnable* m_runnable{nullptr}; + QImage m_image; +}; + +QQuickImageResponse * PDFCoverImageProvider::requestImageResponse(const QString& id, const QSize& requestedSize) +{ + PDFCoverResponse* response = new PDFCoverResponse(id, requestedSize, d->thumbDir, &d->pool); + return response; +} + +class PDFCoverRunnable::Private { +public: + Private() {} + QString id; + QSize requestedSize; + + bool abort{false}; + + QDir thumbDir; +}; + +PDFCoverRunnable::PDFCoverRunnable(const QString& id, const QSize& requestedSize, const QDir& thumbDir) + : d(new Private) { - Q_UNUSED(size) - Q_UNUSED(requestedSize) - QPixmap img; + d->id = id; + d->requestedSize = requestedSize; + d->thumbDir = thumbDir; +} + +void PDFCoverRunnable::abort() +{ + d->abort = true; +} + +void PDFCoverRunnable::run() +{ + QImage img; + + QSize ourSize(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous); + if(d->requestedSize.width() > 0 && d->requestedSize.height() > 0) + { + ourSize = d->requestedSize; + } QMimeDatabase db; - db.mimeTypeForFile(id, QMimeDatabase::MatchContent); - const QMimeType mime = db.mimeTypeForFile(id, QMimeDatabase::MatchContent); - if(mime.inherits("application/pdf")) { + db.mimeTypeForFile(d->id, QMimeDatabase::MatchContent); + const QMimeType mime = db.mimeTypeForFile(d->id, QMimeDatabase::MatchContent); + if(!d->abort && mime.inherits("application/pdf")) { //-sOutputFile=FILENAME.png FILENAME - QString outFile = QString("%1/%2.png").arg(d->thumbDir.absolutePath()).arg(QUrl(id).toString().replace("/", "-").replace(":", "-")); - if(!QFile::exists(outFile)) { + QString outFile = QString("%1/%2.png").arg(d->thumbDir.absolutePath()).arg(QUrl(d->id).toString().replace("/", "-").replace(":", "-")); + if(!d->abort && !QFile::exists(outFile)) { // then we've not already generated a thumbnail, try to make one... QProcess thumbnailer; QStringList args; args << "-sPageList=1" << "-dLastPage=1" << "-dSAFER" << "-dBATCH" << "-dNOPAUSE" << "-dQUIET" << "-sDEVICE=png16m" << "-dGraphicsAlphaBits=4" << "-r300"; - args << QString("-sOutputFile=%1").arg(outFile) << id; + args << QString("-sOutputFile=%1").arg(outFile) << d->id; QString gsApp; #ifdef Q_OS_WIN #ifdef __MINGW32__ gsApp = qApp->applicationDirPath() + "/gsc.exe"; #else gsApp = qApp->applicationDirPath(); #ifdef Q_OS_WIN64 gsApp += "/gswin64c.exe"; #else gsApp += "/gswin32c.exe"; #endif #endif #else gsApp = "gs"; #endif thumbnailer.start(gsApp, args); thumbnailer.waitForFinished(); } bool success = false; // Now, does it exist this time? - if(QFile::exists(outFile)) { + if(!d->abort && QFile::exists(outFile)) { success = img.load(outFile); } - if(!success) { - QIcon oops = QIcon::fromTheme("unknown"); - img = oops.pixmap(oops.availableSizes().last()); - qCDebug(QTQUICK_LOG) << "Failed to load image with id" << id << "from thumbnail file" << outFile; + if(!d->abort && !success) { + QIcon oops = QIcon::fromTheme("application-pdf"); + img = oops.pixmap(oops.availableSizes().last()).toImage(); + qCDebug(QTQUICK_LOG) << "Failed to load image with id" << d->id << "from thumbnail file" << outFile; } } - - return img; + Q_EMIT done(img.scaled(ourSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } diff --git a/src/qtquick/PDFCoverImageProvider.h b/src/qtquick/PDFCoverImageProvider.h index 0bb6a57..4287ed6 100644 --- a/src/qtquick/PDFCoverImageProvider.h +++ b/src/qtquick/PDFCoverImageProvider.h @@ -1,53 +1,79 @@ /* * Copyright (C) 2016 Dan Leinir Turthra Jensen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #ifndef PDFCOVERIMAGEPROVIDER_H #define PDFCOVERIMAGEPROVIDER_H -#include +#include +#include /** * \brief Get file previews of PDF files, where the thumbnailer isn't available... * * NOTE: As this task is potentially heavy, make sure to mark any Image using this provider asynchronous */ -class PDFCoverImageProvider : public QQuickImageProvider +class PDFCoverImageProvider : public QQuickAsyncImageProvider { public: explicit PDFCoverImageProvider(); virtual ~PDFCoverImageProvider(); /** * \brief Get an image. * * @param id The source of the image. - * @param size The size of the original image, unused. * @param requestedSize The required size of the final image, unused. * - * @return a QPixmap. + * @return an asynchronous image response */ - virtual QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; + QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override; +private: + class Private; + Private* d; +}; + +class QDir; +/** + * \brief A worker class which does the bulk of the work for PreviewImageProvider + */ +class PDFCoverRunnable : public QObject, public QRunnable { + Q_OBJECT; +public: + PDFCoverRunnable(const QString &id, const QSize &requestedSize, const QDir& thumbDir); + + void run() override; + + /** + * Request that the preview worker abort what it's doing + */ + Q_SLOT void abort(); + + /** + * \brief Emitted once the preview has been retrieved (successfully or not) + * @param image The preview image in the requested size (possibly a placeholder) + */ + Q_SIGNAL void done(QImage image); private: class Private; Private* d; }; #endif//PDFCOVERIMAGEPROVIDER_H