QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgsrasterdrawer.cpp
Go to the documentation of this file.
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 "qgsrasterdrawer.h"
19
20#include "qgslogger.h"
21#include "qgsmaptopixel.h"
22#include "qgsrasterblock.h"
23#include "qgsrasterinterface.h"
24#include "qgsrasteriterator.h"
25#include "qgsrasterviewport.h"
26#include "qgsrendercontext.h"
27
28#include <QImage>
29#include <QPainter>
30#include <QPdfWriter>
31#include <QString>
32
33using namespace Qt::StringLiterals;
34
36 : mIterator( iterator )
37 , mDpiTarget( dpiTarget )
38{}
39
41 : mIterator( iterator )
42{}
43
45{
46 mDpiScaleFactor = context.dpiTarget() >= 0.0 ? context.dpiTarget() / ( context.scaleFactor() * 25.4 ) : 1.0;
47 mDevicePixelRatio = context.devicePixelRatio();
48
49 draw( context.painter(), viewPort, &context.mapToPixel(), feedback );
50}
51
52void QgsRasterDrawer::draw( QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback )
53{
54 QgsDebugMsgLevel( u"Entered"_s, 4 );
55 if ( !p || !mIterator || !viewPort || !qgsMapToPixel )
56 {
57 return;
58 }
59
60 if ( mDpiTarget >= 0 )
61 {
62 mDpiScaleFactor = mDpiTarget / p->device()->logicalDpiX();
63 }
64
65 // last pipe filter has only 1 band
66 const int bandNumber = 1;
67 mIterator
68 ->startRasterRead( bandNumber, std::floor( static_cast<double>( viewPort->mWidth ) * mDevicePixelRatio ), std::floor( static_cast<double>( viewPort->mHeight ) * mDevicePixelRatio ), viewPort->mDrawnExtent, feedback );
69
70 //number of cols/rows in output pixels
71 int nCols = 0;
72 int nRows = 0;
73 //shift to top left point for the raster part
74 int topLeftCol = 0;
75 int topLeftRow = 0;
76
77 // We know that the output data type of last pipe filter is QImage data
78
79 std::unique_ptr< QgsRasterBlock > block;
80
81 // readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow
82 while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows, block, topLeftCol, topLeftRow ) )
83 {
84 if ( !block )
85 {
86 QgsDebugError( u"Cannot get block"_s );
87 continue;
88 }
89
90 QImage img = block->image();
91
92 // Because of bug in Acrobat Reader we must use "white" transparent color instead
93 // of "black" for PDF. See #9101.
94 QPdfWriter *pdfWriter = dynamic_cast<QPdfWriter *>( p->device() );
95 if ( pdfWriter )
96 {
97 QgsDebugMsgLevel( u"PdfFormat"_s, 4 );
98
99 img = img.convertToFormat( QImage::Format_ARGB32 );
100 const QRgb transparentBlack = qRgba( 0, 0, 0, 0 );
101 const QRgb transparentWhite = qRgba( 255, 255, 255, 0 );
102 for ( int x = 0; x < img.width(); x++ )
103 {
104 for ( int y = 0; y < img.height(); y++ )
105 {
106 if ( img.pixel( x, y ) == transparentBlack )
107 {
108 img.setPixel( x, y, transparentWhite );
109 }
110 }
111 }
112 }
113
114 if ( feedback && feedback->renderPartialOutput() )
115 {
116 // there could have been partial preview written before
117 // so overwrite anything with the resulting image.
118 // (we are guaranteed to have a temporary image for this layer, see QgsMapRendererJob::needTemporaryImage)
119 p->setCompositionMode( QPainter::CompositionMode_Source );
120 }
121
122 drawImage( p, viewPort, img, topLeftCol, topLeftRow, qgsMapToPixel );
123
124 if ( feedback && feedback->renderPartialOutput() )
125 {
126 // go back to the default composition mode
127 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
128 }
129
130 // OK this does not matter much anyway as the tile size quite big so most of the time
131 // there would be just one tile for the whole display area, but it won't hurt...
132 if ( feedback && feedback->isCanceled() )
133 break;
134 }
135}
136
137void QgsRasterDrawer::drawImage( QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *qgsMapToPixel ) const
138{
139 if ( !p || !viewPort )
140 {
141 return;
142 }
143
144 // top left position in device coords
145 const QPoint tlPoint
146 = QPoint( std::floor( viewPort->mTopLeftPoint.x() + topLeftCol / mDpiScaleFactor / mDevicePixelRatio ), std::floor( viewPort->mTopLeftPoint.y() + topLeftRow / mDpiScaleFactor / mDevicePixelRatio ) );
147 const QgsScopedQPainterState painterState( p );
148
149 // Improve rendering of rasters on high DPI screens with Qt's auto scaling enabled
150 if ( !qgsDoubleNear( mDevicePixelRatio, 1.0 ) || !qgsDoubleNear( mDpiScaleFactor, 1.0 ) )
151 {
152 p->setRenderHint( QPainter::SmoothPixmapTransform, true );
153 }
154
155 // Blending problem was reported with PDF output if background color has alpha < 255
156 // in #7766, it seems to be a bug in Qt, setting a brush with alpha 255 is a workaround
157 // which should not harm anything
158 p->setBrush( QBrush( QColor( Qt::white ), Qt::NoBrush ) );
159 if ( qgsMapToPixel )
160 {
161 const int w = qgsMapToPixel->mapWidth();
162 const int h = qgsMapToPixel->mapHeight();
163 const double rotation = qgsMapToPixel->mapRotation();
164 if ( rotation )
165 {
166 // both viewPort and image sizes are dependent on scale
167 const double cx = w / 2.0;
168 const double cy = h / 2.0;
169 p->translate( cx, cy );
170 p->rotate( rotation );
171 p->translate( -cx, -cy );
172 }
173 }
174
175 p->drawImage( QRect( tlPoint.x(), tlPoint.y(), std::ceil( img.width() / mDpiScaleFactor / mDevicePixelRatio ), std::ceil( img.height() / mDpiScaleFactor / mDevicePixelRatio ) ), img );
176
177#if 0
178 // For debugging:
179 QRectF br = QRectF( tlPoint, img.size() / mDpiScaleFactor / devicePixelRatio );
180 QPointF c = br.center();
181 double rad = std::max( br.width(), br.height() ) / 10;
182 p->drawRoundedRect( br, rad, rad );
183 p->drawLine( QLineF( br.x(), br.y(), br.x() + br.width(), br.y() + br.height() ) );
184 p->drawLine( QLineF( br.x() + br.width(), br.y(), br.x(), br.y() + br.height() ) );
185
186 double nw = br.width() * 0.5;
187 double nh = br.height() * 0.5;
188 br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
189 p->drawRoundedRect( br, rad, rad );
190
191 nw = br.width() * 0.5;
192 nh = br.height() * 0.5;
193 br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
194 p->drawRoundedRect( br, rad, rad );
195#endif
196}
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
Perform transforms between map coordinates and device coordinates.
int mapHeight() const
Returns current map height in pixels.
int mapWidth() const
Returns the current map width in pixels.
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Feedback object tailored for raster block reading.
bool renderPartialOutput() const
Whether our painter is drawing to a temporary image used just by this layer.
void drawImage(QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *mapToPixel=nullptr) const
Draws raster part.
Q_DECL_DEPRECATED QgsRasterDrawer(QgsRasterIterator *iterator, double dpiTarget)
The QgsRasterDrawer constructor.
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
Iterator for sequentially processing raster cells.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
float devicePixelRatio() const
Returns the device pixel ratio.
double dpiTarget() const
Returns the targeted DPI for rendering.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Scoped object for saving and restoring a QPainter object's state.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
This class provides details of the viewable area that a raster will be rendered into.
qgssize mHeight
Height, number of rows to be rendered.
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent, in map (destination) CRS.
qgssize mWidth
Width, number of columns to be rendered.