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.
437 lines
14 KiB
437 lines
14 KiB
/*************************************************************************** |
|
* Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> * |
|
* * |
|
* 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 <math.h> |
|
|
|
#include <qfile.h> |
|
#include <qpainter.h> |
|
#include <qpixmap.h> |
|
#include <qsize.h> |
|
#include <qtoolbox.h> |
|
|
|
#include <kactioncollection.h> |
|
#include <kconfigdialog.h> |
|
#include <kdebug.h> |
|
#include <kiconloader.h> |
|
#include <klocale.h> |
|
#include <kmimetype.h> |
|
#include <kprinter.h> |
|
#include <ktempfile.h> |
|
|
|
#include "core/page.h" |
|
#include "core/observer.h" |
|
#include "ui_gssettingswidget.h" |
|
#include "gssettings.h" |
|
|
|
#include "gvlogwindow.h" |
|
#include "interpreter_cmd.h" |
|
#include "internaldocument.h" |
|
#include "interpreter.h" |
|
#include "generator_ghostview.h" |
|
|
|
OKULAR_EXPORT_PLUGIN(GSGenerator) |
|
|
|
GSGenerator::GSGenerator( KPDFDocument * doc ) : |
|
Generator ( doc ), |
|
m_converted(false) |
|
{ |
|
pixGenerator = 0; |
|
asyncGenerator = 0; |
|
internalDoc = 0; |
|
dscForPDF = 0; |
|
m_asyncBusy = false; |
|
m_sRequest=0; |
|
m_asRequest=0; |
|
if ( GSSettings::messages() ) |
|
{ |
|
m_logWindow = new GSLogWindow(); |
|
} |
|
else |
|
m_logWindow = 0; |
|
} |
|
|
|
GSGenerator::~GSGenerator() |
|
{ |
|
delete asyncGenerator; |
|
delete pixGenerator; |
|
} |
|
|
|
void GSGenerator::addPages( KConfigDialog *dlg ) |
|
{ |
|
Ui_GSSettingsWidget gsw; |
|
QWidget* w = new QWidget(0); |
|
gsw.setupUi(w); |
|
dlg->addPage(w, GSSettings::self(), i18n("Ghostscript"), "kghostview", i18n("Ghostscript backend configuration") ); |
|
} |
|
|
|
CDSC_ORIENTATION_ENUM GSGenerator::orientation( int rot ) |
|
{ |
|
Q_ASSERT( rot >= 0 && rot < 4 ); |
|
switch (rot) |
|
{ |
|
case 0: |
|
return CDSC_PORTRAIT; |
|
case 1: |
|
return CDSC_LANDSCAPE; |
|
case 2: |
|
return CDSC_UPSIDEDOWN; |
|
case 3: |
|
return CDSC_SEASCAPE; |
|
} |
|
// get rid of warnings, should never happen |
|
return CDSC_PORTRAIT; |
|
} |
|
|
|
int GSGenerator::rotation ( CDSC_ORIENTATION_ENUM orientation ) |
|
{ |
|
Q_ASSERT( orientation != CDSC_ORIENT_UNKNOWN ); |
|
switch (orientation) |
|
{ |
|
case CDSC_PORTRAIT: |
|
return 0; |
|
case CDSC_LANDSCAPE: |
|
return 1; |
|
case CDSC_UPSIDEDOWN: |
|
return 2; |
|
case CDSC_SEASCAPE: |
|
return 3; |
|
default: ; |
|
} |
|
// get rid of warnings, should never happen |
|
return 0; |
|
} |
|
|
|
// From kghostview |
|
int GSGenerator::angle( CDSC_ORIENTATION_ENUM orientation ) |
|
{ |
|
Q_ASSERT( orientation != CDSC_ORIENT_UNKNOWN ); |
|
int angle = 0; |
|
switch( orientation ) |
|
{ |
|
case CDSC_ORIENT_UNKNOWN: break; // Catched by Q_ASSERT |
|
case CDSC_PORTRAIT: angle = 0; break; |
|
case CDSC_LANDSCAPE: angle = 90; break; |
|
case CDSC_UPSIDEDOWN: angle = 180; break; |
|
case CDSC_SEASCAPE: angle = 270; break; |
|
} |
|
return angle; |
|
} |
|
|
|
inline QString GSGenerator::fileName() { return internalDoc->fileName(); }; |
|
|
|
bool GSGenerator::print( KPrinter& printer ) |
|
{ |
|
KTempFile tf( QString::null, ".ps" ); |
|
if( tf.status() == 0 ) |
|
{ |
|
if ( internalDoc->savePages( tf.name(), printer.pageList() ) ) |
|
{ |
|
return printer.printFiles( QStringList( tf.name() ), true ); |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
bool GSGenerator::loadDocument( const QString & fileName, QVector< KPDFPage * > & pagesVector ) |
|
{ |
|
QString name=fileName; |
|
|
|
bool ps=true; |
|
/* KMimeType::Ptr mime = KMimeType::findByPath (name); |
|
if (mime->name().contains("pdf")) |
|
{ |
|
ps=false; |
|
dscForPDF=new KTempFile( QString::null, ".ps" ); |
|
Q_CHECK_PTR( dscForPDF ); |
|
dscForPDF->setAutoDelete(true); |
|
if( dscForPDF->status() != 0 ) |
|
{ |
|
// error handling here |
|
} |
|
dscForPDF->close(); |
|
QStringList arg; |
|
arg << " " |
|
<< "-q" |
|
<< "-dPARANOIDSAFER" |
|
<< "-dSAFER" |
|
<< "-dDELAYSAFER" |
|
<< "-dNODISPLAY" |
|
<< "-dQUIET" |
|
<< QString("-sPDFname=%1").arg(fileName) |
|
<< QString("-sDSCname=%1").arg(dscForPDF->name()) |
|
<< "-c '<< /PermitFileReading [ InputFile ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe'" |
|
<< "-f pdf2dsc.ps" |
|
<< "-c quit"; |
|
GSInterpreterLib * m_convert=new GSInterpreterLib(); |
|
m_convert->setGhostscriptArguments(arg); |
|
m_convert->start(); |
|
delete m_convert; |
|
m_convert=0; |
|
arg.clear(); |
|
name=dscForPDF->name(); |
|
}*/ |
|
if (! asyncGenerator ) |
|
{ |
|
asyncGenerator= new GSInterpreterCMD ( fileName ); |
|
connect (asyncGenerator, SIGNAL (Finished(QPixmap *)), |
|
this, SLOT(slotAsyncPixmapGenerated (QPixmap *))); |
|
} |
|
if( !pixGenerator ) |
|
{ |
|
pixGenerator = new GSInterpreterLib (); |
|
connect (pixGenerator, SIGNAL (Finished(const QImage*)), |
|
this, SLOT(slotPixmapGenerated (const QImage*))); |
|
|
|
if ( GSSettings::messages() ) |
|
{ |
|
pixGenerator->setBuffered(true); |
|
connect (pixGenerator, SIGNAL (io( GSInterpreterLib::MessageType, const char*, int )), |
|
m_logWindow, SLOT (append(GSInterpreterLib::MessageType, const char*,int))); |
|
} |
|
} |
|
|
|
if ( GSSettings::platformFonts() ) |
|
{ |
|
pixGenerator->setPlatformFonts(false); |
|
asyncGenerator->setPlatformFonts(false); |
|
} |
|
|
|
if ( GSSettings::antialiasing()) |
|
{ |
|
pixGenerator->setAABits(4,2); |
|
asyncGenerator->setAABits(4,2); |
|
} |
|
else |
|
{ |
|
pixGenerator->setAABits(1,1); |
|
asyncGenerator->setAABits(1,1); |
|
} |
|
pixGenerator->setProgressive(false); |
|
// m_pages=pagesVector; |
|
return loadDocumentWithDSC(name,pagesVector,ps); |
|
} |
|
|
|
void GSGenerator::slotPixmapGenerated(const QImage* img) |
|
{ |
|
kWarning() << "SlotSyncGenerated! - finished m_sRequest id=" << m_sRequest->id << " " <<m_sRequest->width << "x" << m_sRequest->height << "@" << m_sRequest->pageNumber << " async == " << m_sRequest->async << endl; |
|
// kWarning() << "sync gen is ready:" << pixGenerator->ready() << endl; |
|
QPixmap * rPix = new QPixmap(); |
|
*rPix = QPixmap::fromImage( *img ); |
|
kWarning() << "unlocking \n"; |
|
syncLock.unlock(); |
|
m_sRequest->page->setPixmap( m_sRequest->id, rPix ); |
|
signalRequestDone( m_sRequest ); |
|
} |
|
|
|
void GSGenerator::slotAsyncPixmapGenerated(QPixmap * pix) |
|
{ |
|
kWarning() << "SlotASyncGenerated!\n"; |
|
m_asRequest->page->setPixmap( m_asRequest->id, pix ); |
|
signalRequestDone( m_asRequest ); |
|
docLock.unlock(); |
|
} |
|
|
|
void GSGenerator::setOrientation(QVector<KPDFPage*>& pages, int rot) |
|
{ |
|
internalDoc->setOrientation(orientation(rot)); |
|
loadPages (pages); |
|
NotifyRequest r(DocumentObserver::Setup, false); |
|
m_document->notifyObservers( &r ); |
|
} |
|
|
|
bool GSGenerator::supportsPaperSizes() |
|
{ |
|
return true; |
|
} |
|
|
|
QStringList GSGenerator::paperSizes() |
|
{ |
|
return GSInternalDocument::paperSizes(); |
|
} |
|
|
|
void GSGenerator::setPaperSize( QVector<KPDFPage*> & pagesVector, int newsize ) |
|
{ |
|
internalDoc->setMedia(paperSizes().at(newsize)); |
|
loadPages(pagesVector); |
|
// FIXME: is it needed to notify the observers? doesn't the document do that already? |
|
NotifyRequest r(DocumentObserver::Setup, false); |
|
m_document->notifyObservers( &r ); |
|
} |
|
|
|
void GSGenerator::setupGUI(KActionCollection * ac , QToolBox * tBox ) |
|
{ |
|
if ( GSSettings::messages() ) |
|
{ |
|
m_box=tBox; |
|
m_box->addItem( m_logWindow, SmallIconSet("queue"), i18n("GhostScript Messages") ); |
|
} |
|
m_actionCollection = ac; |
|
} |
|
|
|
void GSGenerator::freeGUI() |
|
{ |
|
if ( GSSettings::messages() ) |
|
{ |
|
m_box->removeItem(m_box->indexOf(m_logWindow)); |
|
} |
|
} |
|
|
|
bool GSGenerator::loadPages( QVector< KPDFPage * > & pagesVector ) |
|
{ |
|
QSize pSize; |
|
bool atLeastOne=false; |
|
if( internalDoc->dsc()->isStructured() ) |
|
{ |
|
unsigned int i, end=internalDoc->dsc() -> page_count(); |
|
internalDoc->setProlog(qMakePair (internalDoc->dsc()->beginprolog(), |
|
internalDoc->dsc()->endprolog())); |
|
internalDoc->setSetup(qMakePair (internalDoc->dsc()->beginsetup(), |
|
internalDoc->dsc()->endsetup())); |
|
CDSCPAGE * tmpPage; |
|
for ( i=0 ;i < end ; i++ ) |
|
{ |
|
tmpPage=(internalDoc->dsc() -> page() + i); |
|
if (!tmpPage) |
|
{ |
|
kDebug() << "no tmpPage for page nr " << i << endl; |
|
continue; |
|
} |
|
pSize = internalDoc -> computePageSize( internalDoc -> pageMedia( i ) ); |
|
pSize.setHeight((int)ceil(pSize.height()*DPIMod::Y)); |
|
pSize.setWidth((int)ceil(pSize.width()*DPIMod::X)); |
|
pagesVector[i]=new KPDFPage( i, pSize.width(), |
|
pSize.height() , rotation (internalDoc -> orientation(i) ) ); |
|
internalDoc -> insertPageData (i,qMakePair(tmpPage->begin, tmpPage->end)); |
|
atLeastOne=true; |
|
} |
|
} |
|
else |
|
{ |
|
pSize = internalDoc -> computePageSize( internalDoc -> pageMedia() ); |
|
pSize.setHeight((int)ceil(pSize.height()*DPIMod::Y)); |
|
pSize.setWidth((int)ceil(pSize.width()*DPIMod::X)); |
|
QFile f(internalDoc->fileName()); |
|
unsigned long end = f.size(); |
|
internalDoc -> insertPageData (0,qMakePair((unsigned long) 0, end)); |
|
pagesVector.resize(1); |
|
pagesVector[0]=new KPDFPage( 0, pSize.width(), |
|
pSize.height() , rotation (internalDoc -> orientation() ) ); |
|
atLeastOne=true; |
|
} |
|
return atLeastOne; |
|
} |
|
|
|
bool GSGenerator::initInterpreter() |
|
{ |
|
if (! pixGenerator->running()) |
|
{ |
|
if( pixGenerator->start(true) && internalDoc->dsc()->isStructured() ) |
|
{ |
|
kWarning() << "setStructure\n"; |
|
// this 0 is ok here, we will not be getting a PAGE anwser from those |
|
pixGenerator->run ( internalDoc->file() , internalDoc->prolog(), false); |
|
pixGenerator->run ( internalDoc->file() , internalDoc->setup(), false ); |
|
} |
|
} |
|
return pixGenerator->running(); |
|
} |
|
|
|
bool GSGenerator::loadDocumentWithDSC( const QString & name, QVector< KPDFPage * > & pagesVector, bool ps ) |
|
{ |
|
if ( internalDoc ) |
|
{ |
|
// delete the old document to make room for the new one |
|
delete internalDoc; |
|
} |
|
internalDoc = new GSInternalDocument (name, ps ? GSInternalDocument::PS : GSInternalDocument::PDF); |
|
pagesVector.resize( internalDoc->dsc()->page_count() ); |
|
kDebug() << "Page count: " << internalDoc->dsc()->page_count() << endl; |
|
return loadPages (pagesVector); |
|
} |
|
|
|
void GSGenerator::generatePixmap( PixmapRequest * req ) |
|
{ |
|
kWarning() << "receiving req id=" << req->id << " " <<req->width << "x" << req->height << "@" << req->pageNumber << " async == " << req->async << endl; |
|
int pgNo=req->pageNumber; |
|
if ( req->async ) |
|
{ |
|
docLock.lock(); |
|
m_asRequest=req; |
|
kWarning() << "setOrientation\n"; |
|
asyncGenerator->setOrientation(rotation (internalDoc->orientation(pgNo))); |
|
// asyncGenerator->setBoundingBox( internalDoc->boundingBox(i)); |
|
kWarning() << "setSize\n"; |
|
asyncGenerator->setSize(req->width ,req->height); |
|
kWarning() << "setMedia\n"; |
|
asyncGenerator->setMedia( internalDoc -> getPaperSize ( internalDoc -> pageMedia( pgNo )) ); |
|
kWarning() << "setMagnify\n"; |
|
asyncGenerator->setMagnify(qMax(static_cast<double>(req->width)/req->page->width() , |
|
static_cast<double>(req->height)/req->page->height())); |
|
GSInterpreterLib::Position u=internalDoc->pagePos(pgNo); |
|
// kWarning () << "Page pos is " << pgNo << ":"<< u.first << "/" << u.second << endl; |
|
if (!asyncGenerator->interpreterRunning()) |
|
{ |
|
if ( internalDoc->dsc()->isStructured() ) |
|
{ |
|
kWarning() << "setStructure\n"; |
|
asyncGenerator->setStructure( internalDoc->prolog() , internalDoc->setup() ); |
|
} |
|
if (!asyncGenerator->interpreterRunning()) |
|
{ |
|
kWarning() << "start after structure\n"; |
|
asyncGenerator->startInterpreter(); |
|
} |
|
} |
|
kWarning() << "run pagepos\n"; |
|
asyncGenerator->run (internalDoc->pagePos(pgNo)); |
|
} |
|
else |
|
{ |
|
|
|
syncLock.lock(); |
|
// disconnect (pixGenerator, SIGNAL (Finished(const QImage*)), |
|
// this, SLOT(slotPixmapGenerated (const QImage*))); |
|
|
|
pixGenerator->setMedia( internalDoc -> getPaperSize ( internalDoc -> pageMedia( pgNo )) ); |
|
pixGenerator->setMagnify(qMax(static_cast<double>(req->width)/req->page->width() , |
|
static_cast<double>(req->height)/req->page->height())); |
|
pixGenerator->setOrientation(rotation (internalDoc->orientation(pgNo))); |
|
pixGenerator->setSize(req->width ,req->height); |
|
// pixGenerator->setBoundingBox( internalDoc->boundingBox(i)); |
|
|
|
|
|
|
|
if (!pixGenerator->running()) |
|
{ |
|
initInterpreter(); |
|
} |
|
/* connect (pixGenerator, SIGNAL (Finished(const QImage*)), |
|
this, SLOT(slotPixmapGenerated (const QImage*)));*/ |
|
this->m_sRequest=req; |
|
kWarning() << "checking req id=" << req->id << " " <<req->width << "x" << req->height << "@" << req->pageNumber << " async == " << req->async << endl; |
|
kWarning() << "generator running : " << pixGenerator->running() << endl; |
|
pixGenerator->run ( internalDoc->file() , internalDoc->pagePos(pgNo),true); |
|
|
|
} |
|
} |
|
|
|
|
|
bool GSGenerator::canGeneratePixmap( bool async ) |
|
{ |
|
// kWarning () << "ready Async/Sync " << (! docLock.locked()) << "/ " << (( pixGenerator ) ? !syncLock.locked() : true) << " asking for async: " << async << endl; |
|
if (async) return !docLock.locked(); |
|
return !syncLock.locked(); |
|
} |
|
|
|
const DocumentInfo * GSGenerator::generateDocumentInfo() |
|
{ |
|
return internalDoc->generateDocumentInfo(); |
|
} |
|
|
|
#include "generator_ghostview.moc"
|
|
|