1
/* poppler-document.cc: qt interface to poppler
2
* Copyright (C) 2005, Net Integration Technologies, Inc.
3
* Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
4
* Copyright (C) 2005-2010, Albert Astals Cid <aacid@kde.org>
5
* Copyright (C) 2006-2010, Pino Toscano <pino@kde.org>
6
* Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2, or (at your option)
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
23
#include "poppler-qt4.h"
26
#include <ErrorCodes.h>
27
#include <GlobalParams.h>
35
#include <QtCore/QDebug>
36
#include <QtCore/QFile>
37
#include <QtCore/QByteArray>
39
#include "poppler-private.h"
40
#include "poppler-page-private.h"
48
int DocumentData::count = 0;
50
Document *Document::load(const QString &filePath, const QByteArray &ownerPassword,
51
const QByteArray &userPassword)
53
DocumentData *doc = new DocumentData(new GooString(QFile::encodeName(filePath)),
54
new GooString(ownerPassword.data()),
55
new GooString(userPassword.data()));
56
return DocumentData::checkDocument(doc);
59
Document *Document::loadFromData(const QByteArray &fileContents,
60
const QByteArray &ownerPassword,
61
const QByteArray &userPassword)
64
DocumentData *doc = new DocumentData(fileContents,
65
new GooString(ownerPassword.data()),
66
new GooString(userPassword.data()));
67
return DocumentData::checkDocument(doc);
70
Document *DocumentData::checkDocument(DocumentData *doc)
73
if (doc->doc->isOk() || doc->doc->getErrorCode() == errEncrypted) {
74
pdoc = new Document(doc);
75
if (doc->doc->getErrorCode() == errEncrypted)
76
pdoc->m_doc->locked = true;
79
pdoc->m_doc->locked = false;
80
pdoc->m_doc->fillMembers();
91
Document::Document(DocumentData *dataA)
101
Page *Document::page(int index) const
103
Page *page = new Page(m_doc, index);
104
if (page->m_page->page == NULL) {
112
bool Document::isLocked() const
114
return m_doc->locked;
117
bool Document::unlock(const QByteArray &ownerPassword,
118
const QByteArray &userPassword)
121
/* racier then it needs to be */
123
if (!m_doc->fileContents.isEmpty())
125
doc2 = new DocumentData(m_doc->fileContents,
126
new GooString(ownerPassword.data()),
127
new GooString(userPassword.data()));
131
doc2 = new DocumentData(new GooString(m_doc->doc->getFileName()),
132
new GooString(ownerPassword.data()),
133
new GooString(userPassword.data()));
135
if (!doc2->doc->isOk()) {
140
m_doc->locked = false;
141
m_doc->fillMembers();
144
return m_doc->locked;
147
Document::PageMode Document::pageMode() const
149
switch (m_doc->doc->getCatalog()->getPageMode()) {
150
case Catalog::pageModeNone:
152
case Catalog::pageModeOutlines:
154
case Catalog::pageModeThumbs:
156
case Catalog::pageModeFullScreen:
158
case Catalog::pageModeOC:
160
case Catalog::pageModeAttach:
167
Document::PageLayout Document::pageLayout() const
169
switch (m_doc->doc->getCatalog()->getPageLayout()) {
170
case Catalog::pageLayoutNone:
172
case Catalog::pageLayoutSinglePage:
174
case Catalog::pageLayoutOneColumn:
176
case Catalog::pageLayoutTwoColumnLeft:
177
return TwoColumnLeft;
178
case Catalog::pageLayoutTwoColumnRight:
179
return TwoColumnRight;
180
case Catalog::pageLayoutTwoPageLeft:
182
case Catalog::pageLayoutTwoPageRight:
189
int Document::numPages() const
191
return m_doc->doc->getNumPages();
194
QList<FontInfo> Document::fonts() const
196
QList<FontInfo> ourList;
197
FontIterator it( 0, m_doc );
198
while ( it.hasNext() )
200
ourList += it.next();
205
QList<EmbeddedFile*> Document::embeddedFiles() const
207
return m_doc->m_embeddedFiles;
210
bool Document::scanForFonts( int numPages, QList<FontInfo> *fontList ) const
212
if ( !m_doc->m_fontInfoIterator )
214
if ( !m_doc->m_fontInfoIterator->hasNext() )
216
while ( m_doc->m_fontInfoIterator->hasNext() && numPages )
218
(*fontList) += m_doc->m_fontInfoIterator->next();
224
FontIterator* Document::newFontIterator( int startPage ) const
226
return new FontIterator( startPage, m_doc );
229
QByteArray Document::fontData(const FontInfo &fi) const
234
Object refObj, strObj;
235
refObj.initRef(fi.m_data->embRef.num, fi.m_data->embRef.gen);
236
refObj.fetch(m_doc->doc->getXRef(), &strObj);
238
if (strObj.isStream())
241
strObj.streamReset();
242
while ((c = strObj.streamGetChar()) != EOF)
244
result.append((char)c);
246
strObj.streamClose();
253
/* borrowed from kpdf */
254
QString Document::info( const QString & type ) const
256
// [Albert] Code adapted from pdfinfo.cc on xpdf
261
m_doc->doc->getDocInfo( &info );
262
if ( !info.isDict() )
268
Dict *infoDict = info.getDict();
270
if ( infoDict->lookup( type.toLatin1().data(), &obj )->isString() )
272
s1 = obj.getString();
273
result = UnicodeParsedString(s1);
283
QStringList Document::infoKeys() const
289
return QStringList();
291
m_doc->doc->getDocInfo( &info );
292
if ( !info.isDict() )
293
return QStringList();
295
Dict *infoDict = info.getDict();
296
// somehow iterate over keys in infoDict
297
for( int i=0; i < infoDict->getLength(); ++i ) {
298
keys.append( QString::fromAscii(infoDict->getKey(i)) );
305
/* borrowed from kpdf */
306
QDateTime Document::date( const QString & type ) const
308
// [Albert] Code adapted from pdfinfo.cc on xpdf
313
m_doc->doc->getDocInfo( &info );
314
if ( !info.isDict() ) {
320
Dict *infoDict = info.getDict();
323
if ( infoDict->lookup( type.toLatin1().data(), &obj )->isString() )
325
char *aux = obj.getString()->getCString();
326
result = Poppler::convertDate(aux);
333
bool Document::isEncrypted() const
335
return m_doc->doc->isEncrypted();
338
bool Document::isLinearized() const
340
return m_doc->doc->isLinearized();
343
bool Document::okToPrint() const
345
return m_doc->doc->okToPrint();
348
bool Document::okToPrintHighRes() const
350
return m_doc->doc->okToPrintHighRes();
353
bool Document::okToChange() const
355
return m_doc->doc->okToChange();
358
bool Document::okToCopy() const
360
return m_doc->doc->okToCopy();
363
bool Document::okToAddNotes() const
365
return m_doc->doc->okToAddNotes();
368
bool Document::okToFillForm() const
370
return m_doc->doc->okToFillForm();
373
bool Document::okToCreateFormFields() const
375
return ( okToFillForm() && okToChange() );
378
bool Document::okToExtractForAccessibility() const
380
return m_doc->doc->okToAccessibility();
383
bool Document::okToAssemble() const
385
return m_doc->doc->okToAssemble();
388
double Document::pdfVersion() const
390
return m_doc->doc->getPDFMajorVersion () + m_doc->doc->getPDFMinorVersion() / 10.0;
393
void Document::getPdfVersion(int *major, int *minor) const
396
*major = m_doc->doc->getPDFMajorVersion();
398
*minor = m_doc->doc->getPDFMinorVersion();
401
Page *Document::page(const QString &label) const
403
GooString label_g(label.toAscii().data());
406
if (!m_doc->doc->getCatalog()->labelToIndex (&label_g, &index))
412
bool Document::hasEmbeddedFiles() const
414
return (!(0 == m_doc->doc->getCatalog()->numEmbeddedFiles()));
417
QDomDocument *Document::toc() const
419
Outline * outline = m_doc->doc->getOutline();
423
GooList * items = outline->getItems();
424
if ( !items || items->getLength() < 1 )
427
QDomDocument *toc = new QDomDocument();
428
if ( items->getLength() > 0 )
429
m_doc->addTocChildren( toc, toc, items );
434
LinkDestination *Document::linkDestination( const QString &name )
436
GooString * namedDest = QStringToGooString( name );
437
LinkDestinationData ldd(NULL, namedDest, m_doc, false);
438
LinkDestination *ld = new LinkDestination(ldd);
443
void Document::setPaperColor(const QColor &color)
445
m_doc->setPaperColor(color);
448
void Document::setColorDisplayProfile(void* outputProfileA)
451
GfxColorSpace::setDisplayProfile((cmsHPROFILE)outputProfileA);
453
Q_UNUSED(outputProfileA);
457
void Document::setColorDisplayProfileName(const QString &name)
460
GooString *profileName = QStringToGooString( name );
461
GfxColorSpace::setDisplayProfileName(profileName);
468
void* Document::colorRgbProfile() const
471
return (void*)GfxColorSpace::getRGBProfile();
477
void* Document::colorDisplayProfile() const
480
return (void*)GfxColorSpace::getDisplayProfile();
486
QColor Document::paperColor() const
488
return m_doc->paperColor;
491
void Document::setRenderBackend( Document::RenderBackend backend )
493
// no need to delete the outputdev as for the moment we always create a splash one
494
// as the arthur one does not allow "precaching" due to it's signature
495
// delete m_doc->m_outputDev;
496
// m_doc->m_outputDev = NULL;
497
m_doc->m_backend = backend;
500
Document::RenderBackend Document::renderBackend() const
502
return m_doc->m_backend;
505
QSet<Document::RenderBackend> Document::availableRenderBackends()
507
QSet<Document::RenderBackend> ret;
508
#if defined(HAVE_SPLASH)
509
ret << Document::SplashBackend;
511
ret << Document::ArthurBackend;
515
void Document::setRenderHint( Document::RenderHint hint, bool on )
518
m_doc->m_hints |= hint;
520
m_doc->m_hints &= ~(int)hint;
522
// the only way to set antialiasing for Splash is on creation
523
if ( m_doc->m_backend == Document::SplashBackend &&
524
( hint & ( Document::Antialiasing || Document::TextAntialiasing || Document::TextHinting ) ) )
526
delete m_doc->m_outputDev;
527
m_doc->m_outputDev = NULL;
531
Document::RenderHints Document::renderHints() const
533
return Document::RenderHints( m_doc->m_hints );
536
PSConverter *Document::psConverter() const
538
return new PSConverter(m_doc);
541
PDFConverter *Document::pdfConverter() const
543
return new PDFConverter(m_doc);
546
QString Document::metadata() const
549
Catalog *catalog = m_doc->doc->getCatalog();
550
if (catalog && catalog->isOk())
552
GooString *s = catalog->readMetadata();
553
if (s) result = UnicodeParsedString(s);
559
bool Document::hasOptionalContent() const
561
return ( m_doc->doc->getOptContentConfig() && m_doc->doc->getOptContentConfig()->hasOCGs() );
564
OptContentModel *Document::optionalContentModel()
566
if (m_doc->m_optContentModel.isNull()) {
567
m_doc->m_optContentModel = new OptContentModel(m_doc->doc->getOptContentConfig(), 0);
569
return (OptContentModel *)m_doc->m_optContentModel;
572
QStringList Document::scripts() const
574
Catalog *catalog = m_doc->doc->getCatalog();
575
const int numScripts = catalog->numJS();
577
for (int i = 0; i < numScripts; ++i) {
578
GooString *s = catalog->getJS(i);
580
scripts.append(UnicodeParsedString(s));
587
bool Document::getPdfId(QByteArray *permanentId, QByteArray *updateId) const
589
GooString gooPermanentId;
590
GooString gooUpdateId;
592
if (!m_doc->doc->getID(permanentId ? &gooPermanentId : 0, updateId ? &gooUpdateId : 0))
596
*permanentId = gooPermanentId.getCString();
598
*updateId = gooUpdateId.getCString();
603
QDateTime convertDate( char *dateString )
605
int year, mon, day, hour, min, sec, tzHours, tzMins;
608
if ( parseDateString( dateString, &year, &mon, &day, &hour, &min, &sec, &tz, &tzHours, &tzMins ) )
610
QDate d( year, mon, day );
611
QTime t( hour, min, sec );
612
if ( d.isValid() && t.isValid() ) {
613
QDateTime dt( d, t, Qt::UTC );
615
// then we have some form of timezone
617
// We are already at UTC
618
} else if ( '+' == tz ) {
619
// local time is ahead of UTC
620
dt = dt.addSecs(-1*((tzHours*60)+tzMins)*60);
621
} else if ( '-' == tz ) {
622
// local time is behind UTC
623
dt = dt.addSecs(((tzHours*60)+tzMins)*60);
625
qWarning("unexpected tz val");
634
bool isCmsAvailable()