diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e7a290f7..16e57b959 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,15 +23,23 @@ set(okularGenerator_mobi_PART_SRCS generator_mobi.cpp ) +set(mobithumbnail_SRCS + mobipocket.cpp + decompressor.cpp + mobithumbnail.cpp +) + kde4_add_plugin(okularGenerator_mobi ${okularGenerator_mobi_PART_SRCS}) +kde4_add_plugin(mobithumbnail ${mobithumbnail_SRCS}) target_link_libraries(okularGenerator_mobi okularcore ${mobi_LIBRARIES} ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY}) +target_link_libraries(mobithumbnail ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${QT_QTGUI_LIBRARY} ) -install(TARGETS okularGenerator_mobi DESTINATION ${PLUGIN_INSTALL_DIR}) +install(TARGETS mobithumbnail okularGenerator_mobi DESTINATION ${PLUGIN_INSTALL_DIR}) ########### install files ############### -install( FILES libokularGenerator_mobi.desktop okularMobi.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) +install( FILES mobithumbnail.desktop libokularGenerator_mobi.desktop okularMobi.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) install( FILES okularApplication_mobi.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install( diff --git a/TODO b/TODO index 77eb436a4..15a6fcdb2 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,5 @@ - tests for Mobipocket classes - anchors (a filepos=) - decryption for DRMed files (may be impossible and/or illegal) +- strigi analyzer +- thumbnail generator does not for some files (DRMed i think) diff --git a/converter.cpp b/converter.cpp index 39a9a2124..c95cff13a 100644 --- a/converter.cpp +++ b/converter.cpp @@ -50,8 +50,12 @@ QTextDocument* Converter::convert( const QString &fileName ) { MobiDocument* newDocument=new MobiDocument(fileName); if (!newDocument->mobi()->isValid()) { - if (newDocument->mobi()->hasDRM()) emit error(i18n("This book is protected by DRM and can be displayed only on designated device"), -1); - else emit error(i18n("Error while opening the Mobipocket document."), -1); + emit error(i18n("Error while opening the Mobipocket document."), -1); + delete newDocument; + return NULL; + } + if (newDocument->mobi()->hasDRM()) { + emit error(i18n("This book is protected by DRM and can be displayed only on designated device"), -1); delete newDocument; return NULL; } diff --git a/mobidocument.cpp b/mobidocument.cpp index 7affc2626..adce53e72 100644 --- a/mobidocument.cpp +++ b/mobidocument.cpp @@ -40,7 +40,7 @@ QVariant MobiDocument::loadResource(int type, const QUrl &name) if (!ok || recnum>=doc->imageCount()) return QVariant(); QVariant resource; - resource.setValue(doc->getImage(recnum)); + resource.setValue(doc->getImage(recnum-1)); addResource(type, name, resource); return resource; diff --git a/mobipocket.cpp b/mobipocket.cpp index 0d8e009c5..148b7375b 100644 --- a/mobipocket.cpp +++ b/mobipocket.cpp @@ -86,23 +86,30 @@ int PDB::recordCount() const //////////////////////////////////////////// struct DocumentPrivate { - DocumentPrivate(QIODevice* d) : pdb(d), valid(true), firstImageRecord(0), isUtf(false), drm(false) {} + DocumentPrivate(QIODevice* d) : pdb(d), valid(true), firstImageRecord(0), isUtf(false), + drm(false), thumbnailIndex(0) {} PDB pdb; Decompressor* dec; quint16 ntextrecords; bool valid; + + // number of first record holding image. Usually it is directly after end of text, but not always quint16 firstImageRecord; QMap metadata; bool isUtf; bool drm; + // index of thumbnail in image list. May be specified in EXTH. + // If not then just use first image and hope for the best + int thumbnailIndex; + void init(); void findFirstImage(); void parseEXTH(const QByteArray& data); void parseHtmlHead(const QString& data); QString readEXTHRecord(const QByteArray& data, quint32& offset); QString decodeString(const QByteArray& data) const; - + QImage getImageFromRecord(int recnum); }; QString DocumentPrivate::decodeString(const QByteArray& data) const @@ -139,7 +146,7 @@ void DocumentPrivate::init() QByteArray mhead=pdb.getRecord(0); dec = Decompressor::create(mhead[1], pdb); if ((int)mhead[12]!=0 || (int)mhead[13]!=0) drm=true; - if (!dec || drm) { + if (!dec) { valid=false; return; } @@ -151,7 +158,7 @@ void DocumentPrivate::init() if (mhead.size()>176) parseEXTH(mhead); // try getting metadata from HTML if nothing or only title was recovered from MOBI and EXTH records - if (metadata.size()<2) parseHtmlHead(decodeString(dec->decompress(pdb.getRecord(1)))); + if (metadata.size()<2 && !drm) parseHtmlHead(decodeString(dec->decompress(pdb.getRecord(1)))); } void DocumentPrivate::findFirstImage() { @@ -177,6 +184,14 @@ QString DocumentPrivate::readEXTHRecord(const QByteArray& data, quint32& offset) return ret; } +QImage DocumentPrivate::getImageFromRecord(int i) +{ + QByteArray rec=pdb.getRecord(i); + QByteArray rec2=pdb.getRecord(i-2); + return QImage::fromData(rec); +} + + void DocumentPrivate::parseEXTH(const QByteArray& data) { // try to get name @@ -201,6 +216,7 @@ void DocumentPrivate::parseEXTH(const QByteArray& data) case 103: metadata[Document::Description]=readEXTHRecord(data,offset); break; case 105: metadata[Document::Subject]=readEXTHRecord(data,offset); break; case 109: metadata[Document::Copyright]=readEXTHRecord(data,offset); break; + case 202: thumbnailIndex = readBELong(data,offset); offset+=4; break; default: readEXTHRecord(data,offset); } } @@ -240,9 +256,7 @@ bool Document::isValid() const QImage Document::getImage(int i) const { if (!d->firstImageRecord) d->findFirstImage(); - QByteArray rec=d->pdb.getRecord(d->firstImageRecord+i-1); - //FIXME: check if i is in range - return QImage::fromData(rec); + return d->getImageFromRecord(d->firstImageRecord+i); } QMap Document::metadata() const @@ -255,4 +269,10 @@ bool Document::hasDRM() const return d->drm; } +QImage Document::thumbnail() const +{ + if (!d->firstImageRecord) d->findFirstImage(); + return d->getImageFromRecord(d->thumbnailIndex+d->firstImageRecord); +} + } diff --git a/mobipocket.h b/mobipocket.h index ea2a408a3..2aa4b73e9 100644 --- a/mobipocket.h +++ b/mobipocket.h @@ -42,9 +42,10 @@ public: QString text() const; int imageCount() const; QImage getImage(int i) const; + QImage thumbnail() const; bool isValid() const; - - // if true then isValid() will return false + + // if true then it is impossible to get text of book. Images should still be readable bool hasDRM() const; private: DocumentPrivate* const d; diff --git a/mobithumbnail.cpp b/mobithumbnail.cpp new file mode 100644 index 000000000..ed1e5fb68 --- /dev/null +++ b/mobithumbnail.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ + +#include "mobithumbnail.h" +#include "mobipocket.h" + +#include + +extern "C" +{ + KDE_EXPORT ThumbCreator *new_creator() + { + return new MobiThumbnail; + } +} + +bool MobiThumbnail::create(const QString &path, int width, int height, QImage &img) +{ + QFile f(path); + f.open(QIODevice::ReadOnly); + Mobipocket::Document doc(&f); + if (!doc.isValid()) return false; + img=doc.thumbnail(); + return !img.isNull(); +} + +ThumbCreator::Flags MobiThumbnail::flags() const +{ + return static_cast(None); +} + diff --git a/mobithumbnail.desktop b/mobithumbnail.desktop new file mode 100644 index 000000000..757d03ba1 --- /dev/null +++ b/mobithumbnail.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Service +Name=Mobipocket thumbnailer +X-KDE-ServiceTypes=ThumbCreator +MimeType=application/x-mobipocket; +X-KDE-Library=mobithumbnail +CacheThumbnail=true + diff --git a/mobithumbnail.h b/mobithumbnail.h new file mode 100644 index 000000000..78c2d7196 --- /dev/null +++ b/mobithumbnail.h @@ -0,0 +1,23 @@ +/*************************************************************************** + * Copyright (C) 2008 by Jakub Stachowski * + * * + * 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. * + ***************************************************************************/ + +#ifndef MOBITHUMBNAIL_H +#define MOBITHUMBNAIL_H + +#include + +class MobiThumbnail : public ThumbCreator +{ +public: + MobiThumbnail() {} + virtual bool create(const QString &path, int, int, QImage &img); + virtual Flags flags() const; +}; + +#endif