From 12f8ac9f0dcd1b012ae5c88a24499af6d9f6571e Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Fri, 4 Mar 2016 16:44:04 +0200 Subject: [PATCH] kioslave: add ePub thumbnailer Signed-off-by: Ivailo Monev --- kioslave/thumbnail/CMakeLists.txt | 65 ++--- kioslave/thumbnail/epub.cpp | 417 +++++++++++++++++++++++++++++++ kioslave/thumbnail/epub.h | 57 +++++ kioslave/thumbnail/epubthumbnail.cpp | 91 +++++++ kioslave/thumbnail/epubthumbnail.desktop | 11 + kioslave/thumbnail/epubthumbnail.h | 37 +++ 6 files changed, 649 insertions(+), 29 deletions(-) create mode 100644 kioslave/thumbnail/epub.cpp create mode 100644 kioslave/thumbnail/epub.h create mode 100644 kioslave/thumbnail/epubthumbnail.cpp create mode 100644 kioslave/thumbnail/epubthumbnail.desktop create mode 100644 kioslave/thumbnail/epubthumbnail.h diff --git a/kioslave/thumbnail/CMakeLists.txt b/kioslave/thumbnail/CMakeLists.txt index 4674c249..a524c1b9 100644 --- a/kioslave/thumbnail/CMakeLists.txt +++ b/kioslave/thumbnail/CMakeLists.txt @@ -57,12 +57,12 @@ kde4_add_plugin(jpegthumbnail ${jpegthumbnail_PART_SRCS}) target_link_libraries(jpegthumbnail ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${JPEG_LIBRARIES} ${KDE4_KIO_LIBS}) -if (HAVE_EXIV2) +if(HAVE_EXIV2) set_source_files_properties(jpegcreator.cpp PROPERTIES COMPILE_FLAGS "-DHAVE_EXIV2 ${KDE4_ENABLE_EXCEPTIONS}") include_directories(${EXIV1_INCLUDE_DIR}) target_link_libraries(jpegthumbnail ${EXIV2_LIBRARIES}) -endif (HAVE_EXIV2) +endif() install(FILES jpegcreatorsettings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) install(TARGETS jpegthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) @@ -112,7 +112,6 @@ install(TARGETS djvuthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) ########### next target ############### if(OPENEXR_FOUND) - include_directories( ${OPENEXR_INCLUDE_DIR}) set(exrthumbnail_PART_SRCS exrcreator.cpp) @@ -126,14 +125,12 @@ if(OPENEXR_FOUND) set_target_properties(exrthumbnail PROPERTIES COMPILE_FLAGS "${KDE4_ENABLE_EXCEPTIONS}") install(TARGETS exrthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) - install( FILES exrthumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR}) - -endif(OPENEXR_FOUND) + install(FILES exrthumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +endif() ########### next target ############### if(X11_Xcursor_FOUND) - set(cursorthumbnail_PART_SRCS cursorcreator.cpp) kde4_add_plugin(cursorthumbnail ${cursorthumbnail_PART_SRCS}) @@ -141,42 +138,48 @@ if(X11_Xcursor_FOUND) target_link_libraries(cursorthumbnail ${X11_Xcursor_LIB} ${KDE4_KIO_LIBS}) install(TARGETS cursorthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) - install( FILES cursorthumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR}) - -endif(X11_Xcursor_FOUND) + install(FILES cursorthumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +endif() ########### next target ############### -set ( windowsexethumbnail_SRCS windowsexecreator.cpp icoutils_common.cpp) -set ( windowsimagethumbnail_SRCS windowsimagecreator.cpp icoutils_common.cpp) +set(windowsexethumbnail_SRCS windowsexecreator.cpp icoutils_common.cpp) +set(windowsimagethumbnail_SRCS windowsimagecreator.cpp icoutils_common.cpp) -set ( windowsexethumbnail_SRCS ${windowsexethumbnail_SRCS} icoutils_wrestool.cpp ) -set ( windowsimagethumbnail_SRCS ${windowsimagethumbnail_SRCS} icoutils_wrestool.cpp ) +set(windowsexethumbnail_SRCS ${windowsexethumbnail_SRCS} icoutils_wrestool.cpp ) +set(windowsimagethumbnail_SRCS ${windowsimagethumbnail_SRCS} icoutils_wrestool.cpp ) -kde4_add_plugin ( windowsexethumbnail ${windowsexethumbnail_SRCS} ) -target_link_libraries ( windowsexethumbnail ${KDE4_KIO_LIBS} ) -install ( TARGETS windowsexethumbnail DESTINATION ${PLUGIN_INSTALL_DIR} ) -install ( FILES windowsexethumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +kde4_add_plugin(windowsexethumbnail ${windowsexethumbnail_SRCS}) +target_link_libraries( windowsexethumbnail ${KDE4_KIO_LIBS} ) +install(TARGETS windowsexethumbnail DESTINATION ${PLUGIN_INSTALL_DIR} ) -kde4_add_plugin ( windowsimagethumbnail ${windowsimagethumbnail_SRCS} ) -target_link_libraries ( windowsimagethumbnail ${KDE4_KIO_LIBS} ) -install ( TARGETS windowsimagethumbnail DESTINATION ${PLUGIN_INSTALL_DIR} ) -install ( FILES windowsimagethumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +kde4_add_plugin(windowsimagethumbnail ${windowsimagethumbnail_SRCS}) +target_link_libraries(windowsimagethumbnail ${KDE4_KIO_LIBS}) +install(TARGETS windowsimagethumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) ########### next target ############### set(comicbookthumbnail_SRCS comiccreator.cpp) kde4_add_plugin(comicbookthumbnail ${comicbookthumbnail_SRCS}) -target_link_libraries(comicbookthumbnail ${KDE4_KIO_LIBS}) -if (UNIX) - target_link_libraries(comicbookthumbnail ${KDE4_KPTY_LIBRARY}) -endif (UNIX) +target_link_libraries(comicbookthumbnail ${KDE4_KIO_LIBS} ${KDE4_KPTY_LIBRARY}) install(TARGETS comicbookthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) +########### next target ############### + +set(epubthumbnail_SRCS epub.cpp epubthumbnail.cpp) +kde4_add_plugin(epubthumbnail ${epubthumbnail_SRCS}) +target_link_libraries(epubthumbnail ${KDE4_KIO_LIBS}) +install(TARGETS epubthumbnail DESTINATION ${PLUGIN_INSTALL_DIR}) + ########### install files ############### -install(FILES thumbcreator.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) -install(FILES +install( + FILES thumbcreator.desktop + DESTINATION ${SERVICETYPES_INSTALL_DIR} +) + +install( + FILES thumbnail.protocol svgthumbnail.desktop imagethumbnail.desktop @@ -186,4 +189,8 @@ install(FILES djvuthumbnail.desktop desktopthumbnail.desktop comicbookthumbnail.desktop - DESTINATION ${SERVICES_INSTALL_DIR}) + epubthumbnail.desktop + windowsimagethumbnail.desktop + windowsexethumbnail.desktop + DESTINATION ${SERVICES_INSTALL_DIR} +) diff --git a/kioslave/thumbnail/epub.cpp b/kioslave/thumbnail/epub.cpp new file mode 100644 index 00000000..0c684f5b --- /dev/null +++ b/kioslave/thumbnail/epub.cpp @@ -0,0 +1,417 @@ +/* +This file is part of kde-thumbnailer-epub +Copyright (C) 2012-2013-2014 Caig + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "epub.h" + +#include + +bool endsWith (const QString &coverUrl, const QStringList &extensions); + +epub::epub(const QString &path) : KZip(path) +{ + qDebug() << "[epub thumbnailer]" << "Opening" << path; +} + +bool epub::open(QIODevice::OpenMode mode) +{ + bool returnValue = KZip::open(mode); + + qDebug() << "[epub thumbnailer]" << "Retrieving files list..."; + + getItemsList(this->directory(), ""); + + if (mItemsList.count() != 0) { + /* + for (int i = 0; i < mItemsList.count(); ++i) + { + qDebug() << "[epub thumbnailer]" << mItemsList.at(i); + } + */ + qDebug() << "[epub thumbnailer]" << "Found" << mItemsList.count() << "files."; + } else { + qDebug() << "[epub thumbnailer]" << "No files found."; + return false; + } + + if (getOpfUrl()) { + qDebug() << "[epub thumbnailer]" << "Opf:" << mOpfUrl; + } else { + qDebug() << "[epub thumbnailer]" << "No OPF file found."; + return false; + } + + return returnValue; +} + +void epub::getItemsList(const KArchiveDirectory *dir, QString path) +{ + QStringList tempList = dir->entries(); + + for (int i = 0; i < tempList.count(); ++i) + { + const KArchiveEntry *entry = dir->entry(tempList.at(i)); + + if (entry->isFile()) { + mItemsList.append(path + "/" + tempList.at(i)); + } else { + getItemsList(static_cast(entry), path + "/" + tempList.at(i)); + } + } +} + +bool epub::getOpfUrl() +{ + qDebug() << "[epub thumbnailer]" << "Searching for opf url..."; + + QString value = ""; + + QString containerXmlUrl = getFileUrl("META-INF/container.xml"); // it must exist according to format specification, but better to be sure... + if (!containerXmlUrl.isEmpty()) { + if (mDeviceUrl != containerXmlUrl) { + getXml(containerXmlUrl); + } + + while(!mQXml.atEnd()) + { + mQXml.readNext(); + + if (mQXml.name() == "rootfile" && mQXml.isStartElement()) { + QXmlStreamAttributes qxmlAttributes = mQXml.attributes(); + + if (qxmlAttributes.hasAttribute("full-path")) { + value = qxmlAttributes.value("full-path").toString(); + break; + } + } + } + } + + if (value.isEmpty()) { + qDebug() << "[epub thumbnailer]" << "No or wrong container.xml, trying to find opf file manually..."; + + int i = 0; + while (i < mItemsList.count()) + { + if (mItemsList.at(i).endsWith(".opf", Qt::CaseInsensitive)) { + value = mItemsList.at(i); + qDebug() << "[epub thumbnailer]" << "Opf manually found."; + break; + } + ++i; + } + } + + mOpfUrl = value; + + return !mOpfUrl.isEmpty(); +} + +QString epub::parseMetadata() +{ + qDebug() << "[epub thumbnailer]" << "Searching cover reference in metadata..."; + + getXml(mOpfUrl); + + QString value = ""; + + while(!mQXml.atEnd()) + { + mQXml.readNext(); + + if (mQXml.name() == "metadata" && mQXml.isEndElement()) { + break; + } + + if (mQXml.name() == "meta" && mQXml.isStartElement()) { + QXmlStreamAttributes qxmlAttributes = mQXml.attributes(); + + if (qxmlAttributes.hasAttribute("name") && qxmlAttributes.hasAttribute("content")) { + if (qxmlAttributes.value("name") == "cover") { + value = qxmlAttributes.value("content").toString(); + break; + } + } + } + } + + if (value.isEmpty()) { + qDebug() << "[epub thumbnailer]" << "No cover reference found."; + } else { + qDebug() << "[epub thumbnailer]" << "Metadata reference:" << value; + } + + return value; +} + +QString epub::parseManifest(const QString &coverId) +{ + qDebug() << "[epub thumbnailer]" << "Searching for cover href in manifest..."; + + bool exactMatch = true; + QString tCoverId = coverId; + if (tCoverId.isEmpty()) { + tCoverId = "cover"; + exactMatch = false; + } + + getXml(mOpfUrl); + + QString value = ""; + + while(!mQXml.atEnd()) + { + mQXml.readNext(); + + if (mQXml.name() == "manifest" && mQXml.isEndElement()) { + break; + } + + if (mQXml.name() == "item" && mQXml.isStartElement()) { + QXmlStreamAttributes qxmlAttributes = mQXml.attributes(); + + if (qxmlAttributes.hasAttribute("id") && qxmlAttributes.hasAttribute("href")) { + if (exactMatch == true) { + if (qxmlAttributes.value("id").toString().toLower() == tCoverId.toLower()) { //toLower as a workaround for some stupid epubs + value = qxmlAttributes.value("href").toString(); + break; + } + } else { + if (qxmlAttributes.value("id").contains(tCoverId, Qt::CaseInsensitive) && qxmlAttributes.value("media-type").contains("image")) { + value = qxmlAttributes.value("href").toString(); + break; + } + } + } + } + } + + if (value.isEmpty()) { + //value = "cover"; //last chance, try to pick a file with "cover" in the filename + qDebug() << "[epub thumbnailer]" << "No cover href found."; + } else { + qDebug() << "[epub thumbnailer]" << "Cover href:" << value; + } + + return value; +} + +// seems useful on very rare cases +QString epub::parseGuide() +{ + qDebug() << "[epub thumbnailer]" << "Searching cover reference in guide..."; + + getXml(mOpfUrl); + + QString value = ""; + + while(!mQXml.atEnd()) + { + mQXml.readNext(); + + if (mQXml.name() == "guide" && mQXml.isEndElement()) { + break; + } + + if (mQXml.name() == "reference" && mQXml.isStartElement()) { + QXmlStreamAttributes qxmlAttributes = mQXml.attributes(); + + if (qxmlAttributes.hasAttribute("type") && qxmlAttributes.hasAttribute("title") && qxmlAttributes.hasAttribute("href")) { + if (qxmlAttributes.value("type") == "cover" || qxmlAttributes.value("title") == "cover") { + value = qxmlAttributes.value("href").toString(); + break; + } + } + } + } + + if (value.isEmpty()) { + qDebug() << "[epub thumbnailer]" << "No cover reference found."; + } else { + qDebug() << "[epub thumbnailer]" << "Guide reference:" << value; + } + + return value; +} + +// pick the first xhtm file according to the spine section, it could contain the cover image +// seems useful on very rare cases +QString epub::parseSpine() +{ + qDebug() << "[epub thumbnailer]" << "Searching first file in spine..."; + + getXml(mOpfUrl); + + QString value = ""; + + while(!mQXml.atEnd()) + { + mQXml.readNext(); + + if (mQXml.name() == "spine" && mQXml.isEndElement()) { + break; + } + + if (mQXml.name() == "itemref" && mQXml.isStartElement()) { + QXmlStreamAttributes qxmlAttributes = mQXml.attributes(); + + if (qxmlAttributes.hasAttribute("idref")) { + value = qxmlAttributes.value("idref").toString(); + break; + } + } + } + + if (value.isEmpty()) { + qDebug() << "[epub thumbnailer]" << "No first file found."; + } else { + qDebug() << "[epub thumbnailer]" << "First file:" << value; + } + + return value; +} + +//to ensure the ref is an existing file path +QString epub::getFileUrl(const QString &href) +{ + QString value = ""; + QString tHref = href; + + //sometimes parseCoverPage finds relative path, fixes it before to use it + if (href.startsWith("../")) { + tHref = href.mid(3); + } + + int i = 0; + while (i < mItemsList.count()) + { + if (mItemsList.at(i).contains(tHref, Qt::CaseInsensitive)) { + value = mItemsList.at(i); + break; + } + ++i; + } + + return value; +} + +QString epub::getCoverUrl(const QString &href) +{ + QString value = getFileUrl(href); + + if (!value.isEmpty()) { + if (endsWith(value, QStringList() << "jpg" << "jpeg" << "png" << "gif" << "bmp")) { + return value; + } else if (endsWith(value, QStringList() << "xhtml" << "xhtm" << "html" << "htm" << "xml")) { + QString tCoverUrl = parseCoverPage(value); + if (!tCoverUrl.isEmpty()) { + value = getFileUrl(tCoverUrl); + } else { + qDebug() << "[epub thumbnailer]" << "No image found in the cover page."; + } + } + } else { + qDebug() << "[epub thumbnailer]" << "Has it a cover?"; + } + + return value; +} + +bool epub::getFile(const QString &fileName) +{ + if (mDeviceUrl != fileName) { + const KArchiveDirectory *dir = this->directory(); + const KZipFileEntry *file = static_cast(dir->entry(fileName)); + mContainer.reset(file->createDevice()); + mDeviceUrl = fileName; + + return true; + } + + return false; +} + +void epub::getXml(const QString &fileName) +{ + if (!getFile(fileName)) { + mContainer.data()->reset(); // to ensure the file is parsed from beginning + } + + mQXml.setDevice(mContainer.data()); // it's a bit strange to re-set the device in case the QIODevice isn't changed, but seems needed with some (a bit malformed) opf files + + /* + if (getFile(fileName)) { + mQXml.setDevice(mContainer.data()); + } else { + mContainer.data()->reset(); // ensure the file is parsed from beginning + } + */ +} + +bool epub::getCoverImage(const QString &fileName, QImage &coverImage) +{ + if (getFile(fileName)) { + QImage tCoverImage; + if (tCoverImage.loadFromData(mContainer.data()->readAll())) { + coverImage = tCoverImage; + + return true; + } + } + + return false; +} + +// parse an xhtm(in an ideal world with just validated epub files) to search for the first image reference +QString epub::parseCoverPage(const QString &coverUrl) +{ + getXml(coverUrl); + + QString tCoverUrl = ""; + + while (!mQXml.atEnd()) + { + mQXml.readNextStartElement(); + + if (mQXml.name().toString().toLower() == "img") { //toLower as a workaround for some xhtm + tCoverUrl = mQXml.attributes().value("src").toString(); + break; + } else if (mQXml.name().toString().toLower() == "image") { + tCoverUrl = mQXml.attributes().value("xlink:href").toString(); + break; + } + } + + return tCoverUrl; +} + +bool endsWith (const QString &coverUrl, const QStringList &extensions) +{ + bool returnValue = false; + + int i = 0; + while (i < extensions.count()) + { + if (coverUrl.endsWith("." + extensions.at(i), Qt::CaseInsensitive)) { + returnValue = true; + break; + } + ++i; + } + + return returnValue; +} diff --git a/kioslave/thumbnail/epub.h b/kioslave/thumbnail/epub.h new file mode 100644 index 00000000..07cc617c --- /dev/null +++ b/kioslave/thumbnail/epub.h @@ -0,0 +1,57 @@ +/* +This file is part of kde-thumbnailer-epub +Copyright (C) 2012-2013-2014 Caig + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef EPUB_H +#define EPUB_H + +#include +#include +#include + +class epub : public KZip +{ +public: + epub(const QString &path); + bool open(QIODevice::OpenMode mode); + + QString parseMetadata(); + QString parseGuide(); + QString parseSpine(); + QString parseManifest(const QString &coverId); + + QString getCoverUrl(const QString &href); + bool getCoverImage(const QString &fileName, QImage &coverImage); + +private: + QStringList mItemsList; + QScopedPointer mContainer; + QXmlStreamReader mQXml; + QString mDeviceUrl; + + QString mOpfUrl; + + void getItemsList(const KArchiveDirectory *dir, QString path); + bool getOpfUrl(); + QString getFileUrl(const QString &href); + bool getFile(const QString &fileName); + void getXml(const QString &fileName); + + QString parseCoverPage(const QString &coverUrl); +}; + +#endif // EPUB_H diff --git a/kioslave/thumbnail/epubthumbnail.cpp b/kioslave/thumbnail/epubthumbnail.cpp new file mode 100644 index 00000000..46f9ea10 --- /dev/null +++ b/kioslave/thumbnail/epubthumbnail.cpp @@ -0,0 +1,91 @@ +/* +This file is part of kde-thumbnailer-epub +Copyright (C) 2012-2013-2014 Caig + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "epubthumbnail.h" +#include "epub.h" + +#include +#include + +extern "C" +{ + KDE_EXPORT ThumbCreator *new_creator() + { + return new EPUBCreator(); + } +} + +EPUBCreator::EPUBCreator() +{ + +} + +EPUBCreator::~EPUBCreator() +{ + +} + +bool EPUBCreator::create(const QString &path, int width, int height, QImage &img) +{ + epub epubFile(path); + + if (!epubFile.open(QIODevice::ReadOnly)) { + qDebug() << "[epub thumbnailer]" << "Couldn't open or parse" << path; + } else { + QString metadataRef = epubFile.parseMetadata(); + QString coverHref = epubFile.parseManifest(metadataRef); + + if (coverHref.isEmpty()) { + coverHref = epubFile.parseGuide(); + + if (coverHref.isEmpty()) { + QString idRef = epubFile.parseSpine(); + if (idRef.isEmpty()) { + coverHref = "cover"; // last chance, will try to pick a file with "cover" in the url + } else { + coverHref = epubFile.parseManifest(idRef); + if (coverHref.isEmpty()) { + coverHref = "cover"; // last chance + } + } + } + } + + qDebug() << "[epub thumbnailer]" << "Searching for cover url..."; + QString coverUrl = epubFile.getCoverUrl(coverHref); + + if (!coverUrl.isEmpty()) { + qDebug() << "[epub thumbnailer]" << "Cover url:" << coverUrl; + + QImage coverImage; + if (epubFile.getCoverImage(coverUrl, coverImage)) { + img = coverImage.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); + qDebug() << "[epub thumbnailer]" << "Done!"; + } + } + } + + epubFile.close(); + + return !img.isNull(); +} + +ThumbCreator::Flags EPUBCreator::flags() const +{ + return None; +} \ No newline at end of file diff --git a/kioslave/thumbnail/epubthumbnail.desktop b/kioslave/thumbnail/epubthumbnail.desktop new file mode 100644 index 00000000..a2f00e26 --- /dev/null +++ b/kioslave/thumbnail/epubthumbnail.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +Name=ePub documents +Name[de]=ePub-Dateien +Name[it]=Documenti ePub +Name[zh_CN]=ePub 文档 +X-KDE-ServiceTypes=ThumbCreator +MimeType=application/epub+zip; +CacheThumbnail=true +X-KDE-Library=epubthumbnail \ No newline at end of file diff --git a/kioslave/thumbnail/epubthumbnail.h b/kioslave/thumbnail/epubthumbnail.h new file mode 100644 index 00000000..3eaa93ad --- /dev/null +++ b/kioslave/thumbnail/epubthumbnail.h @@ -0,0 +1,37 @@ +/* +This file is part of kde-thumbnailer-epub +Copyright (C) 2012-2013-2014 Caig + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef EPUBTHUMBNAIL_H +#define EPUBTHUMBNAIL_H + +#include +#include + +class EPUBCreator : public QObject, public ThumbCreator +{ + Q_OBJECT + + public: + explicit EPUBCreator(); + virtual ~EPUBCreator(); + virtual bool create(const QString &path, int width, int height, QImage &img); + virtual Flags flags() const; + +}; + +#endif // EPUBTHUMBNAIL_H -- 2.11.0