File indexing completed on 2024-05-12 16:06:41

0001 /*
0002     SPDX-FileCopyrightText: 2008 Ely Levy <elylevy@cs.huji.ac.il>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "epubdocument.h"
0008 #include <QDir>
0009 #include <QTemporaryFile>
0010 
0011 #include <QRegularExpression>
0012 
0013 Q_LOGGING_CATEGORY(OkularEpuDebug, "org.kde.okular.generators.epu", QtWarningMsg)
0014 using namespace Epub;
0015 
0016 EpubDocument::EpubDocument(const QString &fileName, const QFont &font)
0017     : QTextDocument()
0018     , padding(20)
0019     , mFont(font)
0020 {
0021 #ifdef Q_OS_WIN
0022     mEpub = epub_open(qUtf8Printable(fileName), 2);
0023 #else
0024     mEpub = epub_open(qPrintable(fileName), 2);
0025 #endif
0026 
0027     setPageSize(QSizeF(600, 800));
0028 }
0029 
0030 bool EpubDocument::isValid()
0031 {
0032     return (mEpub ? true : false);
0033 }
0034 
0035 EpubDocument::~EpubDocument()
0036 {
0037     if (mEpub) {
0038         epub_close(mEpub);
0039     }
0040 
0041     epub_cleanup();
0042 }
0043 
0044 struct epub *EpubDocument::getEpub()
0045 {
0046     return mEpub;
0047 }
0048 
0049 void EpubDocument::setCurrentSubDocument(const QString &doc)
0050 {
0051     mCurrentSubDocument.clear();
0052     int index = doc.indexOf(QLatin1Char('/'));
0053     if (index > 0) {
0054         mCurrentSubDocument = QUrl::fromLocalFile(doc.left(index + 1));
0055     }
0056 }
0057 
0058 int EpubDocument::maxContentHeight() const
0059 {
0060     return pageSize().height() - (2 * padding);
0061 }
0062 
0063 int EpubDocument::maxContentWidth() const
0064 {
0065     return pageSize().width() - (2 * padding);
0066 }
0067 
0068 QString EpubDocument::checkCSS(const QString &c)
0069 {
0070     QString css = c;
0071     // remove paragraph line-heights
0072     static const QRegularExpression lineHeightRegex {QStringLiteral("line-height\\s*:\\s*[\\w\\.]*;")};
0073     css.remove(lineHeightRegex);
0074 
0075     // HACK transform em and rem notation to px, because QTextDocument doesn't support
0076     // em and rem.
0077     static const QRegularExpression cssSplitRegex {QStringLiteral("\\s+")};
0078     const QStringList cssArray = css.split(cssSplitRegex);
0079     QStringList cssArrayReplaced;
0080     std::size_t cssArrayCount = cssArray.count();
0081     std::size_t i = 0;
0082     static const QRegularExpression re(QStringLiteral("(([0-9]+)(\\.[0-9]+)?)r?em(.*)"));
0083     while (i < cssArrayCount) {
0084         const auto &item = cssArray[i];
0085         QRegularExpressionMatch match = re.match(item);
0086         if (match.hasMatch()) {
0087             double em = match.captured(1).toDouble();
0088             double px = em * mFont.pointSize();
0089             cssArrayReplaced.append(QStringLiteral("%1px%2").arg(px).arg(match.captured(4)));
0090         } else {
0091             cssArrayReplaced.append(item);
0092         }
0093         i++;
0094     }
0095     return cssArrayReplaced.join(QStringLiteral(" "));
0096 }
0097 
0098 QVariant EpubDocument::loadResource(int type, const QUrl &name)
0099 {
0100     int size;
0101     char *data;
0102 
0103     QString fileInPath = mCurrentSubDocument.resolved(name).path();
0104 
0105     // Get the data from the epub file
0106     size = epub_get_data(mEpub, fileInPath.toUtf8().constData(), &data);
0107 
0108     QVariant resource;
0109 
0110     if (data) {
0111         switch (type) {
0112         case QTextDocument::ImageResource: {
0113             QImage img = QImage::fromData((unsigned char *)data, size);
0114             const int maxHeight = maxContentHeight();
0115             const int maxWidth = maxContentWidth();
0116             if (img.height() > maxHeight) {
0117                 img = img.scaledToHeight(maxHeight, Qt::SmoothTransformation);
0118             }
0119             if (img.width() > maxWidth) {
0120                 img = img.scaledToWidth(maxWidth, Qt::SmoothTransformation);
0121             }
0122             resource.setValue(img);
0123             break;
0124         }
0125         case QTextDocument::StyleSheetResource: {
0126             QString css = QString::fromUtf8(data);
0127             resource.setValue(checkCSS(css));
0128             break;
0129         }
0130         case EpubDocument::MovieResource: {
0131             QTemporaryFile *tmp = new QTemporaryFile(QStringLiteral("%1/okrXXXXXX").arg(QDir::tempPath()), this);
0132             if (!tmp->open()) {
0133                 qCWarning(OkularEpuDebug) << "EPUB : error creating temporary video file";
0134             }
0135             if (tmp->write(data, size) == -1) {
0136                 qCWarning(OkularEpuDebug) << "EPUB : error writing data" << tmp->errorString();
0137             }
0138             tmp->flush();
0139             resource.setValue(tmp->fileName());
0140             break;
0141         }
0142         case EpubDocument::AudioResource: {
0143             QByteArray ba(data, size);
0144             resource.setValue(ba);
0145             break;
0146         }
0147         default:
0148             resource.setValue(QString::fromUtf8(data));
0149             break;
0150         }
0151 
0152         free(data);
0153     }
0154 
0155     // add to cache
0156     addResource(type, name, resource);
0157 
0158     return resource;
0159 }