You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
12 KiB
303 lines
12 KiB
/* |
|
SPDX-FileCopyrightText: 2007-2008 Albert Astals Cid <aacid@kde.org> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "generator_ghostview.h" |
|
|
|
#include <math.h> |
|
|
|
#include <QFile> |
|
#include <QPainter> |
|
#include <QPixmap> |
|
#include <QPrinter> |
|
#include <QSize> |
|
|
|
#include <KAboutData> |
|
#include <KConfigDialog> |
|
#include <KLocalizedString> |
|
#include <QDebug> |
|
#include <QDir> |
|
#include <QMimeDatabase> |
|
#include <QMimeType> |
|
#include <QTemporaryFile> |
|
|
|
#include <core/document.h> |
|
#include <core/fileprinter.h> |
|
#include <core/page.h> |
|
#include <core/utils.h> |
|
|
|
#include "gssettings.h" |
|
#include "ui_gssettingswidget.h" |
|
|
|
#include "rendererthread.h" |
|
#include "spectre_debug.h" |
|
|
|
OKULAR_EXPORT_PLUGIN(GSGenerator, "libokularGenerator_ghostview.json") |
|
|
|
GSGenerator::GSGenerator(QObject *parent, const QVariantList &args) |
|
: Okular::Generator(parent, args) |
|
, m_internalDocument(nullptr) |
|
, m_request(nullptr) |
|
{ |
|
setFeature(PrintPostscript); |
|
setFeature(PrintToFile); |
|
|
|
GSRendererThread *renderer = GSRendererThread::getCreateRenderer(); |
|
if (!renderer->isRunning()) { |
|
renderer->start(); |
|
} |
|
connect(renderer, &GSRendererThread::imageDone, this, &GSGenerator::slotImageGenerated, Qt::QueuedConnection); |
|
} |
|
|
|
GSGenerator::~GSGenerator() |
|
{ |
|
} |
|
|
|
bool GSGenerator::reparseConfig() |
|
{ |
|
bool changed = false; |
|
if (m_internalDocument) { |
|
#define SET_HINT(hintname, hintdefvalue, hintvar) \ |
|
{ \ |
|
bool newhint = documentMetaData(hintname, hintdefvalue).toBool(); \ |
|
if (newhint != cache_##hintvar) { \ |
|
cache_##hintvar = newhint; \ |
|
changed = true; \ |
|
} \ |
|
} |
|
SET_HINT(GraphicsAntialiasMetaData, true, AAgfx) |
|
SET_HINT(TextAntialiasMetaData, true, AAtext) |
|
#undef SET_HINT |
|
} |
|
return changed; |
|
} |
|
|
|
void GSGenerator::addPages(KConfigDialog *dlg) |
|
{ |
|
Ui_GSSettingsWidget gsw; |
|
QWidget *w = new QWidget(dlg); |
|
gsw.setupUi(w); |
|
dlg->addPage(w, GSSettings::self(), i18n("Ghostscript"), QStringLiteral("okular-gv"), i18n("Ghostscript Backend Configuration")); |
|
} |
|
|
|
Okular::Document::PrintError GSGenerator::print(QPrinter &printer) |
|
{ |
|
// Create tempfile to write to |
|
QTemporaryFile tf(QDir::tempPath() + QLatin1String("/okular_XXXXXX.ps")); |
|
|
|
// Get list of pages to print |
|
QList<int> pageList = Okular::FilePrinter::pageList(printer, spectre_document_get_n_pages(m_internalDocument), document()->currentPage() + 1, document()->bookmarkedPageList()); |
|
|
|
// Default to Postscript export, but if printing to PDF use that instead |
|
SpectreExporterFormat exportFormat = SPECTRE_EXPORTER_FORMAT_PS; |
|
if (printer.outputFileName().right(3) == QLatin1String("pdf")) { |
|
exportFormat = SPECTRE_EXPORTER_FORMAT_PDF; |
|
tf.setFileTemplate(QDir::tempPath() + QLatin1String("/okular_XXXXXX.pdf")); |
|
} |
|
|
|
if (!tf.open()) { |
|
return Okular::Document::TemporaryFileOpenPrintError; |
|
} |
|
|
|
SpectreExporter *exporter = spectre_exporter_new(m_internalDocument, exportFormat); |
|
SpectreStatus exportStatus = spectre_exporter_begin(exporter, tf.fileName().toLatin1().constData()); |
|
|
|
int i = 0; |
|
while (i < pageList.count() && exportStatus == SPECTRE_STATUS_SUCCESS) { |
|
exportStatus = spectre_exporter_do_page(exporter, pageList.at(i) - 1); |
|
i++; |
|
} |
|
|
|
SpectreStatus endStatus = SPECTRE_STATUS_EXPORTER_ERROR; |
|
if (exportStatus == SPECTRE_STATUS_SUCCESS) { |
|
endStatus = spectre_exporter_end(exporter); |
|
} |
|
|
|
spectre_exporter_free(exporter); |
|
|
|
const QString fileName = tf.fileName(); |
|
tf.close(); |
|
|
|
if (exportStatus == SPECTRE_STATUS_SUCCESS && endStatus == SPECTRE_STATUS_SUCCESS) { |
|
tf.setAutoRemove(false); |
|
return Okular::FilePrinter::printFile(printer, fileName, document()->orientation(), Okular::FilePrinter::SystemDeletesFiles, Okular::FilePrinter::ApplicationSelectsPages, document()->bookmarkedPageRange()); |
|
} |
|
|
|
return Okular::Document::UnknownPrintError; |
|
} |
|
|
|
bool GSGenerator::loadDocument(const QString &fileName, QVector<Okular::Page *> &pagesVector) |
|
{ |
|
cache_AAtext = documentMetaData(TextAntialiasMetaData, true).toBool(); |
|
cache_AAgfx = documentMetaData(GraphicsAntialiasMetaData, true).toBool(); |
|
|
|
m_internalDocument = spectre_document_new(); |
|
spectre_document_load(m_internalDocument, QFile::encodeName(fileName).constData()); |
|
const SpectreStatus loadStatus = spectre_document_status(m_internalDocument); |
|
if (loadStatus != SPECTRE_STATUS_SUCCESS) { |
|
qCDebug(OkularSpectreDebug) << "ERR:" << spectre_status_to_string(loadStatus); |
|
spectre_document_free(m_internalDocument); |
|
m_internalDocument = nullptr; |
|
return false; |
|
} |
|
pagesVector.resize(spectre_document_get_n_pages(m_internalDocument)); |
|
qCDebug(OkularSpectreDebug) << "Page count:" << pagesVector.count(); |
|
return loadPages(pagesVector); |
|
} |
|
|
|
bool GSGenerator::doCloseDocument() |
|
{ |
|
spectre_document_free(m_internalDocument); |
|
m_internalDocument = nullptr; |
|
|
|
return true; |
|
} |
|
|
|
void GSGenerator::slotImageGenerated(QImage *img, Okular::PixmapRequest *request) |
|
{ |
|
// This can happen as GSInterpreterCMD is a singleton and on creation signals all the slots |
|
// of all the generators attached to it |
|
if (request != m_request) { |
|
return; |
|
} |
|
|
|
if (!request->page()->isBoundingBoxKnown()) { |
|
updatePageBoundingBox(request->page()->number(), Okular::Utils::imageBoundingBox(img)); |
|
} |
|
|
|
m_request = nullptr; |
|
QPixmap *pix = new QPixmap(QPixmap::fromImage(*img)); |
|
delete img; |
|
request->page()->setPixmap(request->observer(), pix); |
|
signalPixmapRequestDone(request); |
|
} |
|
|
|
bool GSGenerator::loadPages(QVector<Okular::Page *> &pagesVector) |
|
{ |
|
for (uint i = 0; i < spectre_document_get_n_pages(m_internalDocument); i++) { |
|
SpectrePage *page; |
|
int width = 0, height = 0; |
|
SpectreOrientation pageOrientation = SPECTRE_ORIENTATION_PORTRAIT; |
|
page = spectre_document_get_page(m_internalDocument, i); |
|
if (spectre_document_status(m_internalDocument)) { |
|
qCDebug(OkularSpectreDebug) << "Error getting page" << i << spectre_status_to_string(spectre_document_status(m_internalDocument)); |
|
} else { |
|
spectre_page_get_size(page, &width, &height); |
|
pageOrientation = spectre_page_get_orientation(page); |
|
} |
|
spectre_page_free(page); |
|
if (pageOrientation % 2 == 1) { |
|
qSwap(width, height); |
|
} |
|
pagesVector[i] = new Okular::Page(i, width, height, orientation(pageOrientation)); |
|
} |
|
return pagesVector.count() > 0; |
|
} |
|
|
|
void GSGenerator::generatePixmap(Okular::PixmapRequest *req) |
|
{ |
|
qCDebug(OkularSpectreDebug) << "receiving" << *req; |
|
|
|
SpectrePage *page = spectre_document_get_page(m_internalDocument, req->pageNumber()); |
|
|
|
GSRendererThread *renderer = GSRendererThread::getCreateRenderer(); |
|
|
|
GSRendererThreadRequest gsreq(this); |
|
gsreq.spectrePage = page; |
|
gsreq.platformFonts = GSSettings::platformFonts(); |
|
int graphicsAA = 1; |
|
int textAA = 1; |
|
if (cache_AAgfx) { |
|
graphicsAA = 4; |
|
} |
|
if (cache_AAtext) { |
|
textAA = 4; |
|
} |
|
gsreq.textAAbits = textAA; |
|
gsreq.graphicsAAbits = graphicsAA; |
|
|
|
gsreq.orientation = req->page()->orientation(); |
|
if (req->page()->rotation() == Okular::Rotation90 || req->page()->rotation() == Okular::Rotation270) { |
|
gsreq.magnify = qMax((double)req->height() / req->page()->width(), (double)req->width() / req->page()->height()); |
|
} else { |
|
gsreq.magnify = qMax((double)req->width() / req->page()->width(), (double)req->height() / req->page()->height()); |
|
} |
|
gsreq.request = req; |
|
m_request = req; |
|
renderer->addRequest(gsreq); |
|
} |
|
|
|
bool GSGenerator::canGeneratePixmap() const |
|
{ |
|
return !m_request; |
|
} |
|
|
|
Okular::DocumentInfo GSGenerator::generateDocumentInfo(const QSet<Okular::DocumentInfo::Key> &keys) const |
|
{ |
|
Okular::DocumentInfo docInfo; |
|
if (keys.contains(Okular::DocumentInfo::Title)) { |
|
docInfo.set(Okular::DocumentInfo::Title, QString::fromUtf8(spectre_document_get_title(m_internalDocument))); |
|
} |
|
if (keys.contains(Okular::DocumentInfo::Author)) { |
|
docInfo.set(Okular::DocumentInfo::Author, QString::fromUtf8(spectre_document_get_for(m_internalDocument))); |
|
} |
|
if (keys.contains(Okular::DocumentInfo::Creator)) { |
|
docInfo.set(Okular::DocumentInfo::Creator, QString::fromUtf8(spectre_document_get_creator(m_internalDocument))); |
|
} |
|
if (keys.contains(Okular::DocumentInfo::CreationDate)) { |
|
docInfo.set(Okular::DocumentInfo::CreationDate, QString::fromUtf8(spectre_document_get_creation_date(m_internalDocument))); |
|
} |
|
if (keys.contains(Okular::DocumentInfo::CustomKeys)) { |
|
docInfo.set(QStringLiteral("dscversion"), QString::fromUtf8(spectre_document_get_format(m_internalDocument)), i18n("Document version")); |
|
} |
|
|
|
if (keys.contains(Okular::DocumentInfo::MimeType)) { |
|
int languageLevel = spectre_document_get_language_level(m_internalDocument); |
|
if (languageLevel > 0) { |
|
docInfo.set(QStringLiteral("langlevel"), QString::number(languageLevel), i18n("Language Level")); |
|
} |
|
if (spectre_document_is_eps(m_internalDocument)) { |
|
docInfo.set(Okular::DocumentInfo::MimeType, QStringLiteral("image/x-eps")); |
|
} else { |
|
docInfo.set(Okular::DocumentInfo::MimeType, QStringLiteral("application/postscript")); |
|
} |
|
} |
|
|
|
if (keys.contains(Okular::DocumentInfo::Pages)) { |
|
docInfo.set(Okular::DocumentInfo::Pages, QString::number(spectre_document_get_n_pages(m_internalDocument))); |
|
} |
|
|
|
return docInfo; |
|
} |
|
|
|
Okular::Rotation GSGenerator::orientation(SpectreOrientation pageOrientation) const |
|
{ |
|
switch (pageOrientation) { |
|
case SPECTRE_ORIENTATION_PORTRAIT: |
|
return Okular::Rotation0; |
|
case SPECTRE_ORIENTATION_LANDSCAPE: |
|
return Okular::Rotation90; |
|
case SPECTRE_ORIENTATION_REVERSE_PORTRAIT: |
|
return Okular::Rotation180; |
|
case SPECTRE_ORIENTATION_REVERSE_LANDSCAPE: |
|
return Okular::Rotation270; |
|
} |
|
// get rid of warnings, should never happen |
|
return Okular::Rotation0; |
|
} |
|
|
|
QVariant GSGenerator::metaData(const QString &key, const QVariant &option) const |
|
{ |
|
Q_UNUSED(option) |
|
if (key == QLatin1String("DocumentTitle")) { |
|
const char *title = spectre_document_get_title(m_internalDocument); |
|
if (title) { |
|
return QString::fromLatin1(title); |
|
} |
|
} |
|
return QVariant(); |
|
} |
|
|
|
#include "generator_ghostview.moc"
|
|
|