1 /* poppler-document.cc: qt interface to poppler
2 * Copyright (C) 2005, Net Integration Technologies, Inc.
3 * Copyright (C) 2005-2009, Albert Astals Cid <aacid@kde.org>
4 * Copyright (C) 2006, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
5 * Copyright (C) 2006, Wilfried Huss <Wilfried.Huss@gmx.at>
6 * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
7 *
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)
11 * any later version.
12 *
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.
17 *
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.
21 */
22
23 #include <poppler-qt.h>
24 #include <qfile.h>
25 #include <GlobalParams.h>
26 #include <Outline.h>
27 #include <PDFDoc.h>
28 #include <PSOutputDev.h>
29 #include <Catalog.h>
30 #include <ErrorCodes.h>
31 #include <SplashOutputDev.h>
32 #include <splash/SplashBitmap.h>
33 #include <DateInfo.h>
34 #include "poppler-private.h"
35
36 namespace Poppler {
37
load(const QString & filePath)38 Document *Document::load(const QString &filePath)
39 {
40 if (!globalParams) {
41 globalParams = new GlobalParams();
42 }
43
44 DocumentData *doc = new DocumentData(new GooString(QFile::encodeName(filePath)), NULL);
45 Document *pdoc;
46 if (doc->doc.isOk() || doc->doc.getErrorCode() == errEncrypted) {
47 pdoc = new Document(doc);
48 if (doc->doc.getErrorCode() == errEncrypted)
49 pdoc->data->locked = true;
50 else
51 pdoc->data->locked = false;
52 pdoc->data->m_fontInfoScanner = new FontInfoScanner(&(doc->doc));
53 return pdoc;
54 }
55 else
56 return NULL;
57 }
58
Document(DocumentData * dataA)59 Document::Document(DocumentData *dataA)
60 {
61 data = dataA;
62 }
63
~Document()64 Document::~Document()
65 {
66 delete data;
67 }
68
isLocked() const69 bool Document::isLocked() const
70 {
71 return data->locked;
72 }
73
unlock(const QCString & password)74 bool Document::unlock(const QCString &password)
75 {
76 if (data->locked) {
77 /* racier then it needs to be */
78 GooString *filename = new GooString(data->doc.getFileName());
79 GooString *pwd = new GooString(password.data());
80 DocumentData *doc2 = new DocumentData(filename, pwd);
81 delete pwd;
82 if (!doc2->doc.isOk()) {
83 delete doc2;
84 } else {
85 delete data;
86 data = doc2;
87 data->locked = false;
88 data->m_fontInfoScanner = new FontInfoScanner(&(data->doc));
89 }
90 }
91 return data->locked;
92 }
93
getPageMode(void) const94 Document::PageMode Document::getPageMode(void) const
95 {
96 switch (data->doc.getCatalog()->getPageMode()) {
97 case Catalog::pageModeNone:
98 return UseNone;
99 case Catalog::pageModeOutlines:
100 return UseOutlines;
101 case Catalog::pageModeThumbs:
102 return UseThumbs;
103 case Catalog::pageModeFullScreen:
104 return FullScreen;
105 case Catalog::pageModeOC:
106 return UseOC;
107 default:
108 return UseNone;
109 }
110 }
111
getNumPages() const112 int Document::getNumPages() const
113 {
114 return data->doc.getNumPages();
115 }
116
getPage(int index) const117 Page *Document::getPage(int index) const
118 {
119 Page *p = new Page(this, index);
120 if (p->data->page == NULL) {
121 delete p;
122 return NULL;
123 }
124
125 return p;
126 }
127
fonts() const128 QValueList<FontInfo> Document::fonts() const
129 {
130 QValueList<FontInfo> ourList;
131 scanForFonts(getNumPages(), &ourList);
132 return ourList;
133 }
134
scanForFonts(int numPages,QValueList<FontInfo> * fontList) const135 bool Document::scanForFonts( int numPages, QValueList<FontInfo> *fontList ) const
136 {
137 GooList *items = data->m_fontInfoScanner->scan( numPages );
138
139 if ( NULL == items )
140 return false;
141
142 for ( int i = 0; i < items->getLength(); ++i ) {
143 QString fontName;
144 if (((::FontInfo*)items->get(i))->getName())
145 fontName = ((::FontInfo*)items->get(i))->getName()->getCString();
146
147 FontInfo font(fontName,
148 ((::FontInfo*)items->get(i))->getEmbedded(),
149 ((::FontInfo*)items->get(i))->getSubset(),
150 (Poppler::FontInfo::Type)((::FontInfo*)items->get(i))->getType());
151 fontList->append(font);
152 }
153 deleteGooList(items, ::FontInfo);
154 return true;
155 }
156
157 /* borrowed from kpdf */
getInfo(const QString & type) const158 QString Document::getInfo( const QString & type ) const
159 {
160 // [Albert] Code adapted from pdfinfo.cc on xpdf
161 Object info;
162 if ( data->locked )
163 return NULL;
164
165 data->doc.getDocInfo( &info );
166 if ( !info.isDict() )
167 return NULL;
168
169 QString result;
170 Object obj;
171 GooString *s1;
172 GBool isUnicode;
173 Unicode u;
174 int i;
175 Dict *infoDict = info.getDict();
176
177 if ( infoDict->lookup( (char*)type.latin1(), &obj )->isString() )
178 {
179 s1 = obj.getString();
180 if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getChar(1) & 0xff ) == 0xff )
181 {
182 isUnicode = gTrue;
183 i = 2;
184 }
185 else
186 {
187 isUnicode = gFalse;
188 i = 0;
189 }
190 while ( i < obj.getString()->getLength() )
191 {
192 if ( isUnicode )
193 {
194 u = ( ( s1->getChar(i) & 0xff ) << 8 ) | ( s1->getChar(i+1) & 0xff );
195 i += 2;
196 }
197 else
198 {
199 u = s1->getChar(i) & 0xff;
200 ++i;
201 }
202 result += unicodeToQString( &u, 1 );
203 }
204 obj.free();
205 info.free();
206 return result;
207 }
208 obj.free();
209 info.free();
210 return NULL;
211 }
212
213 /* borrowed from kpdf */
getDate(const QString & type) const214 QDateTime Document::getDate( const QString & type ) const
215 {
216 // [Albert] Code adapted from pdfinfo.cc on xpdf
217 if ( data->locked )
218 return QDateTime();
219
220 Object info;
221 data->doc.getDocInfo( &info );
222 if ( !info.isDict() ) {
223 info.free();
224 return QDateTime();
225 }
226
227 Object obj;
228 int year, mon, day, hour, min, sec, tz_hour, tz_minute;
229 char tz;
230 Dict *infoDict = info.getDict();
231 QString result;
232
233 if ( infoDict->lookup( (char*)type.latin1(), &obj )->isString() )
234 {
235 QString s = UnicodeParsedString(obj.getString());
236 // TODO do something with the timezone information
237 if ( parseDateString( s.latin1(), &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) )
238 {
239 QDate d( year, mon, day ); //CHECK: it was mon-1, Jan->0 (??)
240 QTime t( hour, min, sec );
241 if ( d.isValid() && t.isValid() ) {
242 obj.free();
243 info.free();
244 return QDateTime( d, t );
245 }
246 }
247 }
248 obj.free();
249 info.free();
250 return QDateTime();
251 }
252
isEncrypted() const253 bool Document::isEncrypted() const
254 {
255 return data->doc.isEncrypted();
256 }
257
isLinearized() const258 bool Document::isLinearized() const
259 {
260 return data->doc.isLinearized();
261 }
262
okToPrint() const263 bool Document::okToPrint() const
264 {
265 return data->doc.okToPrint();
266 }
267
okToChange() const268 bool Document::okToChange() const
269 {
270 return data->doc.okToChange();
271 }
272
okToCopy() const273 bool Document::okToCopy() const
274 {
275 return data->doc.okToCopy();
276 }
277
okToAddNotes() const278 bool Document::okToAddNotes() const
279 {
280 return data->doc.okToAddNotes();
281 }
282
getPDFVersion() const283 double Document::getPDFVersion() const
284 {
285 return data->doc.getPDFMajorVersion () + data->doc.getPDFMinorVersion() / 10.0;
286 }
287
getPdfVersion(int * major,int * minor) const288 void Document::getPdfVersion(int *major, int *minor) const
289 {
290 if (major)
291 *major = data->doc.getPDFMajorVersion();
292 if (minor)
293 *minor = data->doc.getPDFMinorVersion();
294 }
295
toc() const296 QDomDocument *Document::toc() const
297 {
298 Outline * outline = data->doc.getOutline();
299 if ( !outline )
300 return NULL;
301
302 GooList * items = outline->getItems();
303 if ( !items || items->getLength() < 1 )
304 return NULL;
305
306 QDomDocument *toc = new QDomDocument();
307 if ( items->getLength() > 0 )
308 data->addTocChildren( toc, toc, items );
309
310 return toc;
311 }
312
linkDestination(const QString & name)313 LinkDestination *Document::linkDestination( const QString &name )
314 {
315 GooString * namedDest = QStringToGooString( name );
316 LinkDestinationData ldd(NULL, namedDest, data);
317 LinkDestination *ld = new LinkDestination(ldd);
318 delete namedDest;
319 return ld;
320 }
321
print(const QString & fileName,QValueList<int> pageList,double hDPI,double vDPI,int rotate)322 bool Document::print(const QString &fileName, QValueList<int> pageList, double hDPI, double vDPI, int rotate)
323 {
324 return print(fileName, pageList, hDPI, vDPI, rotate, -1, -1);
325 }
326
print(const QString & file,QValueList<int> pageList,double hDPI,double vDPI,int rotate,int paperWidth,int paperHeight)327 bool Document::print(const QString &file, QValueList<int> pageList, double hDPI, double vDPI, int rotate, int paperWidth, int paperHeight)
328 {
329 PSOutputDev *psOut = new PSOutputDev(file.latin1(), &(data->doc), data->doc.getXRef(), data->doc.getCatalog(), NULL, 1, data->doc.getNumPages(), psModePS, paperWidth, paperHeight);
330
331 if (psOut->isOk()) {
332 QValueList<int>::iterator it;
333 for (it = pageList.begin(); it != pageList.end(); ++it )
334 data->doc.displayPage(psOut, *it, hDPI, vDPI, rotate, gFalse, gTrue, gTrue);
335
336 delete psOut;
337 return true;
338 } else {
339 delete psOut;
340 return false;
341 }
342 }
343
344 }
345