|
|
|
/* 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, 2010, 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 <tqfile.h>
|
|
|
|
#include <tqimage.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(TQPixmap **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(TQPixmap **q, int x, int y, int w, int h, double xres, double yres, bool doLinks) const
|
|
|
|
{
|
|
|
|
TQImage img = renderToImage(xres, yres, doLinks);
|
|
|
|
*q = new TQPixmap( img );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQImage 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 (TQImage::BigEndian == TQImage::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
|
|
|
|
TQImage img( dataPtr, bw, bh, 32, 0, 0, TQImage::IgnoreEndian );
|
|
|
|
img = img.copy();
|
|
|
|
// unload underlying xpdf bitmap
|
|
|
|
output_dev->startPage( 0, NULL );
|
|
|
|
|
|
|
|
return img;
|
|
|
|
#else
|
|
|
|
(void)xres;
|
|
|
|
(void)xres;
|
|
|
|
(void)doLinks;
|
|
|
|
|
|
|
|
return TQImage();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Page::getText(const Rectangle &r) const
|
|
|
|
{
|
|
|
|
TextOutputDev *output_dev;
|
|
|
|
GooString *s;
|
|
|
|
PDFRectangle *rect;
|
|
|
|
TQString result;
|
|
|
|
::Page *p;
|
|
|
|
|
|
|
|
#if defined(HAVE_POPPLER_060) || defined(HAVE_POPPLER_030) || defined(HAVE_POPPLER_020)
|
|
|
|
output_dev = new TextOutputDev(0, gFalse, 0, gFalse, gFalse);
|
|
|
|
#else
|
|
|
|
output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse);
|
|
|
|
#endif
|
|
|
|
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 = TQString::fromUtf8(s->getCString());
|
|
|
|
|
|
|
|
delete output_dev;
|
|
|
|
delete s;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQValueList<TextBox*> Page::textList() const
|
|
|
|
{
|
|
|
|
TextOutputDev *output_dev;
|
|
|
|
|
|
|
|
TQValueList<TextBox*> output_list;
|
|
|
|
|
|
|
|
#if defined(HAVE_POPPLER_060) || defined(HAVE_POPPLER_030) || defined(HAVE_POPPLER_020)
|
|
|
|
output_dev = new TextOutputDev(0, gFalse, 0, gFalse, gFalse);
|
|
|
|
#else
|
|
|
|
output_dev = new TextOutputDev(0, gFalse, gFalse, gFalse);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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();
|
|
|
|
TQString string = TQString::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;
|
|
|
|
# if defined(HAVE_POPPLER_060)
|
|
|
|
o = data->doc->data->doc.getCatalog()->getPage(data->index + 1)->getTrans();
|
|
|
|
# else
|
|
|
|
data->doc->data->doc.getCatalog()->getPage(data->index + 1)->getTrans(&o);
|
|
|
|
# endif
|
|
|
|
params.dictObj = &o;
|
|
|
|
data->transition = new PageTransition(params);
|
|
|
|
# if !defined(HAVE_POPPLER_060)
|
|
|
|
o.free();
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
return data->transition;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize Page::pageSize() const
|
|
|
|
{
|
|
|
|
::Page *p;
|
|
|
|
|
|
|
|
p = data->doc->data->doc.getCatalog()->getPage(data->index + 1);
|
|
|
|
if ( ( Page::Landscape == orientation() ) || (Page::Seascape == orientation() ) ) {
|
|
|
|
return TQSize( (int)p->getCropHeight(), (int)p->getCropWidth() );
|
|
|
|
} else {
|
|
|
|
return TQSize( (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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQValueList<Link*> Page::links() const
|
|
|
|
{
|
|
|
|
TQValueList<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 );
|
|
|
|
TQRect 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, TQString(), LinkDestination( LinkDestinationData(g->getDest(), g->getNamedDest(), data->doc->data ) ) );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case actionGoToR:
|
|
|
|
{
|
|
|
|
LinkGoToR * g = (LinkGoToR *) a;
|
|
|
|
// copy link file
|
|
|
|
const TQString 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|