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