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 }