Commit e68b6f3f authored by Albert Astals Cid's avatar Albert Astals Cid

2006-11-15 Albert Astals Cid <aacid@kde.org>

        * qt4/src/poppler-link.cc:
        * qt4/src/poppler-page.cc:
        * qt4/src/poppler-qt4.h:
        * qt4/src/poppler-document.cc:
        * qt4/src/poppler-private.h: Generalize the way we render the pages:
        merge all the Page::renderTo* functions in only one that renders on
        a QImage, taking into account the currently chosen backend.
        It is possible to switch rendering backend using the Document.
        Patch by Pino Toscano.

        * qt4/tests/stress-poppler-qt4.cpp:
        * qt4/tests/test-password-qt4.cpp:
        * qt4/tests/test-poppler-qt4.cpp: Adapt the tests to the changes in
        the rendering API of Page. Patch by Pino Toscano.
parent 37088dd3
2006-11-15 Albert Astals Cid <aacid@kde.org>
* qt4/src/poppler-link.cc:
* qt4/src/poppler-page.cc:
* qt4/src/poppler-qt4.h:
* qt4/src/poppler-document.cc:
* qt4/src/poppler-private.h: Generalize the way we render the pages:
merge all the Page::renderTo* functions in only one that renders on
a QImage, taking into account the currently chosen backend.
It is possible to switch rendering backend using the Document.
Patch by Pino Toscano.
* qt4/tests/stress-poppler-qt4.cpp:
* qt4/tests/test-password-qt4.cpp:
* qt4/tests/test-poppler-qt4.cpp: Adapt the tests to the changes in
the rendering API of Page. Patch by Pino Toscano.
2006-11-13 Albert Astals Cid <aacid@kde.org> 2006-11-13 Albert Astals Cid <aacid@kde.org>
* poppler/ArthurOutputDev.cc: Small fix to get colors right * poppler/ArthurOutputDev.cc: Small fix to get colors right
......
...@@ -417,6 +417,20 @@ namespace Poppler { ...@@ -417,6 +417,20 @@ namespace Poppler {
return m_doc->paperColor; return m_doc->paperColor;
} }
void Document::setRenderBackend( Document::RenderBackend backend )
{
// no need to delete the outputdev as for the moment we always create a splash one
// as the arthur one does not allow "precaching" due to it's signature
// delete m_doc->m_outputDev;
// m_doc->m_outputDev = NULL;
m_doc->m_backend = backend;
}
Document::RenderBackend Document::renderBackend() const
{
return m_doc->m_backend;
}
QDateTime convertDate( char *dateString ) QDateTime convertDate( char *dateString )
{ {
int year; int year;
......
...@@ -64,7 +64,7 @@ namespace Poppler { ...@@ -64,7 +64,7 @@ namespace Poppler {
int leftAux, topAux, rightAux, bottomAux; int leftAux, topAux, rightAux, bottomAux;
SplashOutputDev *sod = data.doc->getSplashOutputDev(); OutputDev *sod = data.doc->getOutputDev();
sod->cvtUserToDev( left, top, &leftAux, &topAux ); sod->cvtUserToDev( left, top, &leftAux, &topAux );
sod->cvtUserToDev( right, bottom, &rightAux, &bottomAux ); sod->cvtUserToDev( right, bottom, &rightAux, &bottomAux );
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtGui/QImage> #include <QtGui/QImage>
#include <QtGui/QPixmap> #include <QtGui/QPainter>
#include <GlobalParams.h> #include <GlobalParams.h>
#include <PDFDoc.h> #include <PDFDoc.h>
#include <Catalog.h> #include <Catalog.h>
...@@ -161,75 +161,81 @@ Page::~Page() ...@@ -161,75 +161,81 @@ Page::~Page()
delete m_page; delete m_page;
} }
QImage Page::splashRenderToImage(double xres, double yres, int x, int y, int w, int h, bool doLinks, Rotation rotate) const QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, bool doLinks, Rotation rotate) const
{ {
SplashOutputDev *output_dev = m_page->parentDoc->m_doc->getSplashOutputDev();
int rotation = (int)rotate * 90; int rotation = (int)rotate * 90;
QImage img;
m_page->parentDoc->m_doc->doc.displayPageSlice(output_dev, m_page->index + 1, xres, yres, switch(m_page->parentDoc->m_doc->m_backend)
rotation, false, true, doLinks, x, y, w, h);
SplashBitmap *bitmap = output_dev->getBitmap ();
int bw = bitmap->getWidth();
int bh = bitmap->getHeight();
SplashColorPtr dataPtr = output_dev->getBitmap()->getDataPtr();
if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
{ {
uchar c; case Poppler::Document::SplashBackend:
int count = bw * bh * 4;
for (int k = 0; k < count; k += 4)
{ {
c = dataPtr[k]; SplashOutputDev *splash_output = static_cast<SplashOutputDev *>(m_page->parentDoc->m_doc->getOutputDev());
dataPtr[k] = dataPtr[k+3];
dataPtr[k+3] = c;
c = dataPtr[k+1]; m_page->parentDoc->m_doc->doc.displayPageSlice(splash_output, m_page->index + 1, xres, yres,
dataPtr[k+1] = dataPtr[k+2]; rotation, false, true, doLinks, x, y, w, h);
dataPtr[k+2] = c;
}
}
// construct a qimage SHARING the raw bitmap data in memory
QImage img( dataPtr, bw, bh, QImage::Format_ARGB32 );
img = img.copy();
// unload underlying xpdf bitmap
output_dev->startPage( 0, NULL );
return img; SplashBitmap *bitmap = splash_output->getBitmap();
} int bw = bitmap->getWidth();
int bh = bitmap->getHeight();
QPixmap *Page::splashRenderToPixmap(double xres, double yres, int x, int y, int w, int h, bool doLinks, Rotation rotate) const SplashColorPtr dataPtr = splash_output->getBitmap()->getDataPtr();
{
QImage img = splashRenderToImage(xres, yres, x, y, w, h, doLinks, rotate);
// Turn the QImage into a QPixmap if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
QPixmap* out = new QPixmap(QPixmap::fromImage(img)); {
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;
return out; c = dataPtr[k+1];
} dataPtr[k+1] = dataPtr[k+2];
dataPtr[k+2] = c;
}
}
void Page::renderToPixmap(QPixmap *pixmap, double xres, double yres) const // construct a qimage SHARING the raw bitmap data in memory
{ QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
QPainter* painter = new QPainter(pixmap); img = tmpimg.copy();
painter->setRenderHint(QPainter::Antialiasing); // unload underlying xpdf bitmap
ArthurOutputDev output_dev(painter); splash_output->startPage( 0, NULL );
output_dev.startDoc(m_page->parentDoc->m_doc->doc.getXRef ()); break;
m_page->parentDoc->m_doc->doc.displayPageSlice(&output_dev, }
case Poppler::Document::ArthurBackend:
{
QSize size = pageSize();
QImage tmpimg(w == -1 ? size.width() : w, h == -1 ? size.height() : h, QImage::Format_ARGB32);
QPainter painter(&tmpimg);
painter.setRenderHint(QPainter::Antialiasing);
painter.save();
painter.translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y);
if (w == -1 && h == -1)
painter.scale((double)w/(double)size.width(), (double)h/(double)size.height());
ArthurOutputDev arthur_output(&painter);
arthur_output.startDoc(m_page->parentDoc->m_doc->doc.getXRef());
m_page->parentDoc->m_doc->doc.displayPageSlice(&arthur_output,
m_page->index + 1, m_page->index + 1,
xres, xres,
yres, yres,
0, rotation,
false, false,
true, true,
false, doLinks,
-1, x,
-1, y,
-1, w,
-1); h);
painter->end(); painter.restore();
painter.end();
img = tmpimg;
break;
}
}
return img;
} }
QString Page::text(const QRectF &r) const QString Page::text(const QRectF &r) const
...@@ -412,7 +418,7 @@ QSizeF Page::pageSizeF() const ...@@ -412,7 +418,7 @@ QSizeF Page::pageSizeF() const
QSize Page::pageSize() const QSize Page::pageSize() const
{ {
return QSize( (int)pageSizeF().width(), (int)pageSizeF().height() ); return pageSizeF().toSize();
} }
Page::Orientation Page::orientation() const Page::Orientation Page::orientation() const
...@@ -454,8 +460,9 @@ QList<Link*> Page::links() const ...@@ -454,8 +460,9 @@ QList<Link*> Page::links() const
xpdfLink->getRect( &left, &top, &right, &bottom ); xpdfLink->getRect( &left, &top, &right, &bottom );
QRectF linkArea; QRectF linkArea;
m_page->parentDoc->m_doc->m_splashOutputDev->cvtUserToDev( left, top, &leftAux, &topAux ); OutputDev *output_dev = m_page->parentDoc->m_doc->getOutputDev();
m_page->parentDoc->m_doc->m_splashOutputDev->cvtUserToDev( right, bottom, &rightAux, &bottomAux ); output_dev->cvtUserToDev( left, top, &leftAux, &topAux );
output_dev->cvtUserToDev( right, bottom, &rightAux, &bottomAux );
linkArea.setLeft(leftAux); linkArea.setLeft(leftAux);
linkArea.setTop(topAux); linkArea.setTop(topAux);
linkArea.setRight(rightAux); linkArea.setRight(rightAux);
......
...@@ -66,7 +66,8 @@ namespace Poppler { ...@@ -66,7 +66,8 @@ namespace Poppler {
class DocumentData { class DocumentData {
public: public:
DocumentData(GooString *filePath, GooString *ownerPassword, GooString *userPassword) : DocumentData(GooString *filePath, GooString *ownerPassword, GooString *userPassword) :
doc(filePath, ownerPassword, userPassword), m_fontInfoScanner(0), m_splashOutputDev(0) doc(filePath, ownerPassword, userPassword), m_fontInfoScanner(0),
m_backend(Document::SplashBackend), m_outputDev(0)
{ {
paperColor = Qt::white; paperColor = Qt::white;
// It might be more appropriate to delete these in PDFDoc // It might be more appropriate to delete these in PDFDoc
...@@ -80,25 +81,35 @@ namespace Poppler { ...@@ -80,25 +81,35 @@ namespace Poppler {
~DocumentData() ~DocumentData()
{ {
qDeleteAll(m_embeddedFiles); qDeleteAll(m_embeddedFiles);
delete m_splashOutputDev; delete m_outputDev;
delete m_fontInfoScanner; delete m_fontInfoScanner;
count --; count --;
if ( count == 0 ) delete globalParams; if ( count == 0 ) delete globalParams;
} }
SplashOutputDev *getSplashOutputDev() OutputDev *getOutputDev()
{ {
if (!m_splashOutputDev) if (!m_outputDev)
{ {
switch (m_backend)
{
case Document::ArthurBackend:
// create a splash backend even in case of the Arthur Backend
case Document::SplashBackend:
{
SplashColor bgColor; SplashColor bgColor;
bgColor[0] = paperColor.red(); bgColor[0] = paperColor.red();
bgColor[1] = paperColor.green(); bgColor[1] = paperColor.green();
bgColor[2] = paperColor.blue(); bgColor[2] = paperColor.blue();
m_splashOutputDev = new SplashOutputDev(splashModeRGB8Qt, 4, gFalse, bgColor); SplashOutputDev * splashOutputDev = new SplashOutputDev(splashModeRGB8Qt, 4, gFalse, bgColor);
m_splashOutputDev->startDoc(doc.getXRef()); splashOutputDev->startDoc(doc.getXRef());
m_outputDev = splashOutputDev;
break;
}
}
} }
return m_splashOutputDev; return m_outputDev;
} }
void addTocChildren( QDomDocument * docSyn, QDomNode * parent, GooList * items ) void addTocChildren( QDomDocument * docSyn, QDomNode * parent, GooList * items )
...@@ -161,8 +172,8 @@ namespace Poppler { ...@@ -161,8 +172,8 @@ namespace Poppler {
if (color != paperColor) if (color != paperColor)
{ {
paperColor = color; paperColor = color;
delete m_splashOutputDev; delete m_outputDev;
m_splashOutputDev = NULL; m_outputDev = NULL;
} }
} }
...@@ -183,7 +194,8 @@ namespace Poppler { ...@@ -183,7 +194,8 @@ namespace Poppler {
class PDFDoc doc; class PDFDoc doc;
bool locked; bool locked;
FontInfoScanner *m_fontInfoScanner; FontInfoScanner *m_fontInfoScanner;
SplashOutputDev *m_splashOutputDev; Document::RenderBackend m_backend;
OutputDev *m_outputDev;
QList<EmbeddedFile*> m_embeddedFiles; QList<EmbeddedFile*> m_embeddedFiles;
QColor paperColor; QColor paperColor;
static int count; static int count;
......
...@@ -234,18 +234,14 @@ namespace Poppler { ...@@ -234,18 +234,14 @@ namespace Poppler {
}; };
/** /**
Render the page to a QImage using the Splash renderer Render the page to a QImage using the specified renderer
This method can be used to render the page to a QPixmap. It
uses the "Splash" rendering engine. This method is reasonably
well-tested and has produced good output so far.
If x=y=w=h=-1, the method will automatically compute the If x=y=w=h=-1, the method will automatically compute the
size of the pixmap from the horizontal and vertical size of the pixmap from the horizontal and vertical
resolutions specified in xres and yres. Otherwise, the resolutions specified in xres and yres. Otherwise, the
method renders only a part of the page, specified by the method renders only a part of the page, specified by the
parameters (x, y, w, h) in pixel coordinates. The QPixmap parameters (x, y, w, h) in pixel coordinates. The returned
returned then has size (w, h), independent of the page QImage then has size (w, h), independent of the page
size. size.
\param x specifies the left x-coordinate of the box, in \param x specifies the left x-coordinate of the box, in
...@@ -274,54 +270,7 @@ namespace Poppler { ...@@ -274,54 +270,7 @@ namespace Poppler {
\returns a QImage of the page, or a null image on failure. \returns a QImage of the page, or a null image on failure.
*/ */
QImage splashRenderToImage(double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, bool doLinks = false, Rotation rotate = Rotate0) const; QImage renderToImage(double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, bool doLinks = false, Rotation rotate = Rotate0) const;
/**
Render the page to a QPixmap using the Splash renderer
This member function is provided for convenience. It behaves essentially like the above function.
It is used as follows.
@code
Poppler::Page* pdfPage;
// Generate a QPixmap of the rendered page
QPixmap* pixmap = pdfPage->splashRenderToPixmap(0, 0, 0, 0, xres, yres );
if (pixmap == 0) {
... error message ...
return;
}
... use pixmap ...
delete pixmap;
@endcode
*/
QPixmap *splashRenderToPixmap(double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, bool doLinks = false, Rotation rotate = Rotate0) const;
/**
Render the page to a pixmap using the Arthur (Qt4) renderer
\param q pointer to a QPixmap that is already set to the
intended size.
\param xres horizontal resolution of the graphics device,
in dots per inch
\param yres vertical resolution of the graphics device, in
dots per inch
You are meant to create the pixmap before passing it to
this routine, using something like:
\code
QPixmap* myPixmap = new QPixmap(page->pageSize());
page->renderToPixmap(myPixmap);
\endcode
\warning This is a work in progress. Results are unlikely to be of
high quality.
*/
void renderToPixmap(QPixmap *q, double xres=72.0, double yres=72.0) const;
/** /**
Returns the text that is inside a specified rectangle Returns the text that is inside a specified rectangle
...@@ -460,6 +409,14 @@ delete pixmap; ...@@ -460,6 +409,14 @@ delete pixmap;
TwoPageRight, ///< Display the pages two at a time, with odd-numbered pages on the right TwoPageRight, ///< Display the pages two at a time, with odd-numbered pages on the right
}; };
/**
The render backends available
*/
enum RenderBackend {
SplashBackend, ///< Splash backend
ArthurBackend, ///< Arthur (Qt4) backend
};
/** /**
Load the document from a file on disk Load the document from a file on disk
...@@ -712,6 +669,14 @@ delete pixmap; ...@@ -712,6 +669,14 @@ delete pixmap;
void setPaperColor(const QColor &color); void setPaperColor(const QColor &color);
QColor paperColor() const; QColor paperColor() const;
/**
Sets the backend used to render the pages.
The default backend is @ref SplashBackend
*/
void setRenderBackend( RenderBackend backend );
RenderBackend renderBackend() const;
~Document(); ~Document();
private: private:
......
...@@ -53,8 +53,7 @@ int main( int argc, char **argv ) ...@@ -53,8 +53,7 @@ int main( int argc, char **argv )
for( int index = 0; index < doc->numPages(); ++index ) { for( int index = 0; index < doc->numPages(); ++index ) {
Poppler::Page *page = doc->page( index ); Poppler::Page *page = doc->page( index );
QPixmap *pixmap = new QPixmap(page->pageSize()); QImage image = page->renderToImage();
page->renderToPixmap(pixmap);
page->pageSize(); page->pageSize();
page->orientation(); page->orientation();
delete page; delete page;
......
...@@ -17,7 +17,7 @@ protected: ...@@ -17,7 +17,7 @@ protected:
private: private:
void display(); void display();
int m_currentPage; int m_currentPage;
QPixmap *pixmap; QImage image;
Poppler::Document *doc; Poppler::Document *doc;
}; };
...@@ -34,8 +34,7 @@ void PDFDisplay::display() ...@@ -34,8 +34,7 @@ void PDFDisplay::display()
Poppler::Page *page = doc->page(m_currentPage); Poppler::Page *page = doc->page(m_currentPage);
if (page) { if (page) {
qDebug() << "Displaying page: " << m_currentPage; qDebug() << "Displaying page: " << m_currentPage;
pixmap = new QPixmap(page->pageSize()); image = page->renderToImage();
page->renderToPixmap(pixmap);
update(); update();
delete page; delete page;
} }
...@@ -47,16 +46,15 @@ void PDFDisplay::display() ...@@ -47,16 +46,15 @@ void PDFDisplay::display()
PDFDisplay::~PDFDisplay() PDFDisplay::~PDFDisplay()
{ {
delete doc; delete doc;
delete pixmap;
} }
void PDFDisplay::paintEvent( QPaintEvent *e ) void PDFDisplay::paintEvent( QPaintEvent *e )
{ {
QPainter paint( this ); // paint widget QPainter paint( this ); // paint widget
if (pixmap) { if (!image.isNull()) {
paint.drawPixmap(0, 0, *pixmap); paint.drawImage(0, 0, image);
} else { } else {
qWarning() << "no pixmap"; qWarning() << "null image";
} }
} }
......
...@@ -17,7 +17,7 @@ protected: ...@@ -17,7 +17,7 @@ protected:
private: private:
void display(); void display();
int m_currentPage; int m_currentPage;
QPixmap *pixmap; QImage image;
Poppler::Document *doc; Poppler::Document *doc;
bool useArthur; bool useArthur;
}; };
...@@ -25,7 +25,6 @@ private: ...@@ -25,7 +25,6 @@ private:
PDFDisplay::PDFDisplay( Poppler::Document *d, bool arthur ) PDFDisplay::PDFDisplay( Poppler::Document *d, bool arthur )
{ {
doc = d; doc = d;
pixmap = 0;
m_currentPage = 0; m_currentPage = 0;
useArthur = arthur; useArthur = arthur;
display(); display();
...@@ -39,15 +38,14 @@ void PDFDisplay::display() ...@@ -39,15 +38,14 @@ void PDFDisplay::display()
if (useArthur) if (useArthur)
{ {
qDebug() << "Displaying page using Arthur backend: " << m_currentPage; qDebug() << "Displaying page using Arthur backend: " << m_currentPage;
pixmap = new QPixmap(page->pageSize()); doc->setRenderBackend(Poppler::Document::ArthurBackend);
page->renderToPixmap(pixmap, 72.0, 72.0);
} }
else else
{ {
qDebug() << "Displaying page using Splash backend: " << m_currentPage; qDebug() << "Displaying page using Splash backend: " << m_currentPage;
delete pixmap; doc->setRenderBackend(Poppler::Document::SplashBackend);
pixmap = page->splashRenderToPixmap();
} }
image = page->renderToImage();
update(); update();
delete page; delete page;
} }
...@@ -59,16 +57,15 @@ void PDFDisplay::display() ...@@ -59,16 +57,15 @@ void PDFDisplay::display()
PDFDisplay::~PDFDisplay() PDFDisplay::~PDFDisplay()
{ {
delete doc; delete doc;
delete pixmap;
} }
void PDFDisplay::paintEvent( QPaintEvent *e ) void PDFDisplay::paintEvent( QPaintEvent *e )
{ {
QPainter paint( this ); // paint widget QPainter paint( this ); // paint widget
if (pixmap) { if (!image.isNull()) {
paint.drawPixmap(0, 0, *pixmap); paint.drawImage(0, 0, image);
} else { } else {
qWarning() << "no pixmap"; qWarning() << "null image";
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment