1 /* poppler-page.cc: qt interface to poppler
2 * Copyright (C) 2005, Net Integration Technologies, Inc.
3 * Copyright (C) 2005-2006, 2010 Albert Astals Cid <aacid@kde.org>
4 * Copyright (C) 2005, Tobias Koening <tokoe@kde.org>
5 * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
6 * Copyright (C) 2006, Wilfried Huss <Wilfried.Huss@gmx.at>
7 * Copyright (C) 2006, Jerry Epplin <jepplin@globalvelocity.com>
8 * Copyright (C) 2007, 2010, Pino Toscano <pino@kde.org>
9 * Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
24 */
25
26 #include <poppler-qt.h>
27 #include <qfile.h>
28 #include <qimage.h>
29 #include <config.h>
30 #include <GlobalParams.h>
31 #include <PDFDoc.h>
32 #include <Catalog.h>
33 #include <ErrorCodes.h>
34 #include <TextOutputDev.h>
35 #include <Link.h>
36 #if defined(HAVE_SPLASH)
37 #include <SplashOutputDev.h>
38 #include <splash/SplashBitmap.h>
39 #endif
40
41 #include "poppler-private.h"
42 #include "poppler-page-transition-private.h"
43
44 namespace Poppler {
45
Page(const Document * doc,int index)46 Page::Page(const Document *doc, int index) {
47 data = new PageData();
48 data->index = index;
49 data->doc = doc;
50 data->transition = 0;
51 data->page = doc->data->doc.getPage(data->index + 1);
52 }
53
~Page()54 Page::~Page()
55 {
56 delete data->transition;
57 delete data;
58 }
59
renderToPixmap(QPixmap ** q,int x,int y,int w,int h,bool doLinks) const60 void Page::renderToPixmap(QPixmap **q, int x, int y, int w, int h, bool doLinks) const
61 {
62 renderToPixmap(q, x, y, w, h, 72.0, 72.0, doLinks);
63 }
64
renderToPixmap(QPixmap ** q,int x,int y,int w,int h,double xres,double yres,bool doLinks) const65 void Page::renderToPixmap(QPixmap **q, int x, int y, int w, int h, double xres, double yres, bool doLinks) const
66 {
67 QImage img = renderToImage(xres, yres, doLinks);
68 *q = new QPixmap( img );
69 }
70
renderToImage(double xres,double yres,bool doLinks) const71 QImage Page::renderToImage(double xres, double yres, bool doLinks) const
72 {
73 #if defined(HAVE_SPLASH)
74 SplashOutputDev *output_dev;
75 SplashBitmap *bitmap;
76 SplashColorPtr color_ptr;
77 output_dev = data->doc->data->getOutputDev();
78
79 data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, xres, yres,
80 0, false, true, false, -1, -1, -1, -1);
81 bitmap = output_dev->getBitmap ();
82 color_ptr = bitmap->getDataPtr ();
83 int bw = output_dev->getBitmap()->getWidth();
84 int bh = output_dev->getBitmap()->getHeight();
85 SplashColorPtr dataPtr = output_dev->getBitmap()->getDataPtr();
86
87 if (QImage::BigEndian == QImage::systemByteOrder())
88 {
89 uchar c;
90 int count = bw * bh * 4;
91 for (int k = 0; k < count; k += 4)
92 {
93 c = dataPtr[k];
94 dataPtr[k] = dataPtr[k+3];
95 dataPtr[k+3] = c;
96
97 c = dataPtr[k+1];
98 dataPtr[k+1] = dataPtr[k+2];
99 dataPtr[k+2] = c;
100 }
101 }
102
103 // construct a qimage SHARING the raw bitmap data in memory
104 QImage img( dataPtr, bw, bh, 32, 0, 0, QImage::IgnoreEndian );
105 img = img.copy();
106 // unload underlying xpdf bitmap
107 output_dev->startPage( 0, NULL );
108
109 return img;
110 #else
111 (void)xres;
112 (void)xres;
113 (void)doLinks;
114
115 return QImage();
116 #endif
117 }
118
getText(const Rectangle & r) const119 QString Page::getText(const Rectangle &r) const
120 {
121 TextOutputDev *output_dev;
122 GooString *s;
123 PDFRectangle *rect;
124 QString result;
125 ::Page *p;
126
127 output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse);
128 data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, 72, 72,
129 0, false, false, false, -1, -1, -1, -1);
130 p = data->page;
131 if (r.isNull())
132 {
133 rect = p->getCropBox();
134 s = output_dev->getText(rect->x1, rect->y1, rect->x2, rect->y2);
135 }
136 else
137 {
138 double height, y1, y2;
139 height = p->getCropHeight();
140 y1 = height - r.m_y2;
141 y2 = height - r.m_y1;
142 s = output_dev->getText(r.m_x1, y1, r.m_x2, y2);
143 }
144
145 result = QString::fromUtf8(s->getCString());
146
147 delete output_dev;
148 delete s;
149 return result;
150 }
151
textList() const152 QValueList<TextBox*> Page::textList() const
153 {
154 TextOutputDev *output_dev;
155
156 QValueList<TextBox*> output_list;
157
158 output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse);
159
160 data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, 72, 72,
161 0, false, false, false, -1, -1, -1, -1);
162
163 TextWordList *word_list = output_dev->makeWordList();
164
165 if (!word_list) {
166 delete output_dev;
167 return output_list;
168 }
169
170 for (int i = 0; i < word_list->getLength(); i++) {
171 TextWord *word = word_list->get(i);
172 GooString *word_str = word->getText();
173 QString string = QString::fromUtf8(word_str->getCString());
174 delete word_str;
175 double xMin, yMin, xMax, yMax;
176 word->getBBox(&xMin, &yMin, &xMax, &yMax);
177
178 TextBox* text_box = new TextBox(string, Rectangle(xMin, yMin, xMax, yMax));
179
180 output_list.append(text_box);
181 }
182
183 delete word_list;
184 delete output_dev;
185
186 return output_list;
187 }
188
getTransition() const189 PageTransition *Page::getTransition() const
190 {
191 if (!data->transition)
192 {
193 Object o;
194 PageTransitionParams params;
195 params.dictObj = data->page->getTrans(&o);
196 data->transition = new PageTransition(params);
197 o.free();
198 }
199 return data->transition;
200 }
201
pageSize() const202 QSize Page::pageSize() const
203 {
204 ::Page *p;
205
206 p = data->page;
207 if ( ( Page::Landscape == orientation() ) || (Page::Seascape == orientation() ) ) {
208 return QSize( (int)p->getCropHeight(), (int)p->getCropWidth() );
209 } else {
210 return QSize( (int)p->getCropWidth(), (int)p->getCropHeight() );
211 }
212 }
213
orientation() const214 Page::Orientation Page::orientation() const
215 {
216 ::Page *p = data->page;
217
218 int rotation = p->getRotate();
219 switch (rotation) {
220 case 90:
221 return Page::Landscape;
222 break;
223 case 180:
224 return Page::UpsideDown;
225 break;
226 case 270:
227 return Page::Seascape;
228 break;
229 default:
230 return Page::Portrait;
231 }
232 }
233
links() const234 QValueList<Link*> Page::links() const
235 {
236 QValueList<Link*> popplerLinks;
237
238 #if defined(HAVE_SPLASH)
239 Links *xpdfLinks = data->doc->data->doc.getLinks(data->index + 1);
240 for (int i = 0; i < xpdfLinks->getNumLinks(); ++i)
241 {
242 ::Link *xpdfLink = xpdfLinks->getLink(i);
243
244 double left, top, right, bottom;
245 int leftAux, topAux, rightAux, bottomAux;
246 xpdfLink->getRect( &left, &top, &right, &bottom );
247 QRect linkArea;
248
249 data->doc->data->m_outputDev->cvtUserToDev( left, top, &leftAux, &topAux );
250 data->doc->data->m_outputDev->cvtUserToDev( right, bottom, &rightAux, &bottomAux );
251 linkArea.setLeft(leftAux);
252 linkArea.setTop(topAux);
253 linkArea.setRight(rightAux);
254 linkArea.setBottom(bottomAux);
255
256 if (!xpdfLink->isOk()) continue;
257
258 Link *popplerLink = NULL;
259 ::LinkAction *a = xpdfLink->getAction();
260 if ( a )
261 {
262 switch ( a->getKind() )
263 {
264 case actionGoTo:
265 {
266 LinkGoTo * g = (LinkGoTo *) a;
267 // create link: no ext file, namedDest, object pointer
268 popplerLink = new LinkGoto( linkArea, QString::null, LinkDestination( LinkDestinationData(g->getDest(), g->getNamedDest(), data->doc->data ) ) );
269 }
270 break;
271
272 case actionGoToR:
273 {
274 LinkGoToR * g = (LinkGoToR *) a;
275 // copy link file
276 const QString fileName = UnicodeParsedString( g->getFileName() );
277 // ceate link: fileName, namedDest, object pointer
278 popplerLink = new LinkGoto( linkArea, fileName, LinkDestination( LinkDestinationData(g->getDest(), g->getNamedDest(), data->doc->data ) ) );
279 }
280 break;
281
282 case actionLaunch:
283 {
284 LinkLaunch * e = (LinkLaunch *)a;
285 GooString * p = e->getParams();
286 popplerLink = new LinkExecute( linkArea, e->getFileName()->getCString(), p ? p->getCString() : 0 );
287 }
288 break;
289
290 case actionNamed:
291 {
292 const char * name = ((LinkNamed *)a)->getName()->getCString();
293 if ( !strcmp( name, "NextPage" ) )
294 popplerLink = new LinkAction( linkArea, LinkAction::PageNext );
295 else if ( !strcmp( name, "PrevPage" ) )
296 popplerLink = new LinkAction( linkArea, LinkAction::PagePrev );
297 else if ( !strcmp( name, "FirstPage" ) )
298 popplerLink = new LinkAction( linkArea, LinkAction::PageFirst );
299 else if ( !strcmp( name, "LastPage" ) )
300 popplerLink = new LinkAction( linkArea, LinkAction::PageLast );
301 else if ( !strcmp( name, "GoBack" ) )
302 popplerLink = new LinkAction( linkArea, LinkAction::HistoryBack );
303 else if ( !strcmp( name, "GoForward" ) )
304 popplerLink = new LinkAction( linkArea, LinkAction::HistoryForward );
305 else if ( !strcmp( name, "Quit" ) )
306 popplerLink = new LinkAction( linkArea, LinkAction::Quit );
307 else if ( !strcmp( name, "GoToPage" ) )
308 popplerLink = new LinkAction( linkArea, LinkAction::GoToPage );
309 else if ( !strcmp( name, "Find" ) )
310 popplerLink = new LinkAction( linkArea, LinkAction::Find );
311 else if ( !strcmp( name, "FullScreen" ) )
312 popplerLink = new LinkAction( linkArea, LinkAction::Presentation );
313 else if ( !strcmp( name, "Close" ) )
314 {
315 // acroread closes the document always, doesnt care whether
316 // its presentation mode or not
317 // popplerLink = new LinkAction( linkArea, LinkAction::EndPresentation );
318 popplerLink = new LinkAction( linkArea, LinkAction::Close );
319 }
320 else
321 {
322 // TODO
323 }
324 }
325 break;
326
327 case actionURI:
328 {
329 popplerLink = new LinkBrowse( linkArea, ((LinkURI *)a)->getURI()->getCString() );
330 }
331 break;
332
333 case actionMovie:
334 case actionSound:
335 case actionRendition:
336 case actionJavaScript:
337 case actionOCGState:
338 break;
339
340 case actionUnknown:
341 break;
342 }
343 }
344
345 if (popplerLink)
346 {
347 popplerLinks.append(popplerLink);
348 }
349 }
350
351 delete xpdfLinks;
352 #endif
353
354 return popplerLinks;
355 }
356
357 }
358