/* poppler-page.cc: qt interface to poppler * Copyright (C) 2005, Net Integration Technologies, Inc. * Copyright (C) 2005-2006, Albert Astals Cid * Copyright (C) 2005, Tobias Koening * Copyright (C) 2005, Stefan Kebekus * Copyright (C) 2006, Wilfried Huss * Copyright (C) 2006, Jerry Epplin * Copyright (C) 2007, 2010, Pino Toscano * * 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 #include #include #include #include #include #include #include #include #include #if defined(HAVE_SPLASH) #include #include #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 Page::textList() const { TextOutputDev *output_dev; QValueList 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 Page::links() const { QValueList 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: case actionOCGState: break; case actionUnknown: break; } } if (popplerLink) { popplerLinks.append(popplerLink); } } delete xpdfLinks; #endif return popplerLinks; } }