Commit 4d2969d5 authored by Albert Astals Cid's avatar Albert Astals Cid
Browse files

Thumbnail generation is now done inside a thread

Need testers before backporting it to 3.3.x so please test

svn path=/trunk/kdegraphics/kpdf/; revision=344025
parent 3f84918a
......@@ -42,7 +42,7 @@ shellrc_DATA = kpdf_shell.rc
kde_module_LTLIBRARIES = libkpdfpart.la
# the Part's source, library search path, and link libraries
libkpdfpart_la_SOURCES = QOutputDev.cpp QOutputDevPixmap.cpp QOutputDevKPrinter.cpp kpdf_part.cpp kpdf_pagewidget.cc part.cpp thumbnail.cpp thumbnaillist.cpp kpdf_error.cpp xpdf_errors.cpp
libkpdfpart_la_SOURCES = QOutputDev.cpp QOutputDevPixmap.cpp QOutputDevKPrinter.cpp kpdf_part.cpp kpdf_pagewidget.cc part.cpp thumbnail.cpp thumbnaillist.cpp kpdf_error.cpp xpdf_errors.cpp thumbnailgenerator.cpp
libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
libkpdfpart_la_LIBADD = ../xpdf/libxpdf.la $(LIB_KPARTS) $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm
......
......@@ -22,9 +22,6 @@
#include <GfxState.h>
#include <qpixmap.h>
#include <qimage.h>
#include <kdebug.h>
#include "SplashBitmap.h"
......@@ -36,25 +33,12 @@
// QOutputDevPixmap
//------------------------------------------------------------------------
QOutputDevPixmap::QOutputDevPixmap(SplashColor paperColor) : QOutputDev(paperColor), m_pixmap(0)
QOutputDevPixmap::QOutputDevPixmap(SplashColor paperColor) : QOutputDev(paperColor), m_image(0)
{
}
QOutputDevPixmap::~QOutputDevPixmap( )
{
delete m_pixmap;
}
void QOutputDevPixmap::startPage ( int pageNum, GfxState *state )
{
QOutputDev::startPage(pageNum, state);
delete m_pixmap;
m_pixmap = new QPixmap ( qRound ( state->getPageWidth ( )), qRound ( state->getPageHeight ( )));
//printf ( "NEW PIXMAP (%ld x %ld)\n", qRound ( state-> getPageWidth ( )), qRound ( state-> getPageHeight ( )));
m_pixmap-> fill ( Qt::white ); // clear pixmap
}
void QOutputDevPixmap::endPage ( )
......@@ -66,5 +50,10 @@ void QOutputDevPixmap::endPage ( )
bh = getBitmap()->getHeight();
bw = getBitmap()->getWidth();
dataPtr = getBitmap()->getDataPtr();
m_pixmap->convertFromImage(QImage((uchar*)dataPtr.rgb8, bw, bh, 32, 0, 0, QImage::IgnoreEndian));
m_image = QImage((uchar*)dataPtr.rgb8, bw, bh, 32, 0, 0, QImage::IgnoreEndian);
}
const QImage &QOutputDevPixmap::getImage() const
{
return m_image;
}
......@@ -21,7 +21,7 @@
#include "QOutputDev.h"
class QPixmap;
#include <qimage.h>
class QOutputDevPixmap : public QOutputDev {
public:
......@@ -32,18 +32,13 @@ public:
// Destructor.
virtual ~QOutputDevPixmap();
//----- initialization and control
// Start a page.
virtual void startPage(int pageNum, GfxState *state);
// End a page
virtual void endPage();
QPixmap * getPixmap() const { return m_pixmap; };
const QImage &getImage() const;
private:
QPixmap * m_pixmap; // pixmap to draw into
QImage m_image;
};
#endif // QOUTPUTDEVPIXMAP
......@@ -31,9 +31,10 @@
namespace KPDF
{
PageWidget::PageWidget(QWidget* parent, const char* name)
PageWidget::PageWidget(QWidget* parent, const char* name, QMutex *docMutex)
: QScrollView(parent, name, WRepaintNoErase),
m_doc(0),
m_docMutex(docMutex),
m_zoomFactor( 1.0 ),
m_currentPage( 1 ),
m_pressedAction( 0 ),
......@@ -122,24 +123,24 @@ namespace KPDF
void PageWidget::drawContents ( QPainter *p, int clipx, int clipy, int clipw, int cliph )
{
QPixmap * m_pixmap = NULL;
QImage im;
QColor bc(KGlobalSettings::calculateAlternateBackgroundColor(KGlobalSettings::baseColor()));
if (m_outputdev)
m_pixmap = m_outputdev->getPixmap();
if ( m_pixmap != NULL && ! m_pixmap->isNull() )
im = m_outputdev->getImage();
if ( !im.isNull() )
{
p->drawPixmap ( clipx, clipy, *m_pixmap, clipx, clipy, clipw, cliph );
if ((clipw + clipx) > m_pixmap->width())
p->fillRect ( m_pixmap->width(),
p->drawImage ( clipx, clipy, im, clipx, clipy, clipw, cliph );
if ((clipw + clipx) > im.width())
p->fillRect ( im.width(),
clipy,
clipw - (m_pixmap->width() - clipx),
m_pixmap->height() - clipy,
clipw - (im.width() - clipx),
im.height() - clipy,
bc );
if ((cliph + clipy) > m_pixmap->height())
if ((cliph + clipy) > im.height())
p->fillRect ( clipx,
m_pixmap->height(),
im.height(),
clipw,
cliph - (m_pixmap->height() - clipy),
cliph - (im.height() - clipy),
bc );
if (m_selection)
{
......@@ -300,9 +301,11 @@ namespace KPDF
const float ppp = basePpp * m_zoomFactor; // pixels per point
m_docMutex->lock();
m_doc->displayPage(m_outputdev, m_currentPage, ppp * 72.0, ppp * 72.0, 0, true, true);
m_docMutex->unlock();
resizeContents ( m_outputdev->getPixmap()->width ( ), m_outputdev->getPixmap()->height ( ));
resizeContents ( m_outputdev->getImage().width ( ), m_outputdev->getImage().height ( ));
viewport()->update();
}
......
......@@ -23,6 +23,8 @@
#include "CharTypes.h"
class QMutex;
class LinkAction;
class PDFDoc;
......@@ -40,7 +42,7 @@ namespace KPDF
enum ZoomMode { FitInWindow, FitWidth, FitVisible, FixedFactor };
public:
PageWidget(QWidget* parent = 0, const char* name = 0);
PageWidget(QWidget* parent, const char* name, QMutex *docMutex);
~PageWidget();
void setPDFDocument(PDFDoc*);
void setPixelsPerPoint(float);
......@@ -92,7 +94,7 @@ namespace KPDF
QOutputDevPixmap * m_outputdev;
PDFDoc* m_doc;
QMutex* m_docMutex;
float m_ppp; // Pixels per point
float m_zoomFactor;
ZoomMode m_zoomMode;
......
......@@ -28,6 +28,7 @@
#include <qwidget.h>
#include <qlistbox.h>
#include <qfile.h>
#include <qpainter.h>
#include <qtimer.h>
#include <kaction.h>
......@@ -56,7 +57,6 @@
#include "QOutputDevKPrinter.h"
#include "QOutputDevPixmap.h"
// #include "kpdf_canvas.h"
#include "kpdf_pagewidget.h"
typedef KParts::GenericFactory<KPDF::Part> KPDFPartFactory;
......@@ -82,7 +82,7 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
// we need an instance
setInstance(KPDFPartFactory::instance());
pdfpartview = new PDFPartView(parentWidget, widgetName);
pdfpartview = new PDFPartView(parentWidget, widgetName, &m_docMutex);
connect(pdfpartview, SIGNAL( clicked ( int ) ), this, SLOT( pageClicked ( int ) ));
......@@ -187,8 +187,9 @@ Part::Part(QWidget *parentWidget, const char *widgetName,
Part::~Part()
{
m_count--;
if (m_count == 0) delete globalParams;
pdfpartview->stopThumbnailGeneration();
writeSettings();
if (m_count == 0) delete globalParams;
delete m_doc;
}
......@@ -365,6 +366,7 @@ Part::createAboutData()
bool
Part::closeURL()
{
pdfpartview->stopThumbnailGeneration();
delete m_doc;
m_doc = 0;
......@@ -393,38 +395,18 @@ Part::openFile()
if (m_doc->getNumPages() > 0)
{
// TODO use a qvaluelist<int> to pass aspect ratio?
// TODO move it to inside pdfpartview or even the thumbnail list itself?
pdfpartview->setPages(m_doc->getNumPages(), m_doc->getPageHeight(1)/m_doc->getPageWidth(1));
pdfpartview->generateThumbnails(m_doc);
m_outputDev->setPDFDocument(m_doc);
goToPage(1);
m_nextThumbnail=1;
QTimer::singleShot(10, this, SLOT(nextThumbnail()));
}
return true;
}
void Part::nextThumbnail()
{
// check the user did not change the document and we are trying to render somethiung that
// does not exist
if (m_nextThumbnail > m_doc->getNumPages()) return;
// Pixels per point when the zoomFactor is 1.
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
QOutputDevPixmap odev(paperColor);
odev.startDoc(m_doc->getXRef());
m_doc->displayPage(&odev, m_nextThumbnail, QPaintDevice::x11AppDpiX(), QPaintDevice::x11AppDpiY(), 0, true, true);
pdfpartview->setThumbnail(m_nextThumbnail, odev.getPixmap());
m_nextThumbnail++;
if (m_nextThumbnail <= m_doc->getNumPages())
QTimer::singleShot(10, this, SLOT(nextThumbnail()));
}
void
Part::fileSaveAs()
{
......@@ -758,11 +740,14 @@ void Part::doPrint( KPrinter& printer )
QOutputDevKPrinter printdev( painter, paperColor, printer );
printdev.startDoc(m_doc->getXRef());
QValueList<int> pages = printer.pageList();
for ( QValueList<int>::ConstIterator i = pages.begin(); i != pages.end();)
{
m_docMutex.lock();
m_doc->displayPage(&printdev, *i, printer.resolution(), printer.resolution(), 0, true, true);
if ( ++i != pages.end() )
printer.newPage();
m_docMutex.unlock();
}
}
......@@ -809,7 +794,9 @@ void Part::doFind(QString s, bool next)
pg = m_currentPage + 1;
while(!found && pg <= m_doc->getNumPages())
{
m_docMutex.lock();
m_doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse);
m_docMutex.unlock();
found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1);
if (!found) pg++;
}
......@@ -822,7 +809,9 @@ void Part::doFind(QString s, bool next)
pg = 1;
while(!found && pg < m_currentPage)
{
m_docMutex.lock();
m_doc->displayPage(textOut, pg, 72, 72, 0, gTrue, gFalse);
m_docMutex.unlock();
found = textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, &xMin1, &yMin1, &xMax1, &yMax1);
if (!found) pg++;
}
......
......@@ -16,8 +16,7 @@
#ifndef _KPDF_PART_H_
#define _KPDF_PART_H_
#include <qpainter.h>
#include <qpixmap.h>
#include <qmutex.h>
#include <qwidget.h>
#include <kparts/browserextension.h>
......@@ -25,8 +24,6 @@
#include "QOutputDev.h"
class QPainter;
class QPixmap;
class QWidget;
class KAboutData;
......@@ -150,10 +147,10 @@ namespace KPDF
// first page is page 1
int m_currentPage;
QMutex m_docMutex;
ZoomMode m_zoomMode;
float m_zoomFactor;
int m_nextThumbnail;
static unsigned int m_count;
......@@ -161,7 +158,6 @@ namespace KPDF
void slotFitToWidthToggled();
void redrawPage();
void pageClicked ( int );
void nextThumbnail();
void fileSaveAs();
};
......
......@@ -19,17 +19,17 @@
* Constructs a PDFPartView as a child of 'parent', with the
* name 'name'
*/
PDFPartView::PDFPartView(QWidget* parent, const char* name) : QWidget(parent, name)
PDFPartView::PDFPartView(QWidget* parent, const char* name, QMutex *docMutex) : QWidget(parent, name)
{
PDFPartViewLayout = new QHBoxLayout( this, 11, 6, "PDFPartViewLayout");
pagesList = new ThumbnailList(this);
pagesList = new ThumbnailList(this, docMutex);
pagesList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)7, 0, 0, pagesList->sizePolicy().hasHeightForWidth() ) );
pagesList->setMaximumSize( QSize( 75, 32767 ) );
pagesList->setColumnWidth(0, 75);
PDFPartViewLayout->addWidget( pagesList );
outputdev = new KPDF::PageWidget( this, "outputdev" );
outputdev = new KPDF::PageWidget( this, "outputdev", docMutex );
PDFPartViewLayout->addWidget( outputdev );
resize( QSize(623, 381).expandedTo(minimumSizeHint()) );
clearWState( WState_Polished );
......@@ -56,9 +56,14 @@ void PDFPartView::setPages(int i, double ar)
pagesList->setPages(i, ar);
}
void PDFPartView::setThumbnail(int i, const QPixmap *thumbnail)
void PDFPartView::generateThumbnails(PDFDoc *doc)
{
pagesList->setThumbnail(i, thumbnail);
pagesList->generateThumbnails(doc);
}
void PDFPartView::stopThumbnailGeneration()
{
pagesList->stopThumbnailGeneration();
}
void PDFPartView::showPageList(bool show)
......
......@@ -10,16 +10,17 @@
#ifndef PDFPARTVIEW_H
#define PDFPARTVIEW_H
#include <qpixmap.h>
#include <qwidget.h>
class QHBoxLayout;
class QPixmap;
class QMutex;
namespace KPDF {
class PageWidget;
class PageWidget;
}
class PDFDoc;
class ThumbnailList;
class PDFPartView : public QWidget
......@@ -27,15 +28,16 @@ class PDFPartView : public QWidget
Q_OBJECT
public:
PDFPartView(QWidget* parent, const char* name);
PDFPartView(QWidget* parent, const char* name, QMutex *docMutex);
~PDFPartView();
// first page is page 1
void setCurrentThumbnail(int i);
void setPages(int i, double ar);
void setThumbnail(int i, const QPixmap *thumbnail);
void setPages(int i, double ar);
void generateThumbnails(PDFDoc *doc);
void stopThumbnailGeneration();
void showPageList(bool show);
// TODO make private
......
......@@ -24,19 +24,20 @@ Thumbnail::Thumbnail(QWidget *parent, const QString &text, const QColor &color,
setPaletteBackgroundColor(m_backgroundColor);
}
void Thumbnail::setPixmap(const QPixmap *thumbnail)
void Thumbnail::setImage(const QImage *thumbnail)
{
m_original = thumbnail->convertToImage().smoothScale(m_thumbnailW->size());
// TODO i am almost sure this can be done inside the thumbnailgenerator thread
m_original = thumbnail->smoothScale(m_thumbnailW->size());
m_thumbnailW->setPaletteBackgroundPixmap(m_original);
}
void Thumbnail::setPixmapSize(int height, int width)
void Thumbnail::setImageSize(int height, int width)
{
m_thumbnailW->setFixedHeight(height);
m_thumbnailW->setFixedWidth(width);
}
int Thumbnail::getPixmapHeight() const
int Thumbnail::getImageHeight() const
{
return m_thumbnailW->size().height();
}
......
......@@ -11,6 +11,7 @@
#define THUMBNAIL_H
#include <qcolor.h>
#include <qimage.h>
#include <qvbox.h>
class QLabel;
......@@ -22,9 +23,9 @@ public:
Thumbnail(QWidget *parent, const QString &text, const QColor &color, int height, int width);
public slots:
void setPixmap(const QPixmap *thumbnail);
void setPixmapSize(int height, int width);
int getPixmapHeight() const;
void setImage(const QImage *thumbnail);
void setImageSize(int height, int width);
int getImageHeight() const;
void setSelected(bool selected);
int labelSizeHintHeight();
......
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* *
* 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 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qapplication.h>
#include <qevent.h>
#include <qimage.h>
#include <qmutex.h>
#include "PDFDoc.h"
#include "thumbnailgenerator.h"
ThumbnailGenerator::ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o) : m_doc(doc), m_docMutex(docMutex), m_page(page), m_o(o), m_ppp(ppp)
{
}
int ThumbnailGenerator::getPage() const
{
return m_page;
}
void ThumbnailGenerator::run()
{
QCustomEvent *ce;
QImage *i;
SplashColor paperColor;
paperColor.rgb8 = splashMakeRGB8(0xff, 0xff, 0xff);
QOutputDevPixmap 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);
QApplication::postEvent(m_o, ce);
}
/***************************************************************************
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
* *
* 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 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef THUMBNAILGENERATOR_H
#define THUMBNAILGENERATOR_H
#include <qthread.h>
#include "QOutputDevPixmap.h"
class QMutex;
class PDFDoc;
class ThumbnailGenerator : public QThread
{
public:
ThumbnailGenerator(PDFDoc *doc, QMutex *docMutex, int page, double ppp, QObject *o);
int getPage() const;
protected:
void run();
private:
PDFDoc *m_doc;
QMutex *m_docMutex;
int m_page;
QObject *m_o;
double m_ppp;
};
#endif
......@@ -9,10 +9,13 @@
#include <math.h>
#include "PDFDoc.h"
#include "thumbnailgenerator.h"
#include "thumbnaillist.h"
#include "thumbnail.h"
ThumbnailList::ThumbnailList(QWidget *parent) : QTable(parent)
ThumbnailList::ThumbnailList(QWidget *parent, QMutex *docMutex) : QTable(parent), m_tg(0), m_doc(0), m_docMutex(docMutex)
{
setNumCols(1);
setLeftMargin(0);
......@@ -25,6 +28,15 @@ ThumbnailList::ThumbnailList(QWidget *parent) : QTable(parent)
connect(this, SIGNAL(currentChanged(int, int)), this, SLOT(changeSelected(int)));
}
ThumbnailList::~ThumbnailList()
{
if (m_tg)
{
m_tg->wait();
delete m_tg;
}
}
void ThumbnailList::setCurrentItem(int i)
{
setCurrentCell(i, 0);
......@@ -41,6 +53,54 @@ void ThumbnailList::changeSelected(int i)
if (t) t -> setSelected(true);
}
void ThumbnailList::generateThumbnails(PDFDoc *doc)
{
m_nextThumbnail = 1;
m_doc = doc;
generateNextThumbnail();
}
void ThumbnailList::generateNextThumbnail()
{
if (m_tg)
{
m_tg->wait();
delete m_tg;
}
m_tg = new ThumbnailGenerator(m_doc, m_docMutex, m_nextThumbnail, QPaintDevice::x11AppDpiX(), this);
m_tg->start(QThread::IdlePriority);
}
void ThumbnailList::stopThumbnailGeneration()
{
if (m_tg)
{
m_ignoreNext = true;
m_tg->wait();
delete m_tg;
m_tg = 0;
}
}
void ThumbnailList::customEvent(QCustomEvent *e)
{
if (e->type() == 65432 && !m_ignoreNext)
{
QImage *i = (QImage*)(e -> data());
setThumbnail(m_nextThumbnail, i);
m_nextThumbnail++;
if (m_nextThumbnail <= m_doc->getNumPages()) generateNextThumbnail();
else
{