1 /***************************************************************************
2 qgsrasterdrawer.cpp
3 ---------------------
4 begin : June 2012
5 copyright : (C) 2012 by Radim Blazek
6 email : radim dot blazek at gmail.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgslogger.h"
19 #include "qgsrasterblock.h"
20 #include "qgsrasterdrawer.h"
21 #include "qgsrasterinterface.h"
22 #include "qgsrasteriterator.h"
23 #include "qgsrasterviewport.h"
24 #include "qgsmaptopixel.h"
25 #include "qgsrendercontext.h"
26 #include <QImage>
27 #include <QPainter>
28 #ifndef QT_NO_PRINTER
29 #include <QPrinter>
30 #endif
31
QgsRasterDrawer(QgsRasterIterator * iterator)32 QgsRasterDrawer::QgsRasterDrawer( QgsRasterIterator *iterator ): mIterator( iterator )
33 {
34 }
35
draw(QPainter * p,QgsRasterViewPort * viewPort,const QgsMapToPixel * qgsMapToPixel,QgsRasterBlockFeedback * feedback)36 void QgsRasterDrawer::draw( QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback )
37 {
38 QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
39 if ( !p || !mIterator || !viewPort || !qgsMapToPixel )
40 {
41 return;
42 }
43
44 // last pipe filter has only 1 band
45 int bandNumber = 1;
46 mIterator->startRasterRead( bandNumber, viewPort->mWidth, viewPort->mHeight, viewPort->mDrawnExtent, feedback );
47
48 //number of cols/rows in output pixels
49 int nCols = 0;
50 int nRows = 0;
51 //shift to top left point for the raster part
52 int topLeftCol = 0;
53 int topLeftRow = 0;
54
55 // We know that the output data type of last pipe filter is QImage data
56
57 std::unique_ptr< QgsRasterBlock > block;
58
59 // readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow
60 while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows,
61 block, topLeftCol, topLeftRow ) )
62 {
63 if ( !block )
64 {
65 QgsDebugMsg( QStringLiteral( "Cannot get block" ) );
66 continue;
67 }
68
69 QImage img = block->image();
70
71 #ifndef QT_NO_PRINTER
72 // Because of bug in Acrobat Reader we must use "white" transparent color instead
73 // of "black" for PDF. See #9101.
74 QPrinter *printer = dynamic_cast<QPrinter *>( p->device() );
75 if ( printer && printer->outputFormat() == QPrinter::PdfFormat )
76 {
77 QgsDebugMsgLevel( QStringLiteral( "PdfFormat" ), 4 );
78
79 img = img.convertToFormat( QImage::Format_ARGB32 );
80 QRgb transparentBlack = qRgba( 0, 0, 0, 0 );
81 QRgb transparentWhite = qRgba( 255, 255, 255, 0 );
82 for ( int x = 0; x < img.width(); x++ )
83 {
84 for ( int y = 0; y < img.height(); y++ )
85 {
86 if ( img.pixel( x, y ) == transparentBlack )
87 {
88 img.setPixel( x, y, transparentWhite );
89 }
90 }
91 }
92 }
93 #endif
94
95 if ( feedback && feedback->renderPartialOutput() )
96 {
97 // there could have been partial preview written before
98 // so overwrite anything with the resulting image.
99 // (we are guaranteed to have a temporary image for this layer, see QgsMapRendererJob::needTemporaryImage)
100 p->setCompositionMode( QPainter::CompositionMode_Source );
101 }
102
103 drawImage( p, viewPort, img, topLeftCol, topLeftRow, qgsMapToPixel );
104
105 if ( feedback && feedback->renderPartialOutput() )
106 {
107 // go back to the default composition mode
108 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
109 }
110
111 // OK this does not matter much anyway as the tile size quite big so most of the time
112 // there would be just one tile for the whole display area, but it won't hurt...
113 if ( feedback && feedback->isCanceled() )
114 break;
115 }
116 }
117
drawImage(QPainter * p,QgsRasterViewPort * viewPort,const QImage & img,int topLeftCol,int topLeftRow,const QgsMapToPixel * qgsMapToPixel) const118 void QgsRasterDrawer::drawImage( QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *qgsMapToPixel ) const
119 {
120 if ( !p || !viewPort )
121 {
122 return;
123 }
124
125 //top left position in device coords
126 QPoint tlPoint = QPoint( viewPort->mTopLeftPoint.x() + topLeftCol, viewPort->mTopLeftPoint.y() + topLeftRow );
127 QgsScopedQPainterState painterState( p );
128 p->setRenderHint( QPainter::Antialiasing, false );
129
130 // Blending problem was reported with PDF output if background color has alpha < 255
131 // in #7766, it seems to be a bug in Qt, setting a brush with alpha 255 is a workaround
132 // which should not harm anything
133 p->setBrush( QBrush( QColor( Qt::white ), Qt::NoBrush ) );
134
135 if ( qgsMapToPixel )
136 {
137 int w = qgsMapToPixel->mapWidth();
138 int h = qgsMapToPixel->mapHeight();
139
140 double rotation = qgsMapToPixel->mapRotation();
141 if ( rotation )
142 {
143 // both viewPort and image sizes are dependent on scale
144 double cx = w / 2.0;
145 double cy = h / 2.0;
146 p->translate( cx, cy );
147 p->rotate( rotation );
148 p->translate( -cx, -cy );
149 }
150 }
151
152 p->drawImage( tlPoint, img );
153
154 #if 0
155 // For debugging:
156 QRectF br = QRectF( tlPoint, img.size() );
157 QPointF c = br.center();
158 double rad = std::max( br.width(), br.height() ) / 10;
159 p->drawRoundedRect( br, rad, rad );
160 p->drawLine( QLineF( br.x(), br.y(), br.x() + br.width(), br.y() + br.height() ) );
161 p->drawLine( QLineF( br.x() + br.width(), br.y(), br.x(), br.y() + br.height() ) );
162
163 double nw = br.width() * 0.5;
164 double nh = br.height() * 0.5;
165 br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
166 p->drawRoundedRect( br, rad, rad );
167
168 nw = br.width() * 0.5;
169 nh = br.height() * 0.5;
170 br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
171 p->drawRoundedRect( br, rad, rad );
172 #endif
173 }
174
175