More refactoring. Big internal changes but nothing visible.. apart from a

memory reduction on the displayed page. OutputDev under big changes.
Now DocumentObservers have an unique ID so they can queue requests to
documents and they get their data stored in Page(s). No more Pixmaps or
Thumbnails requests, every observer can request a custom-sized pixmap for
a given page. That makes room for new observers (like a cool perspective
book like page viewer or stacked viewer or what your fantasy suggests :-).

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=346792
This commit is contained in:
Enrico Ros 2004-09-15 20:45:00 +00:00
parent 8ac5c9e95b
commit 727d5dd57a
14 changed files with 360 additions and 329 deletions

View file

@ -19,80 +19,121 @@
#pragma implementation
#endif
#include <kdebug.h>
#include "SplashBitmap.h"
#include "TextOutputDev.h"
#include "QOutputDev.h"
// NOTE: XPDF/Splash implementation dependant code will be marked with '###'
//------------------------------------------------------------------------
// QOutputDev
// KPDFOutputDev
//------------------------------------------------------------------------
QOutputDev::QOutputDev(SplashColor paperColor)
: SplashOutputDev(splashModeRGB8, false, paperColor), m_image(0)
KPDFOutputDev::KPDFOutputDev(SplashColor paperColor)
: SplashOutputDev(splashModeRGB8, false, paperColor),
m_pixmapWidth( -1 ), m_pixmapHeight( -1 ), m_pixmap( 0 ), m_text( 0 )
{
// create text object
m_text = new TextPage ( gFalse );
}
QOutputDev::~QOutputDev ( )
KPDFOutputDev::~KPDFOutputDev()
{
delete m_pixmap;
delete m_text;
}
void QOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen)
void KPDFOutputDev::setParams( int width, int height, bool generateText )
{
m_text->addChar(state, x, y, dx, dy, code, u, uLen);
m_pixmapWidth = width;
m_pixmapHeight = height;
if ( m_pixmap )
{
delete m_pixmap;
m_pixmap = 0;
}
delete m_text;
m_text = generateText ? new TextPage( gFalse ) : 0;
}
QPixmap * KPDFOutputDev::takePixmap()
{
QPixmap * pix = m_pixmap;
m_pixmap = 0;
return pix;
}
TextPage * KPDFOutputDev::takeTextPage()
{
TextPage * text = m_text;
m_text = 0;
return text;
}
void KPDFOutputDev::startPage(int pageNum, GfxState *state)
{
m_pageNum = pageNum;
SplashOutputDev::startPage(pageNum, state);
if ( m_text )
m_text->startPage(state);
}
void KPDFOutputDev::endPage()
{
SplashOutputDev::endPage();
if ( m_text )
m_text->coalesce(gTrue);
// create a QPixmap from page data
delete m_pixmap;
int bh = getBitmap()->getHeight(),
bw = getBitmap()->getWidth();
SplashColorPtr dataPtr = getBitmap()->getDataPtr();
QImage * img = new QImage((uchar*)dataPtr.rgb8, bw, bh, 32, 0, 0, QImage::IgnoreEndian);
if ( bw != m_pixmapWidth || bh != m_pixmapHeight )
{
// it may happen (in fact it doesn't) that we need rescaling
kdWarning() << "Pixmap at page '" << m_pageNum << "' needed rescale." << endl;
m_pixmap = new QPixmap( img->smoothScale( m_pixmapWidth, m_pixmapHeight ) );
}
else
m_pixmap = new QPixmap( *img );
delete img;
// ### hack: unload memory used by bitmap
SplashOutputDev::startPage(0, NULL);
}
void KPDFOutputDev::drawLink(Link * /*l*/, Catalog */*catalog*/)
{
/* double x1,y1, x2,y2;
l->getRect( &x1,&y1, &x2,&y2 );
LinkAction * a = l->getAction();
pri NOWARN ntf("LINK %x ok:%d t:%d rect:[%f,%f,%f,%f] \n", (uint)l, (int)l->isOk(),
(int)a->getKind(), x1,y2, x2-x1, y2-y1 );
*/}
void KPDFOutputDev::updateFont(GfxState *state)
{
SplashOutputDev::updateFont(state);
if ( m_text )
m_text->updateFont(state);
}
void KPDFOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen)
{
if ( m_text )
m_text->addChar(state, x, y, dx, dy, code, u, uLen);
SplashOutputDev::drawChar(state, x, y, dx, dy, originX, originY, code, u, uLen);
}
GBool QOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
GBool KPDFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
{
m_text->addChar(state, x, y, dx, dy, code, u, uLen);
if ( m_text )
m_text->addChar(state, x, y, dx, dy, code, u, uLen);
return SplashOutputDev::beginType3Char(state, x, y, dx, dy, code, u, uLen);
}
void QOutputDev::clear()
{
startDoc(NULL);
startPage(0, NULL);
}
void QOutputDev::startPage(int pageNum, GfxState *state)
{
SplashOutputDev::startPage(pageNum, state);
m_text->startPage(state);
}
void QOutputDev::endPage()
{
SplashColorPtr dataPtr;
int bh, bw;
SplashOutputDev::endPage();
m_text->coalesce(gTrue);
bh = getBitmap()->getHeight();
bw = getBitmap()->getWidth();
dataPtr = getBitmap()->getDataPtr();
m_image = QImage((uchar*)dataPtr.rgb8, bw, bh, 32, 0, 0, QImage::IgnoreEndian);
m_image.setAlphaBuffer( false );
// TODO HACK: unload memory used by bitmap
//SplashOutputDev::startPage(pageNum, state (with pix size={0,0}) );
}
void QOutputDev::updateFont(GfxState *state)
{
SplashOutputDev::updateFont(state);
m_text->updateFont(state);
}
bool QOutputDev::find(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, double *xMin, double *yMin, double *xMax, double *yMax)
{
return m_text -> findText(s, len, startAtTop, stopAtBottom, startAtLast, stopAtLast, xMin, yMin, xMax, yMax);
}
const QImage &QOutputDev::getImage() const
{
return m_image;
}

View file

@ -12,8 +12,8 @@
* (at your option) any later version. *
***************************************************************************/
#ifndef QOUTPUTDEV_H
#define QOUTPUTDEV_H
#ifndef KPDFOUTPUTDEV_H
#define KPDFOUTPUTDEV_H
#ifdef __GNUC__
#pragma interface
@ -21,43 +21,55 @@
#include <qimage.h>
#include "XRef.h"
#include "SplashOutputDev.h"
#include "Link.h"
class TextPage;
class KPDFPage;
class QOutputDev : public SplashOutputDev
/**
* @short A SplashOutputDev rendered that grab text and links.
*
* This output device:
* - renders the page using SplashOutputDev (its parent)
* - harvests text into a textPage (for searching text)
* - harvests links and set them to a KPDFPage
*/
class KPDFOutputDev : public SplashOutputDev
{
public:
// Constructor
QOutputDev(SplashColor paperColor);
// Destructor.
virtual ~QOutputDev();
// Start a page.
virtual void startPage(int pageNum, GfxState *state);
// End a page.
virtual void endPage();
//----- update text state
virtual void updateFont(GfxState *state);
//----- text drawing
virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen);
virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
// Clear out the document (used when displaying an empty window).
void clear();
bool find(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, double *xMin, double *yMin, double *xMax, double *yMax);
const QImage &getImage() const;
private:
TextPage *m_text; // text from the current page
QImage m_image; // the image where the page is drawn
public:
KPDFOutputDev( SplashColor paperColor );
virtual ~KPDFOutputDev();
// to be called before PDFDoc->displayPage( thisclass, .. )
void setParams( int pixmapWidth, int pixmapHeight, bool generateText );
// takes pointers out of the class (so deletion it's up to others)
QPixmap * takePixmap();
TextPage * takeTextPage();
/** inherited from OutputDev */
// Start a page.
virtual void startPage(int pageNum, GfxState *state);
// End a page.
virtual void endPage();
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog);
//----- update text state
virtual void updateFont(GfxState *state);
//----- text drawing
virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, Unicode *u, int uLen);
virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
private:
// the pixmap where the page is drawn (generated on every execution)
int m_pageNum;
int m_pixmapWidth;
int m_pixmapHeight;
QPixmap * m_pixmap;
// text page generated on demand
TextPage * m_text;
};
#endif

View file

@ -1,18 +1,32 @@
Personal Albert's list
-> make links functional
-> make links functional (done in HEAD)
More items
-> multiple pages per view
-> continous mode
-> screen editing: framework
-> screen editing: tools
-> export all text in plain_text/html
-> extract(export?) images
-> implement history (mainly for actionNamed)
-> new icons (contest at kde-look that will end in 2004-Oct-01)
Porting / In progress
-> implementing Document / Page using AACid's thread as the generation thread
-> improve thumbnail generation to make it non-gui blocking
-> multiple pages per view
-> centering pages in the view
Porting / In progress on the branch (first item comes first):
-> porting Albert's link following
-> porting Albert's search
-> implementing async document generator using Albert's thread as the generation thread
-> better zoom handling
Done (sorted by inv.time)
-> smart handling of pixmap using an Observer ID (thumbnails are gone, only pixmaps now)
-> some toolbar/menu changes
-> outline bottom and right edges (of pages)
Done
-> merge lots of kpdf_part and part (centralview) code (to simplify/clenup)
-> maybe: use local instead of X memory for thumbnails (..)
-> centering pages in the view
-> kpdf output at 100% has exactly the same size as acroread now
-> qsplitter layouting
-> zooming works as expected (and added 'fit to page' too)
-> new go to page dialog
-> previews sorted by visible areas (prioritize items where the scrollbar is)
-> previews speedup: 50-100%
-> use local instead of X memory for thumbnails (..)
-> merge lots of kpdf_part and part (centralview) code (to simplify/clenup)

View file

@ -11,6 +11,7 @@
#include <qfile.h>
#include <qmutex.h>
#include <qvaluevector.h>
#include <qmap.h>
#include <kdebug.h>
// local includes
@ -35,18 +36,18 @@ public:
// document related
QMutex docLock;
PDFDoc * pdfdoc;
QOutputDev * splashOutputDevice;
KPDFOutputDev * kpdfOutputDev;
int currentPage;
float currentPosition;
QValueVector< KPDFPage* > pages;
// observers related (note: won't delete oservers)
QValueList< KPDFDocumentObserver* > observers;
QMap< int, KPDFDocumentObserver* > observers;
};
#define foreachObserver( cmd ) {\
QValueList<KPDFDocumentObserver*>::iterator it = d->observers.begin();\
QValueList<KPDFDocumentObserver*>::iterator end = d->observers.end();\
QMap<int,KPDFDocumentObserver*>::iterator it = d->observers.begin();\
QMap<int,KPDFDocumentObserver*>::iterator end = d->observers.end();\
for ( ; it != end ; ++ it ) { (*it)-> cmd ; } }
/*
@ -60,13 +61,13 @@ KPDFDocument::KPDFDocument()
d->currentPosition = 0;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8( 0xff, 0xff, 0xff );
d->splashOutputDevice = new QOutputDev( paperColor );
d->kpdfOutputDev = new KPDFOutputDev( paperColor );
}
KPDFDocument::~KPDFDocument()
{
close();
delete d->splashOutputDevice;
delete d->kpdfOutputDev;
delete d;
}
@ -94,7 +95,7 @@ bool KPDFDocument::openFile( const QString & docFile )
errors::clear();
// initialize output device for rendering current pdf
d->splashOutputDevice->startDoc( d->pdfdoc->getXRef() );
d->kpdfOutputDev->startDoc( d->pdfdoc->getXRef() );
// build Pages (currentPage was set -1 by deletePages)
uint pageCount = d->pdfdoc->getNumPages();
@ -146,6 +147,44 @@ const KPDFPage * KPDFDocument::page( uint n ) const
}
void KPDFDocument::addObserver( KPDFDocumentObserver * pObserver )
{
d->observers[ pObserver->observerId() ] = pObserver;
}
void KPDFDocument::requestPixmap( int id, uint page, int width, int height, bool syn )
{
KPDFPage * kp = d->pages[page];
if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 )
return;
if ( syn )
{
// in-place Pixmap generation for syncronous requests
if ( !kp->hasPixmap( id, width, height ) )
{
// set KPDFPage pointer to outputdevice for links/text harvesting
d->kpdfOutputDev->setParams( width, height, false );
// compute dpi used to get an image with desired width and height
double fakeDpiX = width * 72.0 / kp->width(),
fakeDpiY = height * 72.0 / kp->height();
d->docLock.lock();
d->pdfdoc->displayPage( d->kpdfOutputDev, page + 1, fakeDpiX, fakeDpiY, 0, true, true );
d->docLock.unlock();
kp->setPixmap( id, d->kpdfOutputDev->takePixmap() );
d->observers[id]->notifyPixmapChanged( page );
}
}
else
{
//TODO asyncronous events queuing
}
}
// BEGIN slots
void KPDFDocument::slotSetCurrentPage( int page )
{
slotSetCurrentPagePosition( page, 0.0 );
@ -261,93 +300,16 @@ void KPDFDocument::slotFind( bool /*nextMatch*/, const QString & /*text*/ )
void KPDFDocument::slotGoToLink( /* QString anchor */ )
{
}
//END slots
void KPDFDocument::addObserver( KPDFDocumentObserver * pObserver )
{
d->observers.push_back( pObserver );
}
void KPDFDocument::requestPixmap( uint page, int width, int height, bool syn )
{
KPDFPage * kp = d->pages[page];
if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 )
return;
if ( syn )
{
// in-place Pixmap generation for syncronous requests
if ( !kp->hasPixmap( width, height ) )
{
// compute dpi used to get an image with desired width and height
double fakeDpiX = width * 72.0 / kp->width(),
fakeDpiY = height * 72.0 / kp->height();
d->docLock.lock();
d->pdfdoc->displayPage( d->splashOutputDevice, page + 1, fakeDpiX, fakeDpiY, 0, true, false );
d->docLock.unlock();
// it may happen (in fact it doesn't) that we need rescaling
if ( d->splashOutputDevice->getImage().size() != QSize( width, height ) )
{
kdWarning() << "Pixmap for page '" << page << "' needed rescale." << endl;
kp->setPixmap( d->splashOutputDevice->getImage().smoothScale( width, height ) );
}
else
kp->setPixmap( d->splashOutputDevice->getImage() );
foreachObserver( notifyPixmapChanged( page ) );
}
}
else
{
//TODO asyncronous events queuing
}
}
void KPDFDocument::requestThumbnail( uint page, int width, int height, bool syn )
{
KPDFPage * kp = d->pages[page];
if ( !d->pdfdoc || !kp || kp->width() < 1 || kp->height() < 1 )
return;
if ( syn )
{
// in-place Thumbnail generation for syncronous requests
if ( !kp->hasThumbnail( width, height ) )
{
// compute dpi used to get an image with desired width and height
double fakeDpiX = width * 72.0 / kp->width(),
fakeDpiY = height * 72.0 / kp->height();
d->docLock.lock();
d->pdfdoc->displayPage( d->splashOutputDevice, page + 1, fakeDpiX, fakeDpiY, 0, true, false );
d->docLock.unlock();
// it may happen (in fact it doesn't) that we need rescaling
if ( d->splashOutputDevice->getImage().size() != QSize( width, height ) )
{
kdWarning() << "Thumbnail for page '" << page << "' needed rescale." << endl;
kp->setThumbnail( d->splashOutputDevice->getImage().smoothScale( width, height ) );
}
else
kp->setThumbnail( d->splashOutputDevice->getImage() );
foreachObserver( notifyThumbnailChanged( page ) );
}
}
else
{
//TODO asyncronous events queuing
}
}
void KPDFDocument::sendFilteredPageList()
void KPDFDocument::sendFilteredPageList( bool forceEmpty )
{
// make up a value list of the pages [1,2,3..]
uint pageCount = d->pages.count();
QValueList<int> pagesList;
for ( uint i = 0; i < pageCount ; i++ )
pagesList.push_back( i );
if ( !forceEmpty )
for ( uint i = 0; i < pageCount ; i++ )
pagesList.push_back( i );
// send the list to observers
foreachObserver( pageSetup( pagesList ) );
@ -359,8 +321,7 @@ void KPDFDocument::deletePages()
return;
// broadcast an empty page list to observers
QValueList<int> pagesList;
foreachObserver( pageSetup( pagesList ) );
sendFilteredPageList( true );
// delete pages and clear container
for ( uint i = 0; i < d->pages.count() ; i++ )

View file

@ -18,23 +18,26 @@ class KPDFPage;
/**
* @short Base class for objects being notified when something changes.
*
* Inherit this class and call KPDFDocument->addObserver( obsClass ) to get
* notified of asyncronous events (a new thumbnail has arrived, a pixmap has
* changed, and other events).
* Inherit this class and call KPDFDocument->addObserver( obsClass ) to get notified
* of asyncronous events (a new pixmap has arrived, changed, etc... ).
*/
class KPDFDocumentObserver
{
public:
// you must give each observer a unique ID (used for notifications)
virtual uint observerId() = 0;
// monitor changes in pixmaps (generation thread complete)
virtual void notifyThumbnailChanged( int /*pageNumber*/ ) {};
virtual void notifyPixmapChanged( int /*pageNumber*/ ) {};
// commands from the Document to observers
// commands from the Document to all observers
virtual void pageSetup( const QValueList<int> & /*pages*/ ) {};
virtual void pageSetCurrent( int /*pageNumber*/, float /*position*/ ) {};
virtual void pageSetHilight( int /*x*/, int /*y*/, int /*width*/, int /*height*/ ) {};
//virtual void pageSetHilight( int /*x*/, int /*y*/, int /*width*/, int /*height*/ ) {};
};
#define PAGEWIDGET_ID 1
#define THUMBNAILS_ID 2
/**
* @short The information container. Actions (like open,find) take place here.
@ -63,8 +66,7 @@ public:
// observers related methods
void addObserver( KPDFDocumentObserver * pObserver );
void requestPixmap( uint page, int width, int height, bool syncronous = false );
void requestThumbnail( uint page, int width, int height, bool syncronous = false );
void requestPixmap( int id, uint page, int width, int height, bool syncronous = false );
public slots:
// document commands via slots
@ -78,7 +80,7 @@ signals:
void pageChanged();
private:
void sendFilteredPageList();
void sendFilteredPageList( bool forceEmpty = false );
void deletePages();
class KPDFDocumentPrivate * d;

View file

@ -115,7 +115,7 @@ void PageWidget::pageSetup( const QValueList<int> & pages )
m_page = 0;
if ( pages.count() < 1 )
return slotUpdateView();
return;
// populate internal vector with the list of pages and update
QValueList<int>::const_iterator pageIt = pages.begin();
@ -258,7 +258,7 @@ void PageWidget::viewportResizeEvent( QResizeEvent * )
}
m_delayTimer->start( 400, true );
// recalc coordinates
slotUpdateView( false );
//slotUpdateView( false );
}
void PageWidget::keyPressEvent( QKeyEvent * e )
@ -324,7 +324,7 @@ void PageWidget::dropEvent( QDropEvent * ev )
emit urlDropped( lst.first() );
}
void PageWidget::drawContents ( QPainter *p, int clipx, int clipy, int clipw, int cliph )
void PageWidget::drawContents( QPainter *p, int clipx, int clipy, int clipw, int cliph )
{
QColor bc( paletteBackgroundColor() /*KGlobalSettings::calculateAlternateBackgroundColor( KGlobalSettings::baseColor() )*/ );
if ( m_page )
@ -339,7 +339,7 @@ void PageWidget::drawContents ( QPainter *p, int clipx, int clipy, int clipw, in
p->translate( m_pageRect.left(), m_pageRect.top() );
QRect translatedPageClip( pageClip );
translatedPageClip.moveBy( -m_pageRect.left(), -m_pageRect.top() );
m_page->drawPixmap( p, translatedPageClip, m_pageRect.width(), m_pageRect.height() );
m_page->drawPixmap( PAGEWIDGET_ID, p, translatedPageClip, m_pageRect.width(), m_pageRect.height() );
p->restore();
}
@ -499,7 +499,7 @@ void PageWidget::slotUpdateView( bool repaint )
viewH = QMAX( viewport()->height(), pageH );
m_pageRect.setRect( (viewW - pageW) / 2, (viewH - pageH) / 2, pageW, pageH );
resizeContents( viewW, viewH );
m_document->requestPixmap( m_page->number(), pageW, pageH, true );
m_document->requestPixmap( PAGEWIDGET_ID, m_page->number(), pageW, pageH, true );
}
if ( repaint )
viewport()->update();

View file

@ -34,6 +34,7 @@ public:
PageWidget( QWidget *parent, KPDFDocument *document );
// create actions that interact with this widget
uint observerId() { return PAGEWIDGET_ID; }
void setupActions( KActionCollection * collection, KConfigGroup * config );
void saveSettings( KConfigGroup * config );

View file

@ -9,94 +9,96 @@
// qt includes
#include <qapplication.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qstring.h>
#include <qpainter.h>
#include <qmap.h>
// local includes
#include "TextOutputDev.h"
#include "page.h"
class PageOverlay { /*fake temp class*/ };
// TODO add painting effects (plus selection rectangle)
// TODO think about moving rendering ...
#include <qimage.h>
KPDFPage::KPDFPage( uint page, float w, float h, int r )
: m_number( page ), m_width( w ), m_height( h ), m_rotate( r ),
m_pixmap( 0 ), m_thumbnail( 0 ), m_text( 0 ), m_overlay( 0 )
KPDFPage::KPDFPage( int page, float w, float h, int r )
: m_number( page ), m_rotation( r ), m_width( w ), m_height( h ), m_text( 0 )
{
/* m_thumbnail = new QPixmap( "/a.png", "PNG" );
QImage im = m_thumbnail->convertToImage();
im = im.smoothScale(100,100);
im.setAlphaBuffer( false );
m_thumbnail->convertFromImage(im);
*/
}
KPDFPage::~KPDFPage()
{
delete m_pixmap;
delete m_thumbnail;
QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
for ( ; it != end; ++it )
delete *it;
delete m_text;
delete m_overlay;
}
//BEGIN drawing functions
// drawing functions draw the pixmap directly if it has the right size, or
// else set a scale matrix to the painter and paint a quick 'zoomed' pixmap
//TODO drawing: if !pix but thumb still draw pix scaling thumb and vice-versa.
void KPDFPage::drawPixmap( QPainter * p, const QRect & limits, int width, int height ) const
void KPDFPage::drawPixmap( int id, QPainter * p, const QRect & limits, int width, int height ) const
{
if ( m_pixmap )
QPixmap * pixmap = 0;
// if a pixmap is present for given id, use it
if ( m_pixmaps.contains( id ) )
pixmap = m_pixmaps[ id ];
// else find the closest match using pixmaps of other IDs (great optim!)
else if ( !m_pixmaps.isEmpty() )
{
if ( m_pixmap->width() == width && m_pixmap->height() == height )
p->drawPixmap( limits.topLeft(), *m_pixmap, limits );
int minDistance = -1;
QMap<int,QPixmap *>::const_iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
for ( ; it != end; ++it )
{
int pixWidth = (*it)->width(),
distance = pixWidth > width ? pixWidth - width : width - pixWidth;
if ( minDistance == -1 || distance < minDistance )
{
pixmap = *it;
minDistance = distance;
}
}
}
// if we found a pixmap draw it
if ( pixmap )
{
// fast blit the pixmap if it has the right size..
if ( pixmap->width() == width && pixmap->height() == height )
p->drawPixmap( limits.topLeft(), *pixmap, limits );
// ..else set a scale matrix to the painter and paint a quick 'zoomed' pixmap
else
{
p->scale( width / (double)m_pixmap->width(), height / (double)m_pixmap->height() );
p->drawPixmap( 0,0, *m_pixmap, 0,0, m_pixmap->width(), m_pixmap->height() );
p->setPen( Qt::black );
p->drawLine( 0, 0, 20, 0 );
p->drawLine( 20, 0, 0, 20 );
p->drawLine( 0, 20, 0, 0 );
p->save();
p->scale( width / (double)pixmap->width(), height / (double)pixmap->height() );
p->drawPixmap( 0,0, *pixmap, 0,0, pixmap->width(), pixmap->height() );
p->restore();
// draw a red cross (to hilight that the pixmap has not the right size)
p->setPen( Qt::red );
p->drawLine( 0, 0, width, height );
p->drawLine( 0, height, width, 0 );
}
// draw selection (FIXME Enrico: move selection stuff inside PAGE!!)
/*if ( there is something to hilght )
p->setBrush(Qt::SolidPattern);
p->setPen(QPen(Qt::black, 1)); // should not be necessary bug a Qt bug makes it necessary
p->setRasterOp(Qt::NotROP);
p->drawRect(qRound(m_xMin*m_zoomFactor), qRound(m_yMin*m_zoomFactor), qRound((m_xMax- m_xMin)*m_zoomFactor), qRound((m_yMax- m_yMin)*m_zoomFactor));
p->setBrush(Qt::SolidPattern);
p->setPen(QPen(Qt::black, 1)); // should not be necessary bug a Qt bug makes it necessary
p->setRasterOp(Qt::NotROP);
p->drawRect(qRound(m_xMin*m_zoomFactor), qRound(m_yMin*m_zoomFactor), qRound((m_xMax- m_xMin)*m_zoomFactor), qRound((m_yMax- m_yMin)*m_zoomFactor));
*/
}
// else draw a blank area
else
p->fillRect( limits, Qt::white /*FIXME change to the page bg color*/ );
}
void KPDFPage::drawThumbnail( QPainter * p, const QRect & limits, int width, int height ) const // OK
{
if ( m_thumbnail )
{
if ( m_thumbnail->width() == width && m_thumbnail->height() == height )
p->drawPixmap( limits.topLeft(), *m_thumbnail, limits );
else
{
p->scale( width / (double)m_thumbnail->width(), height / (double)m_thumbnail->height() );
p->drawPixmap( 0,0, *m_thumbnail, 0,0, m_thumbnail->width(), m_thumbnail->height() );
}
}
else
p->fillRect( limits, QApplication::palette().active().base() );
}
//END drawing functions
//BEGIN contents set methods
bool KPDFPage::hasPixmap( int width, int height ) const
bool KPDFPage::hasPixmap( int id, int width, int height ) const
{
return m_pixmap ? ( m_pixmap->width() == width && m_pixmap->height() == height ) : false;
}
bool KPDFPage::hasThumbnail( int width, int height ) const
{
return m_thumbnail ? ( m_thumbnail->width() == width && m_thumbnail->height() == height ) : false;
if ( !m_pixmaps.contains( id ) )
return false;
QPixmap * p = m_pixmaps[ id ];
return p ? ( p->width() == width && p->height() == height ) : false;
}
bool KPDFPage::hasLink( int mouseX, int mouseY ) const
@ -106,10 +108,11 @@ bool KPDFPage::hasLink( int mouseX, int mouseY ) const
return QRect( 20,20, 100,50 ).contains( mouseX, mouseY );
}
void KPDFPage::setPixmap( const QImage & image )
void KPDFPage::setPixmap( int id, QPixmap * pixmap )
{
delete m_pixmap;
m_pixmap = new QPixmap( image );
if ( !m_pixmaps.contains( id ) )
delete m_pixmaps[id];
m_pixmaps[id] = pixmap;
}
/*
@ -121,12 +124,6 @@ void KPDFPage::setPixmapOverlayNotations( ..DOMdescription.. )
}
*/
void KPDFPage::setThumbnail( const QImage & image )
{
delete m_thumbnail;
m_thumbnail = new QPixmap( image );
}
/*
void KPDFPage::setTextPage( TextOutputDev * textPage )
{
@ -140,17 +137,16 @@ void KPDFPage::setLinks( ..SomeStruct.. )
{
}
*/
//END contents set methods
//BEGIN [FIND]
/*bool KPDFPage::hasText( QString & text )
{ //TODO this
return text.isNull();
// FIXME MOVED from the QOutputDev. Find over a textpage.
//bool find(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, double *xMin, double *yMin, double *xMax, double *yMax)
//{return m_text -> findText(s, len, startAtTop, stopAtBottom, startAtLast, stopAtLast, xMin, yMin, xMax, yMax);}
}
const QRect & KPDFPage::textPosition()
{ //TODO this
return QRect();
}*/
//END [FIND]

View file

@ -10,37 +10,27 @@
#ifndef _KPDF_PAGE_H_
#define _KPDF_PAGE_H_
class QPixmap;
class QPainter;
class QImage;
class QPixmap;
//class QString;
//class QRect;
class TextOutputDev;
class PageOverlay;
/**
* @short Collector for all the data belonging to a page.
*
* The Page class contains its pixmap, the thumbnail, a search page (a class
* used internally for searching data) the modifiers descriptors (for overlay
* graphics) and more.
* It provides accessor methods for all those operations too.
*
* Note: add stuff this class contains is destroyed automatically when the
* class is destroyed.
* The KPDFPage class contains pixmaps (referenced using obsedvers id as key),
* a search page (a class used internally for searching data), link classes
* (that describe links in the current page) plus graphics overlays and more.
*
* Note: All objects passed to this class will be destoryed on class deletion.
*/
/*
[19:52] *TSDgeos* is, for links to work i need to enable setMouseTracking in the widget
[19:53] *TSDgeos* that generates a mousemoveevent even if the user does not click the mouse so i can change the cursor when the user is over a link
[19:53] *TSDgeos* do you think page could have a "cache" of places where the link exists so i don't have to query xpdf every time?
[19:57] *eros* I'll add a cache.
*/
// ### HACK : this structure is under big changes ###
class KPDFPage
{
public:
KPDFPage( uint number, float width, float height, int rotation );
KPDFPage( int number, float width, float height, int rotation );
~KPDFPage();
// query properties (const read-only methods)
@ -48,34 +38,46 @@ public:
float width() const { return m_width; }
float height() const { return m_height; }
float ratio() const { return m_height / m_width; }
float rotation() const { return m_rotate; }
bool hasPixmap( int width, int height ) const;
bool hasThumbnail( int width, int height ) const;
float rotation() const { return m_rotation; }
bool hasPixmap( int id, int width, int height ) const;
bool hasLink( int mouseX, int mouseY ) const;
void drawPixmap( QPainter * p, const QRect & rect, int width, int height ) const;
void drawThumbnail( QPainter * p, const QRect & rect, int width, int height ) const;
void drawPixmap( int id, QPainter * p, const QRect & rect, int width, int height ) const;
// page contents setup
void setPixmap( const QImage & image );
/*void setPixmapOverlaySelection( const QRect & normalizedRect );*/
/*void setPixmapOverlayNotations( ..DOMdescription.. );*/
void setThumbnail( const QImage & image );
// page contents setup *NOTE changes in progress*
void setPixmap( int id, QPixmap * pixmap );
/*void setTextPage( TextOutputDev * );*/
/*void setLinks( ..SomeStruct.. ); or (better): */
/*void addLink( QFloatRect( normalizedRect ), int destPage, int destPos ); */
/*void setPixmapOverlaySelection( const QRect & normalizedRect );*/
/*void setPixmapOverlayNotations( ..DOMdescription.. );*/
// FIND command
//bool hasText( QString & text );
//const QRect & textPosition();
private:
uint m_number;
int m_number, m_rotation;
float m_width, m_height;
int m_rotate;
QPixmap * m_pixmap;
QPixmap * m_thumbnail;
TextOutputDev * m_text;
PageOverlay * m_overlay;
};
QMap<int,QPixmap *> m_pixmaps;
TextOutputDev * m_text;
};
/*
class KPDFLink
{
public:
enum LinkType { Goto, Execute, Action, URI, Movie };
KPDFLink( LinkType type ) : m_type( type ) {};
void setType( LinkType type ) { m_type = type; }
LinkType type() { return m_type; }
private:
LinkType m_type;
float x_min, x_max, y_min, y_max;
// [Goto] type
// []
};
*/
#endif

View file

@ -11,6 +11,7 @@
#include <qpainter.h>
#include "thumbnail.h"
#include "document.h"
#include "page.h"
Thumbnail::Thumbnail( QWidget *parent, const KPDFPage *page )
@ -83,7 +84,7 @@ void Thumbnail::paintEvent( QPaintEvent * e )
p.translate( 1, 1 );
clipRect.moveBy( -1, -1 );
clipRect = clipRect.intersect( QRect( 0, 0, m_previewWidth, m_previewHeight ) );
m_page->drawThumbnail( &p, clipRect, m_previewWidth, m_previewHeight );
m_page->drawPixmap( THUMBNAILS_ID, &p, clipRect, m_previewWidth, m_previewHeight );
p.end();
}

View file

@ -9,7 +9,7 @@
#ifndef THUMBNAIL_H
#define THUMBNAIL_H
#include <qwidget.h>
class QLabel;

View file

@ -29,18 +29,18 @@ int ThumbnailGenerator::getPage() const
void ThumbnailGenerator::run()
{
QCustomEvent *ce;
QImage *i;
//QImage *i;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
QOutputDev odev(paperColor);
KPDFOutputDev odev(paperColor);
odev.startDoc(m_doc->getXRef());
m_docMutex->lock();
m_doc -> displayPage(&odev, m_page, m_ppp, m_ppp, 0, true, false);
m_docMutex->unlock();
ce = new QCustomEvent(65432);
i = new QImage(odev.getImage());
i -> detach();
ce -> setData(i);
//i = new QImage(odev.getImage()); FIXME commented because the ODEV is changing
//i -> detach();
//ce -> setData(i);
QApplication::postEvent(m_o, ce);
}

View file

@ -35,7 +35,7 @@ ThumbnailList::ThumbnailList(QWidget *parent, KPDFDocument *document)
viewport()->setPaletteBackgroundColor( palette().active().base() );
setFrameStyle( StyledPanel | Raised );
connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestThumbnails(int, int)) );
connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestPixmaps(int, int)) );
}
void ThumbnailList::setupActions( KActionCollection * ac, KConfigGroup * config )
@ -92,7 +92,7 @@ void ThumbnailList::pageSetup( const QValueList<int> & pages )
resizeContents( width, totalHeight );
// request for thumbnail generation
requestThumbnails( 200 );
requestPixmaps( 200 );
}
void ThumbnailList::pageSetCurrent( int pageNumber, float /*position*/ )
@ -120,7 +120,7 @@ void ThumbnailList::pageSetCurrent( int pageNumber, float /*position*/ )
}
}
void ThumbnailList::notifyThumbnailChanged( int pageNumber )
void ThumbnailList::notifyPixmapChanged( int pageNumber )
{
QValueVector<Thumbnail *>::iterator thumbIt = m_thumbnails.begin();
QValueVector<Thumbnail *>::iterator thumbEnd = m_thumbnails.end();
@ -195,7 +195,7 @@ void ThumbnailList::viewportResizeEvent(QResizeEvent *e)
if ( e->size().width() != e->oldSize().width() )
{
// runs the timer avoiding a thumbnail regeneration by 'contentsMoving'
requestThumbnails( 2000 );
requestPixmaps( 2000 );
// resize and reposition items
int totalHeight = 0,
@ -219,12 +219,12 @@ void ThumbnailList::viewportResizeEvent(QResizeEvent *e)
else if ( e->size().height() <= e->oldSize().height() )
return;
// update Thumbnails since width has changed or height has increased
requestThumbnails( 500 );
requestPixmaps( 500 );
}
//END widget events
//BEGIN internal SLOTS
void ThumbnailList::slotRequestThumbnails( int /*newContentsX*/, int newContentsY )
void ThumbnailList::slotRequestPixmaps( int /*newContentsX*/, int newContentsY )
{
// an update is already scheduled, so don't proceed
if ( m_delayTimer && m_delayTimer->isActive() )
@ -243,17 +243,17 @@ void ThumbnailList::slotRequestThumbnails( int /*newContentsX*/, int newContents
if ( top > vHeight )
break;
else if ( top + t->height() > 0 )
m_document->requestThumbnail( t->pageNumber(), t->previewWidth(), t->previewHeight(), true );
m_document->requestPixmap( THUMBNAILS_ID, t->pageNumber(), t->previewWidth(), t->previewHeight(), true );
}
}
//END internal SLOTS
void ThumbnailList::requestThumbnails( int delayMs )
void ThumbnailList::requestPixmaps( int delayMs )
{
if ( !m_delayTimer )
{
m_delayTimer = new QTimer( this );
connect( m_delayTimer, SIGNAL( timeout() ), this, SLOT( slotRequestThumbnails() ) );
connect( m_delayTimer, SIGNAL( timeout() ), this, SLOT( slotRequestPixmaps() ) );
}
m_delayTimer->start( delayMs, true );
}

View file

@ -26,6 +26,7 @@ Q_OBJECT
ThumbnailList(QWidget *parent, KPDFDocument *document);
// create actions that interact with this widget and load/save settings
uint observerId() { return THUMBNAILS_ID; }
void setupActions( KActionCollection * collection, KConfigGroup * config );
void saveSettings( KConfigGroup * config );
@ -36,7 +37,7 @@ Q_OBJECT
void pageSetCurrent( int pageNumber, float position );
// redraw thumbnail ( inherited as DocumentObserver )
void notifyThumbnailChanged( int pageNumber );
void notifyPixmapChanged( int pageNumber );
protected:
// scroll up/down the view
@ -50,10 +51,10 @@ Q_OBJECT
public slots:
// make requests for generating pixmaps for visible thumbnails
void slotRequestThumbnails( int newContentsX = -1, int newContentsY = -1 );
void slotRequestPixmaps( int newContentsX = -1, int newContentsY = -1 );
private:
void requestThumbnails( int delayMs = 0 );
void requestPixmaps( int delayMs = 0 );
KPDFDocument *m_document;
Thumbnail *m_selected;
QTimer *m_delayTimer;