PDA

View Full Version : QPainter bug or QPrinter bug?



lni
27th March 2009, 00:28
Hi,

Can someone please verify this? Click the 3rd button on the viewer, and print to a file, it appears to be a bug.



#include <QtGui>

class MyGraphicsView : public QGraphicsView {
public:
MyGraphicsView( QGraphicsScene * scene ) :
QGraphicsView( scene ) {
}

protected:

virtual void contextMenuEvent ( QContextMenuEvent * event ) {
QStringList al;
al << "Print..." << "Save as an image file...";

QMenu menu;
for ( QStringList::const_iterator it=al.begin(); it!=al.end(); it++ ) {
menu.addAction( (*it) );
}

QAction* action = menu.exec( event->globalPos() );
if ( action ) {
takeAction( al.indexOf( action->text() ) );
}

}

private:

void takeAction( int idx ) {
switch ( idx ) {
case 0: {
QPrinter printer( QPrinter::HighResolution );
printer.setDocName( "test" );
printer.setCreator( "test example" );
printer.setOrientation( QPrinter::Landscape );
QPrintDialog dialog( &printer );
if ( dialog.exec() ) {
QPainter painter( &printer );
scene()->render( &painter );
}
} break;
case 1: {
QString filter( "*.bmp *.jpg *.jpeg *.png *.ppm *.tiff *.xbm *.xpm" );
QString filename = QFileDialog::getSaveFileName( this, "Save as image",
"", filter );
if ( !filename.isEmpty() ) {
QRectF frame( scene()->sceneRect() );
frame.moveTo( 0., 0. );
QImage image( frame.size().toSize(), QImage::Format_RGB32 );
QPainter painter( &image );
painter.fillRect( frame, QBrush( Qt::white ) );
scene()->render( &painter );
if ( !image.save( filename ) ) {
qDebug() << "Fail to save file";
}
}
} break;
}

}

};

class MyImageItem : public QGraphicsItem {
public:

MyImageItem( QGraphicsItem* parent=0 ) :
QGraphicsItem( parent ) {
}

QRectF boundingRect() const {
return QRectF( 0, 0, 400, 400 );
}

void paint( QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget* widget ) {

QPen pen( Qt::red );
painter->setPen( pen );

// create a mono image
QImage image( boundingRect().size().toSize(), QImage::Format_Mono );

// set color1 to be transparent and fill the image
image.setColor( Qt::color1, Qt::transparent );
image.fill( Qt::color1 );

// set foreground color
image.setColor( Qt::color0, pen.color().rgb() );

for ( int ix = 0; ix < image.width(); ix++ ) {
image.setPixel( QPoint( ix, 1 ), Qt::color0 );
image.setPixel( QPoint( ix, image.height()/2 ), Qt::color0 );
image.setPixel( QPoint( ix, image.height() - 1 ), Qt::color0 );
}

for ( int iy = 0; iy < image.height(); iy++ ) {
image.setPixel( QPoint( 1, iy ), Qt::color0 );
image.setPixel( QPoint( image.width()/2, iy ), Qt::color0 );
image.setPixel( QPoint( image.width()-1, iy ), Qt::color0 );
}

painter->drawImage( image.rect(), image );
//painter->drawPixmap( QPoint( 0, 0 ), QBitmap::fromImage( image ) );

}

};

int main( int argc, char** argv )
{
QApplication app( argc, argv );
QGraphicsScene* scene( new QGraphicsScene );
scene->setSceneRect( QRectF( 0, 0, 450, 450 ) );

MyImageItem imgItem;
imgItem.setPos( 50, 50 );

scene->addItem( &imgItem );

// view
MyGraphicsView view( scene );
view.resize( 500, 500 );
view.show();

return app.exec();

}

faldzip
27th March 2009, 08:48
And what should happen? I can see 4 squares and i can right click on them and save them to file (see attachment). And the file looks exactly like the window content...

lni
27th March 2009, 13:59
Saving to image is fine. But when you print to a pdf file, it is bad...

Try this new example, it looks worse with text in my computer:


#include <QtGui>

class MyGraphicsView : public QGraphicsView {
public:
MyGraphicsView( QGraphicsScene * scene ) :
QGraphicsView( scene ) {
}

protected:

virtual void contextMenuEvent ( QContextMenuEvent * event ) {
QStringList al;
al << "Print..." << "Save as an image file...";

QMenu menu;
for ( QStringList::const_iterator it=al.begin(); it!=al.end(); it++ ) {
menu.addAction( (*it) );
}

QAction* action = menu.exec( event->globalPos() );
if ( action ) {
takeAction( al.indexOf( action->text() ) );
}

}

private:

void takeAction( int idx ) {
switch ( idx ) {
case 0: {
QPrinter printer( QPrinter::HighResolution );
printer.setDocName( "test" );
printer.setCreator( "test example" );
printer.setOrientation( QPrinter::Landscape );
QPrintDialog dialog( &printer );
if ( dialog.exec() ) {
QPainter painter( &printer );
scene()->render( &painter );
}
} break;
case 1: {
QString filter( "*.bmp *.jpg *.jpeg *.png *.ppm *.tiff *.xbm *.xpm" );
QString filename = QFileDialog::getSaveFileName( this, "Save as image",
"", filter );
if ( !filename.isEmpty() ) {
QRectF frame( scene()->sceneRect() );
frame.moveTo( 0., 0. );
QImage image( frame.size().toSize(), QImage::Format_RGB32 );
QPainter painter( &image );
painter.fillRect( frame, QBrush( Qt::white ) );
scene()->render( &painter );
if ( !image.save( filename ) ) {
qDebug() << "Fail to save file";
}
}
} break;
}

}

};

class MyImageItem : public QGraphicsItem {
public:

MyImageItem( QGraphicsItem* parent=0 ) :
QGraphicsItem( parent ) {
}

QRectF boundingRect() const {
return QRectF( 0, 0, 400, 400 );
}

void paint( QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget* widget ) {

QPen pen( Qt::red );
painter->setPen( pen );

QFont font = painter->font();
font.setPointSize( 16 );

painter->setFont( font );
painter->drawText( 30, 30, "Text behind a transparent image" );

// create a mono image
QImage image( boundingRect().size().toSize(), QImage::Format_Mono );

// set color1 to be transparent and fill the image
image.setColor( Qt::color1, Qt::transparent );
image.fill( Qt::color1 );

// set foreground color
image.setColor( Qt::color0, pen.color().rgb() );

for ( int ix = 0; ix < image.width(); ix++ ) {
image.setPixel( QPoint( ix, 1 ), Qt::color0 );
image.setPixel( QPoint( ix, image.height()/2 ), Qt::color0 );
image.setPixel( QPoint( ix, image.height() - 1 ), Qt::color0 );
}

for ( int iy = 0; iy < image.height(); iy++ ) {
image.setPixel( QPoint( 1, iy ), Qt::color0 );
image.setPixel( QPoint( image.width()/2, iy ), Qt::color0 );
image.setPixel( QPoint( image.width()-1, iy ), Qt::color0 );
}

painter->drawImage( image.rect(), image );
//painter->drawPixmap( QPoint( 0, 0 ), QBitmap::fromImage( image ) );

}

};

int main( int argc, char** argv )
{
QApplication app( argc, argv );
QGraphicsScene* scene( new QGraphicsScene );
scene->setSceneRect( QRectF( 0, 0, 450, 450 ) );

MyImageItem imgItem;
imgItem.setPos( 50, 50 );

scene->addItem( &imgItem );

// view
MyGraphicsView view( scene );
view.resize( 500, 500 );
view.show();

return app.exec();

}

wysota
29th March 2009, 17:31
What exactly is the problem?

lni
29th March 2009, 21:55
I attached 2 snapshots, 1st one is the plot by the program, 2nd one is a pdf output. It appears the pdf engine or QPrinter can't handle QImage::Format_Mono image that has transparent background... Also, the text is wrong too.

wysota
29th March 2009, 23:32
I think the general problem is that you don't into account that the screen and the pdf have different resolutions. I've been printing using Qt's PDF generator and I can assure you it works just fine.

As for the image, I'd say the Mono format gets stored as an image that doesn't support transparency (JPG maybe?) or it gets converted to such a format. Just to be sure it's not the problem with the pdf renderer in kpdf, check the file with some other viewer (okular or acroread).

lni
30th March 2009, 01:48
I have been trying in many different machines with different kernels. In Windows, I tried CutePDF writer (http://www.cutepdf.com/), as well as Adobe's pdf writer. In linux, I have tested on Fedora core 4 and core 10, as well as enterprise Linux 4.0. For pdf viewer, I have tried acrobat in windows. In Linux, I tried kpdf, evince, and okular. All of them give the same error result.

However, if I switch to QImage::Format_Indexed8, it works fine. But QImage::Format_Indexed8 is really a waste of resources. All I need is two colors in the image...

I don't know why the font is distorted by painter...

I just reported this bug to Cattell a few weeks ago:
http://www.qtsoftware.com/developer/task-tracker/index_html?id=245819&method=entry