📄 generator_pdf.cpp
字号:
/*************************************************************************** * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> * * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> * * * * 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. * ***************************************************************************/// qt/kde includes#include <qfile.h>#include <qimage.h>#include <qregexp.h>#include <qtextstream.h>#include <kauthorized.h>#include <klocale.h>#include <kpassworddialog.h>#include <kwallet.h>#include <kprinter.h>#include <ktempfile.h>#include <kmessagebox.h>#include <kdebug.h>// local includes#include "generator_pdf.h"#include "core/observer.h" //for PAGEVIEW_ID#include "core/page.h"#include "core/annotations.h"#include "core/pagetransition.h"#include "settings.h"#include <config.h>#include <config-okular.h>class PDFEmbeddedFile : public EmbeddedFile{ public: PDFEmbeddedFile(Poppler::EmbeddedFile *f) : ef(f) { } QString name() const { return ef->name(); } QString description() const { return ef->description(); } QByteArray data() const { return ef->data(); } QDateTime modificationDate() const { return ef->modDate(); } QDateTime creationDate() const { return ef->createDate(); } private: Poppler::EmbeddedFile *ef;};static void fillViewportFromLinkDestination( DocumentViewport &viewport, const Poppler::LinkDestination &destination, const Poppler::Document *pdfdoc ){ viewport.pageNumber = destination.pageNumber() - 1; if (viewport.pageNumber == -1) return; // get destination position // TODO add other attributes to the viewport (taken from link)// switch ( destination->getKind() )// {// case destXYZ: if (destination.isChangeLeft() || destination.isChangeTop()) { Poppler::Page *page = pdfdoc->page( viewport.pageNumber ); // TODO remember to change this if we implement DPI and/or rotation double left, top; left = destination.left(); top = destination.top(); QSize pageSize = page->pageSize(); delete page; viewport.rePos.normalizedX = (double)left / (double)pageSize.width(); viewport.rePos.normalizedY = (double)top / (double)pageSize.height(); viewport.rePos.enabled = true; viewport.rePos.pos = DocumentViewport::TopLeft; } /* TODO if ( dest->getChangeZoom() ) make zoom change*//* break; default: // implement the others cases break;*/// }}static KPDFLink* createKPDFLinkFromPopplerLink(const Poppler::Link *popplerLink, const Poppler::Document *pdfdoc){ KPDFLink *kpdfLink = 0; const Poppler::LinkGoto *popplerLinkGoto; const Poppler::LinkExecute *popplerLinkExecute; const Poppler::LinkBrowse *popplerLinkBrowse; const Poppler::LinkAction *popplerLinkAction; DocumentViewport viewport; switch(popplerLink->linkType()) { case Poppler::Link::None: break; case Poppler::Link::Goto: popplerLinkGoto = static_cast<const Poppler::LinkGoto *>(popplerLink); fillViewportFromLinkDestination( viewport, popplerLinkGoto->destination(), pdfdoc ); kpdfLink = new KPDFLinkGoto(popplerLinkGoto->fileName(), viewport); break; case Poppler::Link::Execute: popplerLinkExecute = static_cast<const Poppler::LinkExecute *>(popplerLink); kpdfLink = new KPDFLinkExecute( popplerLinkExecute->fileName(), popplerLinkExecute->parameters() ); break; case Poppler::Link::Browse: popplerLinkBrowse = static_cast<const Poppler::LinkBrowse *>(popplerLink); kpdfLink = new KPDFLinkBrowse( popplerLinkBrowse->url() ); break; case Poppler::Link::Action: popplerLinkAction = static_cast<const Poppler::LinkAction *>(popplerLink); kpdfLink = new KPDFLinkAction( (KPDFLinkAction::ActionType)popplerLinkAction->actionType() ); break; case Poppler::Link::Movie: // not implemented break; } return kpdfLink;}static QLinkedList<ObjectRect*> generateKPDFLinks( const QList<Poppler::Link*> &popplerLinks, int width, int height, const Poppler::Document *pdfdoc ){ QLinkedList<ObjectRect*> kpdfLinks; foreach(const Poppler::Link *popplerLink, popplerLinks) { QRectF linkArea = popplerLink->linkArea(); double nl = linkArea.left() / (double)width, nt = linkArea.top() / (double)height, nr = linkArea.right() / (double)width, nb = linkArea.bottom() / (double)height; // create the rect using normalized coords and attach the KPDFLink to it ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, false, ObjectRect::Link, createKPDFLinkFromPopplerLink(popplerLink, pdfdoc) ); // add the ObjectRect to the container kpdfLinks.push_front( rect ); } qDeleteAll(popplerLinks); return kpdfLinks;}/** NOTES on threading: * internal: thread race prevention is done via the 'docLock' mutex. the * mutex is needed only because we have the asynchronous thread; else * the operations are all within the 'gui' thread, scheduled by the * Qt scheduler and no mutex is needed. * external: dangerous operations are all locked via mutex internally, and the * only needed external thing is the 'canGeneratePixmap' method * that tells if the generator is free (since we don't want an * internal queue to store PixmapRequests). A generatedPixmap call * without the 'ready' flag set, results in undefined behavior. * So, as example, printing while generating a pixmap asynchronously is safe, * it might only block the gui thread by 1) waiting for the mutex to unlock * in async thread and 2) doing the 'heavy' print operation. */OKULAR_EXPORT_PLUGIN(PDFGenerator)PDFGenerator::PDFGenerator( KPDFDocument * doc ) : Generator( doc ), pdfdoc( 0 ), ready( true ), pixmapRequest( 0 ), docInfoDirty( true ), docSynopsisDirty( true ), docFontsDirty( true ), docEmbeddedFilesDirty( true ){ // update the configuration reparseConfig(); // generate the pixmapGeneratorThread generatorThread = new PDFPixmapGeneratorThread( this ); connect(generatorThread, SIGNAL(finished()), this, SLOT(threadFinished()), Qt::QueuedConnection);}PDFGenerator::~PDFGenerator(){ // stop and delete the generator thread if ( generatorThread ) { generatorThread->wait(); delete generatorThread; }}void PDFGenerator::setOrientation(QVector<KPDFPage*> & pagesVector, int orientation){ loadPages(pagesVector,orientation,true);}//BEGIN Generator inherited functionsbool PDFGenerator::loadDocument( const QString & filePath, QVector<KPDFPage*> & pagesVector ){#ifndef NDEBUG if ( pdfdoc ) { kDebug() << "PDFGenerator: multiple calls to loadDocument. Check it." << endl; return false; }#endif // create PDFDoc for the given file pdfdoc = Poppler::Document::load( filePath, 0, 0 ); // if the file didn't open correctly it might be encrypted, so ask for a pass bool firstInput = true; bool triedWallet = false; KWallet::Wallet * wallet = 0; while ( !pdfdoc && pdfdoc->isLocked() ) { QByteArray password; // 1.A. try to retrieve the first password from the kde wallet system if ( !triedWallet ) { QString walletName = KWallet::Wallet::NetworkWallet(); wallet = KWallet::Wallet::openWallet( walletName ); if ( wallet ) { // use the KPdf folder (and create if missing) if ( !wallet->hasFolder( "KPdf" ) ) wallet->createFolder( "KPdf" ); wallet->setFolder( "KPdf" ); // look for the pass in that folder QString retrievedPass; if ( !wallet->readPassword( filePath.section('/', -1, -1), retrievedPass ) ) password = retrievedPass.toLocal8Bit(); } triedWallet = true; } // 1.B. if not retrieved, ask the password using the kde password dialog if ( password.isNull() ) { QString prompt; if ( firstInput ) prompt = i18n( "Please insert the password to read the document:" ); else prompt = i18n( "Incorrect password. Try again:" ); firstInput = false; // if the user presses cancel, abort opening if ( KPasswordDialog::getPassword( 0, password, prompt ) != KPasswordDialog::Accepted ) break; } // 2. reopen the document using the password pdfdoc->unlock( password, password ); // 3. if the password is correct, store it to the wallet if ( !pdfdoc->isLocked() && wallet && /*safety check*/ wallet->isOpen() ) { QString goodPass = QString::fromLocal8Bit( password.data() ); wallet->writePassword( filePath.section('/', -1, -1), goodPass ); } } if ( !pdfdoc ) { pdfdoc = 0; return false; } // build Pages (currentPage was set -1 by deletePages) uint pageCount = pdfdoc->numPages(); pagesVector.resize(pageCount); loadPages(pagesVector, 0, false); // the file has been loaded correctly return true;}Poppler::Annotation* getPopplerAnnot(Annotation* ann){ if(!ann) return NULL; Poppler::Annotation* resannot; if(ann->subType()==Annotation::AText) { TextAnnotation * a=(TextAnnotation *)ann; Poppler::TextAnnotation * t=new Poppler::TextAnnotation(); resannot=t; t->textType = (Poppler::TextAnnotation::TextType)a->textType; t->textIcon = a->textIcon; t->textFont = a->textFont; t->inplaceAlign = a->inplaceAlign; t->inplaceText = a->inplaceText; t->inplaceIntent = (Poppler::TextAnnotation::InplaceIntent)a->inplaceIntent; for(int i=0;i<3;i++) { t->inplaceCallout[i] = QPointF(a->inplaceCallout[i].x, a->inplaceCallout[i].y); } } else if(ann->subType()==Annotation::ALine) { LineAnnotation *a = (LineAnnotation *)ann; Poppler::LineAnnotation * t=new Poppler::LineAnnotation(); resannot=t; foreach(NormalizedPoint pt, a->linePoints) { t->linePoints.append(QPointF(pt.x, pt.y)); } t->lineStartStyle = (Poppler::LineAnnotation::TermStyle)a->lineStartStyle; t->lineEndStyle = (Poppler::LineAnnotation::TermStyle)a->lineEndStyle; t->lineClosed = a->lineClosed; t->lineInnerColor = a->lineInnerColor; t->lineLeadingFwdPt = a->lineLeadingFwdPt; t->lineLeadingBackPt = a->lineLeadingBackPt; t->lineShowCaption = a->lineShowCaption; t->lineIntent = (Poppler::LineAnnotation::LineIntent)a->lineIntent; } else if(ann->subType()==Annotation::AGeom) { GeomAnnotation *a = (GeomAnnotation*) ann; Poppler::GeomAnnotation * t=new Poppler::GeomAnnotation(); resannot=t; t->geomType = (Poppler::GeomAnnotation::GeomType)a->geomType; t->geomInnerColor = a->geomInnerColor; t->geomWidthPt = a->geomWidthPt; } else if(ann->subType()==Annotation::AHighlight) { HighlightAnnotation *a = (HighlightAnnotation*) ann; Poppler::HighlightAnnotation * t=new Poppler::HighlightAnnotation(); resannot=t; t->highlightType = (Poppler::HighlightAnnotation::HighlightType)a->highlightType; foreach(HighlightAnnotation::Quad ua, a->highlightQuads) { Poppler::HighlightAnnotation::Quad ut; for(int i=0;i<4;i++) { ut.points[i]=QPointF(ua.points[i].x,ua.points[i].y); } ut.capStart=ua.capStart; ut.capEnd=ua.capEnd; ut.feather=ua.feather; t->highlightQuads.append(ut); } } else if(ann->subType()==Annotation::AStamp) { StampAnnotation *a=(StampAnnotation*)ann; Poppler::StampAnnotation * t=new Poppler::StampAnnotation(); resannot=t; t->stampIconName = a->stampIconName; } else if(ann->subType()==Annotation::AInk) { InkAnnotation *a=(InkAnnotation*)ann; Poppler::InkAnnotation * t=new Poppler::InkAnnotation(); resannot=t; foreach(QLinkedList<NormalizedPoint> alist, a->inkPaths) { QLinkedList<QPointF> lt; foreach(NormalizedPoint pa, alist) { lt.append(QPointF(pa.x,pa.y)); } t->inkPaths.append(lt); } } else { resannot=new Poppler::Annotation(); } //COMMON params: resannot->author=ann->author; resannot->contents=ann->contents; resannot->uniqueName=ann->uniqueName; resannot->modifyDate=ann->modifyDate; resannot->creationDate=ann->creationDate; resannot->flags=ann->flags; resannot->boundary=QRectF(ann->boundary.left,ann->boundary.top, ann->boundary.right,ann->boundary.bottom); resannot->style.color=ann->style.color;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -