/*************************************************************************** * Copyright (C) 2007-2008 by Albert Astals Cid * * * * 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 "generator_ghostview.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_gssettingswidget.h" #include "gssettings.h" #include "spectre_debug.h" #include "rendererthread.h" OKULAR_EXPORT_PLUGIN(GSGenerator, "libokularGenerator_ghostview.json") GSGenerator::GSGenerator( QObject *parent, const QVariantList &args ) : Okular::Generator( parent, args ), m_internalDocument(0), m_request(0) { 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("GraphicsAntialias", true, AAgfx) SET_HINT("TextAntialias", 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") ); } bool GSGenerator::print( QPrinter& printer ) { bool result = false; // Create tempfile to write to QTemporaryFile tf(QDir::tempPath() + QLatin1String("/okular_XXXXXX.ps")); // Get list of pages to print QList 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 false; 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 ); int ret = Okular::FilePrinter::printFile( printer, fileName, document()->orientation(), Okular::FilePrinter::SystemDeletesFiles, Okular::FilePrinter::ApplicationSelectsPages, document()->bookmarkedPageRange() ); if ( ret >= 0 ) result = true; } return result; } bool GSGenerator::loadDocument( const QString & fileName, QVector< Okular::Page * > & pagesVector ) { cache_AAtext = documentMetaData(QStringLiteral("TextAntialias"), true).toBool(); cache_AAgfx = documentMetaData(QStringLiteral("GraphicsAntialias"), 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 = 0; 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 = 0; 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 = 0; 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 &keys ) const { Okular::DocumentInfo docInfo; if ( keys.contains( Okular::DocumentInfo::Title ) ) docInfo.set( Okular::DocumentInfo::Title, spectre_document_get_title(m_internalDocument) ); if ( keys.contains( Okular::DocumentInfo::Author ) ) docInfo.set( Okular::DocumentInfo::Author, spectre_document_get_for(m_internalDocument) ); if ( keys.contains( Okular::DocumentInfo::Creator ) ) docInfo.set( Okular::DocumentInfo::Creator, spectre_document_get_creator(m_internalDocument) ); if ( keys.contains( Okular::DocumentInfo::CreationDate ) ) docInfo.set( Okular::DocumentInfo::CreationDate, spectre_document_get_creation_date(m_internalDocument) ); if ( keys.contains( Okular::DocumentInfo::CustomKeys ) ) docInfo.set( QStringLiteral("dscversion"), 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"