| /* poppler-page.cc: qt interface to poppler |
| * Copyright (C) 2005, Net Integration Technologies, Inc. |
| * Copyright (C) 2005-2006, Albert Astals Cid <aacid@kde.org> |
| * Copyright (C) 2005, Tobias Koening <tokoe@kde.org> |
| * Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de> |
| * Copyright (C) 2006, Wilfried Huss <Wilfried.Huss@gmx.at> |
| * Copyright (C) 2006, Jerry Epplin <jepplin@globalvelocity.com> |
| * Copyright (C) 2007, Pino Toscano <pino@kde.org> |
| * |
| * 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, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <poppler-qt.h> |
| #include <qfile.h> |
| #include <qimage.h> |
| #include <config.h> |
| #include <GlobalParams.h> |
| #include <PDFDoc.h> |
| #include <Catalog.h> |
| #include <ErrorCodes.h> |
| #include <TextOutputDev.h> |
| #include <Link.h> |
| #if defined(HAVE_SPLASH) |
| #include <SplashOutputDev.h> |
| #include <splash/SplashBitmap.h> |
| #endif |
| |
| #include "poppler-private.h" |
| #include "poppler-page-transition-private.h" |
| |
| namespace Poppler { |
| |
| class PageData { |
| public: |
| const Document *doc; |
| int index; |
| PageTransition *transition; |
| }; |
| |
| Page::Page(const Document *doc, int index) { |
| data = new PageData(); |
| data->index = index; |
| data->doc = doc; |
| data->transition = 0; |
| } |
| |
| Page::~Page() |
| { |
| delete data->transition; |
| delete data; |
| } |
| |
| void Page::renderToPixmap(QPixmap **q, int x, int y, int w, int h, bool doLinks) const |
| { |
| renderToPixmap(q, x, y, w, h, 72.0, 72.0, doLinks); |
| } |
| |
| void Page::renderToPixmap(QPixmap **q, int x, int y, int w, int h, double xres, double yres, bool doLinks) const |
| { |
| QImage img = renderToImage(xres, yres, doLinks); |
| *q = new QPixmap( img ); |
| } |
| |
| QImage Page::renderToImage(double xres, double yres, bool doLinks) const |
| { |
| #if defined(HAVE_SPLASH) |
| SplashOutputDev *output_dev; |
| SplashBitmap *bitmap; |
| SplashColorPtr color_ptr; |
| output_dev = data->doc->data->getOutputDev(); |
| |
| data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, xres, yres, |
| 0, false, true, false, -1, -1, -1, -1); |
| bitmap = output_dev->getBitmap (); |
| color_ptr = bitmap->getDataPtr (); |
| int bw = output_dev->getBitmap()->getWidth(); |
| int bh = output_dev->getBitmap()->getHeight(); |
| SplashColorPtr dataPtr = output_dev->getBitmap()->getDataPtr(); |
| |
| if (QImage::BigEndian == QImage::systemByteOrder()) |
| { |
| uchar c; |
| int count = bw * bh * 4; |
| for (int k = 0; k < count; k += 4) |
| { |
| c = dataPtr[k]; |
| dataPtr[k] = dataPtr[k+3]; |
| dataPtr[k+3] = c; |
| |
| c = dataPtr[k+1]; |
| dataPtr[k+1] = dataPtr[k+2]; |
| dataPtr[k+2] = c; |
| } |
| } |
| |
| // construct a qimage SHARING the raw bitmap data in memory |
| QImage img( dataPtr, bw, bh, 32, 0, 0, QImage::IgnoreEndian ); |
| img = img.copy(); |
| // unload underlying xpdf bitmap |
| output_dev->startPage( 0, NULL ); |
| |
| return img; |
| #else |
| (void)xres; |
| (void)xres; |
| (void)doLinks; |
| |
| return QImage(); |
| #endif |
| } |
| |
| QString Page::getText(const Rectangle &r) const |
| { |
| TextOutputDev *output_dev; |
| GooString *s; |
| PDFRectangle *rect; |
| QString result; |
| ::Page *p; |
| |
| output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse); |
| data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, 72, 72, |
| 0, false, false, false, -1, -1, -1, -1); |
| p = data->doc->data->doc.getCatalog()->getPage(data->index + 1); |
| if (r.isNull()) |
| { |
| rect = p->getCropBox(); |
| s = output_dev->getText(rect->x1, rect->y1, rect->x2, rect->y2); |
| } |
| else |
| { |
| double height, y1, y2; |
| height = p->getCropHeight(); |
| y1 = height - r.m_y2; |
| y2 = height - r.m_y1; |
| s = output_dev->getText(r.m_x1, y1, r.m_x2, y2); |
| } |
| |
| result = QString::fromUtf8(s->getCString()); |
| |
| delete output_dev; |
| delete s; |
| return result; |
| } |
| |
| QValueList<TextBox*> Page::textList() const |
| { |
| TextOutputDev *output_dev; |
| |
| QValueList<TextBox*> output_list; |
| |
| output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse); |
| |
| data->doc->data->doc.displayPageSlice(output_dev, data->index + 1, 72, 72, |
| 0, false, false, false, -1, -1, -1, -1); |
| |
| TextWordList *word_list = output_dev->makeWordList(); |
| |
| if (!word_list) { |
| delete output_dev; |
| return output_list; |
| } |
| |
| for (int i = 0; i < word_list->getLength(); i++) { |
| TextWord *word = word_list->get(i); |
| GooString *word_str = word->getText(); |
| QString string = QString::fromUtf8(word_str->getCString()); |
| delete word_str; |
| double xMin, yMin, xMax, yMax; |
| word->getBBox(&xMin, &yMin, &xMax, &yMax); |
| |
| TextBox* text_box = new TextBox(string, Rectangle(xMin, yMin, xMax, yMax)); |
| |
| output_list.append(text_box); |
| } |
| |
| delete word_list; |
| delete output_dev; |
| |
| return output_list; |
| } |
| |
| PageTransition *Page::getTransition() const |
| { |
| if (!data->transition) |
| { |
| Object o; |
| PageTransitionParams params; |
| params.dictObj = data->doc->data->doc.getCatalog()->getPage(data->index + 1)->getTrans(&o); |
| data->transition = new PageTransition(params); |
| o.free(); |
| } |
| return data->transition; |
| } |
| |
| QSize Page::pageSize() const |
| { |
| ::Page *p; |
| |
| p = data->doc->data->doc.getCatalog()->getPage(data->index + 1); |
| if ( ( Page::Landscape == orientation() ) || (Page::Seascape == orientation() ) ) { |
| return QSize( (int)p->getCropHeight(), (int)p->getCropWidth() ); |
| } else { |
| return QSize( (int)p->getCropWidth(), (int)p->getCropHeight() ); |
| } |
| } |
| |
| Page::Orientation Page::orientation() const |
| { |
| ::Page *p = data->doc->data->doc.getCatalog()->getPage(data->index + 1); |
| |
| int rotation = p->getRotate(); |
| switch (rotation) { |
| case 90: |
| return Page::Landscape; |
| break; |
| case 180: |
| return Page::UpsideDown; |
| break; |
| case 270: |
| return Page::Seascape; |
| break; |
| default: |
| return Page::Portrait; |
| } |
| } |
| |
| QValueList<Link*> Page::links() const |
| { |
| QValueList<Link*> popplerLinks; |
| |
| #if defined(HAVE_SPLASH) |
| Links *xpdfLinks = data->doc->data->doc.getLinks(data->index + 1); |
| for (int i = 0; i < xpdfLinks->getNumLinks(); ++i) |
| { |
| ::Link *xpdfLink = xpdfLinks->getLink(i); |
| |
| double left, top, right, bottom; |
| int leftAux, topAux, rightAux, bottomAux; |
| xpdfLink->getRect( &left, &top, &right, &bottom ); |
| QRect linkArea; |
| |
| data->doc->data->m_outputDev->cvtUserToDev( left, top, &leftAux, &topAux ); |
| data->doc->data->m_outputDev->cvtUserToDev( right, bottom, &rightAux, &bottomAux ); |
| linkArea.setLeft(leftAux); |
| linkArea.setTop(topAux); |
| linkArea.setRight(rightAux); |
| linkArea.setBottom(bottomAux); |
| |
| if (!xpdfLink->isOk()) continue; |
| |
| Link *popplerLink = NULL; |
| ::LinkAction *a = xpdfLink->getAction(); |
| if ( a ) |
| { |
| switch ( a->getKind() ) |
| { |
| case actionGoTo: |
| { |
| LinkGoTo * g = (LinkGoTo *) a; |
| // create link: no ext file, namedDest, object pointer |
| popplerLink = new LinkGoto( linkArea, QString::null, LinkDestination( LinkDestinationData(g->getDest(), g->getNamedDest(), data->doc->data ) ) ); |
| } |
| break; |
| |
| case actionGoToR: |
| { |
| LinkGoToR * g = (LinkGoToR *) a; |
| // copy link file |
| const QString fileName = UnicodeParsedString( g->getFileName() ); |
| // ceate link: fileName, namedDest, object pointer |
| popplerLink = new LinkGoto( linkArea, fileName, LinkDestination( LinkDestinationData(g->getDest(), g->getNamedDest(), data->doc->data ) ) ); |
| } |
| break; |
| |
| case actionLaunch: |
| { |
| LinkLaunch * e = (LinkLaunch *)a; |
| GooString * p = e->getParams(); |
| popplerLink = new LinkExecute( linkArea, e->getFileName()->getCString(), p ? p->getCString() : 0 ); |
| } |
| break; |
| |
| case actionNamed: |
| { |
| const char * name = ((LinkNamed *)a)->getName()->getCString(); |
| if ( !strcmp( name, "NextPage" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::PageNext ); |
| else if ( !strcmp( name, "PrevPage" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::PagePrev ); |
| else if ( !strcmp( name, "FirstPage" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::PageFirst ); |
| else if ( !strcmp( name, "LastPage" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::PageLast ); |
| else if ( !strcmp( name, "GoBack" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::HistoryBack ); |
| else if ( !strcmp( name, "GoForward" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::HistoryForward ); |
| else if ( !strcmp( name, "Quit" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::Quit ); |
| else if ( !strcmp( name, "GoToPage" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::GoToPage ); |
| else if ( !strcmp( name, "Find" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::Find ); |
| else if ( !strcmp( name, "FullScreen" ) ) |
| popplerLink = new LinkAction( linkArea, LinkAction::Presentation ); |
| else if ( !strcmp( name, "Close" ) ) |
| { |
| // acroread closes the document always, doesnt care whether |
| // its presentation mode or not |
| // popplerLink = new LinkAction( linkArea, LinkAction::EndPresentation ); |
| popplerLink = new LinkAction( linkArea, LinkAction::Close ); |
| } |
| else |
| { |
| // TODO |
| } |
| } |
| break; |
| |
| case actionURI: |
| { |
| popplerLink = new LinkBrowse( linkArea, ((LinkURI *)a)->getURI()->getCString() ); |
| } |
| break; |
| |
| case actionMovie: |
| case actionSound: |
| case actionRendition: |
| case actionJavaScript: |
| break; |
| |
| case actionUnknown: |
| break; |
| } |
| } |
| |
| if (popplerLink) |
| { |
| popplerLinks.append(popplerLink); |
| } |
| } |
| |
| delete xpdfLinks; |
| #endif |
| |
| return popplerLinks; |
| } |
| |
| } |