Warning, file /education/cantor/src/lib/renderer.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2012 Martin Kuettler <martin.kuettler@gmail.com> 0004 */ 0005 0006 #include "renderer.h" 0007 0008 #include <QUuid> 0009 #include <QDebug> 0010 #include <QMutex> 0011 0012 #include <config-cantorlib.h> 0013 0014 #include <poppler-qt5.h> 0015 #ifdef LIBSPECTRE_FOUND 0016 #include "libspectre/spectre.h" 0017 #endif 0018 0019 0020 using namespace Cantor; 0021 0022 // We need this, because poppler-qt5 not threadsafe before 0.73.0 and 0.73.0 is too new 0023 // and not common widespread in repositories 0024 static QMutex popplerMutex; 0025 0026 class Cantor::RendererPrivate{ 0027 public: 0028 double scale{1}; 0029 bool useHighRes{false}; 0030 }; 0031 0032 Renderer::Renderer() : d(new RendererPrivate()) 0033 { 0034 } 0035 0036 Renderer::~Renderer() 0037 { 0038 delete d; 0039 } 0040 0041 void Renderer::setScale(qreal scale) 0042 { 0043 d->scale = scale; 0044 } 0045 0046 qreal Renderer::scale() 0047 { 0048 return d->scale; 0049 } 0050 0051 void Renderer::useHighResolution(bool b) 0052 { 0053 d->useHighRes = b; 0054 } 0055 0056 QTextImageFormat Renderer::render(QTextDocument *document, Method method, const QUrl &url, const QString& uuid) 0057 { 0058 QTextImageFormat format; 0059 0060 QUrl internal; 0061 internal.setScheme(QLatin1String("internal")); 0062 internal.setPath(uuid); 0063 0064 QSizeF s = renderToResource(document, method, url, internal); 0065 0066 if(s.isValid()) 0067 { 0068 format.setName(internal.url()); 0069 format.setWidth(s.width()); 0070 format.setHeight(s.height()); 0071 } 0072 0073 return format; 0074 } 0075 0076 QTextImageFormat Renderer::render(QTextDocument *document, const Cantor::LatexRenderer* latex) 0077 { 0078 QTextImageFormat format = render(document, Method::EPS, QUrl::fromLocalFile(latex->imagePath()), latex->uuid()); 0079 0080 if (!format.name().isEmpty()) { 0081 format.setProperty(CantorFormula, latex->method()); 0082 format.setProperty(ImagePath, latex->imagePath()); 0083 format.setProperty(Code, latex->latexCode()); 0084 } 0085 0086 return format; 0087 } 0088 0089 QSizeF Renderer::renderToResource(QTextDocument *document, Method method, const QUrl &url, const QUrl& internal) 0090 { 0091 QSizeF size; 0092 QImage img = renderToImage(url, method, &size); 0093 0094 qDebug() << internal; 0095 document->addResource(QTextDocument::ImageResource, internal, QVariant(img) ); 0096 return size; 0097 } 0098 0099 QImage Renderer::epsRenderToImage(const QUrl& url, double scale, bool useHighRes, QSizeF* size, QString* errorReason) 0100 { 0101 #ifdef LIBSPECTRE_FOUND 0102 SpectreDocument* doc = spectre_document_new(); 0103 SpectreRenderContext* rc = spectre_render_context_new(); 0104 0105 qDebug() << "rendering eps file: " << url; 0106 QByteArray local_file = url.toLocalFile().toUtf8(); 0107 spectre_document_load(doc, local_file.data()); 0108 0109 bool isEps = spectre_document_is_eps(doc); 0110 if (!isEps) 0111 { 0112 if (errorReason) 0113 *errorReason = QString::fromLatin1("Error: spectre document is not eps! It means, that url is invalid"); 0114 return QImage(); 0115 } 0116 0117 int wdoc, hdoc; 0118 qreal w, h; 0119 double realScale; 0120 spectre_document_get_page_size(doc, &wdoc, &hdoc); 0121 if(useHighRes) { 0122 realScale = 1.2*4.0; //1.2 scaling factor, to make it look nice, 4x for high resolution 0123 w = 1.2 * wdoc; 0124 h = 1.2 * hdoc; 0125 } else { 0126 realScale=1.8*scale; 0127 w = 1.8 * wdoc; 0128 h = 1.8 * hdoc; 0129 } 0130 0131 qDebug()<<"scale: "<<realScale; 0132 0133 qDebug()<<"dimension: "<<w<<"x"<<h; 0134 unsigned char* data; 0135 int rowLength; 0136 0137 spectre_render_context_set_scale(rc, realScale, realScale); 0138 spectre_document_render_full( doc, rc, &data, &rowLength); 0139 0140 QImage img(data, wdoc*realScale, hdoc*realScale, rowLength, QImage::Format_RGB32); 0141 spectre_document_free(doc); 0142 spectre_render_context_free(rc); 0143 img = img.convertToFormat(QImage::Format_ARGB32); 0144 0145 if (size) 0146 *size = QSizeF(w,h); 0147 return img; 0148 #else 0149 if (errorReason) 0150 *errorReason = QString::fromLatin1("Render Eps on Cantor without eps support (libspectre)!"); 0151 0152 Q_UNUSED(url); 0153 Q_UNUSED(scale); 0154 Q_UNUSED(useHighRes); 0155 Q_UNUSED(size); 0156 return QImage(); 0157 #endif 0158 } 0159 0160 QImage Renderer::pdfRenderToImage(const QUrl& url, double scale, bool highResolution, QSizeF* size, QString* errorReason) 0161 { 0162 popplerMutex.lock(); 0163 Poppler::Document* document = Poppler::Document::load(url.toLocalFile()); 0164 popplerMutex.unlock(); 0165 if (document == nullptr) 0166 { 0167 if (errorReason) 0168 *errorReason = QString::fromLatin1("Poppler library have failed to open file % as pdf").arg(url.toLocalFile()); 0169 return QImage(); 0170 } 0171 0172 Poppler::Page* pdfPage = document->page(0); 0173 if (pdfPage == nullptr) { 0174 if (errorReason) 0175 *errorReason = QString::fromLatin1("Poppler library failed to access first page of %1 document").arg(url.toLocalFile()); 0176 0177 delete document; 0178 return QImage(); 0179 } 0180 0181 QSize pageSize = pdfPage->pageSize(); 0182 0183 double realScale = 1.7 * 1.8; 0184 qreal w = 1.7 * pageSize.width(); 0185 qreal h = 1.7 * pageSize.height(); 0186 if(highResolution) 0187 realScale *= 5; 0188 else 0189 realScale *= scale; 0190 0191 0192 QImage image = pdfPage->renderToImage(72.0*realScale, 72.0*realScale); 0193 0194 delete pdfPage; 0195 popplerMutex.lock(); 0196 delete document; 0197 popplerMutex.unlock(); 0198 0199 if (image.isNull()) 0200 { 0201 if (errorReason) 0202 *errorReason = QString::fromLatin1("Poppler library failed to render pdf %1 to image").arg(url.toLocalFile()); 0203 0204 return image; 0205 } 0206 0207 // Resize with smooth transformation for more beautiful result 0208 image = image.convertToFormat(QImage::Format_ARGB32).scaled(image.size()/1.8, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0209 0210 if (size) 0211 *size = QSizeF(w, h); 0212 return image; 0213 } 0214 0215 0216 QImage Renderer::renderToImage(const QUrl& url, Method method, QSizeF* size) 0217 { 0218 switch(method) 0219 { 0220 case Method::PDF: 0221 return pdfRenderToImage(url, d->scale, d->useHighRes, size); 0222 0223 case Method::EPS: 0224 return epsRenderToImage(url, d->scale, d->useHighRes, size); 0225 0226 default: 0227 return QImage(); 0228 } 0229 }