QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 "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 
33  : mIterator( iterator )
34  , mDpiTarget( dpiTarget )
35 {
36 }
37 
38 void QgsRasterDrawer::draw( QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback )
39 {
40  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
41  if ( !p || !mIterator || !viewPort || !qgsMapToPixel )
42  {
43  return;
44  }
45 
46  // last pipe filter has only 1 band
47  const int bandNumber = 1;
48  mIterator->startRasterRead( bandNumber, viewPort->mWidth, viewPort->mHeight, viewPort->mDrawnExtent, feedback );
49 
50  //number of cols/rows in output pixels
51  int nCols = 0;
52  int nRows = 0;
53  //shift to top left point for the raster part
54  int topLeftCol = 0;
55  int topLeftRow = 0;
56 
57  // We know that the output data type of last pipe filter is QImage data
58 
59  std::unique_ptr< QgsRasterBlock > block;
60 
61  // readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow
62  while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows,
63  block, topLeftCol, topLeftRow ) )
64  {
65  if ( !block )
66  {
67  QgsDebugMsg( QStringLiteral( "Cannot get block" ) );
68  continue;
69  }
70 
71  QImage img = block->image();
72 
73 #ifndef QT_NO_PRINTER
74  // Because of bug in Acrobat Reader we must use "white" transparent color instead
75  // of "black" for PDF. See #9101.
76  QPrinter *printer = dynamic_cast<QPrinter *>( p->device() );
77  if ( printer && printer->outputFormat() == QPrinter::PdfFormat )
78  {
79  QgsDebugMsgLevel( QStringLiteral( "PdfFormat" ), 4 );
80 
81  img = img.convertToFormat( QImage::Format_ARGB32 );
82  const QRgb transparentBlack = qRgba( 0, 0, 0, 0 );
83  const QRgb transparentWhite = qRgba( 255, 255, 255, 0 );
84  for ( int x = 0; x < img.width(); x++ )
85  {
86  for ( int y = 0; y < img.height(); y++ )
87  {
88  if ( img.pixel( x, y ) == transparentBlack )
89  {
90  img.setPixel( x, y, transparentWhite );
91  }
92  }
93  }
94  }
95 #endif
96 
97  if ( feedback && feedback->renderPartialOutput() )
98  {
99  // there could have been partial preview written before
100  // so overwrite anything with the resulting image.
101  // (we are guaranteed to have a temporary image for this layer, see QgsMapRendererJob::needTemporaryImage)
102  p->setCompositionMode( QPainter::CompositionMode_Source );
103  }
104 
105  drawImage( p, viewPort, img, topLeftCol, topLeftRow, qgsMapToPixel );
106 
107  if ( feedback && feedback->renderPartialOutput() )
108  {
109  // go back to the default composition mode
110  p->setCompositionMode( QPainter::CompositionMode_SourceOver );
111  }
112 
113  // OK this does not matter much anyway as the tile size quite big so most of the time
114  // there would be just one tile for the whole display area, but it won't hurt...
115  if ( feedback && feedback->isCanceled() )
116  break;
117  }
118 }
119 
120 void QgsRasterDrawer::drawImage( QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *qgsMapToPixel ) const
121 {
122  if ( !p || !viewPort )
123  {
124  return;
125  }
126 
127  const double dpiScaleFactor = mDpiTarget >= 0.0 ? mDpiTarget / p->device()->logicalDpiX() : 1.0;
128  //top left position in device coords
129  const QPoint tlPoint = QPoint( viewPort->mTopLeftPoint.x() + std::floor( topLeftCol / dpiScaleFactor ), viewPort->mTopLeftPoint.y() + std::floor( topLeftRow / dpiScaleFactor ) );
130 
131  const QgsScopedQPainterState painterState( p );
132  p->setRenderHint( QPainter::Antialiasing, false );
133 
134  // Blending problem was reported with PDF output if background color has alpha < 255
135  // in #7766, it seems to be a bug in Qt, setting a brush with alpha 255 is a workaround
136  // which should not harm anything
137  p->setBrush( QBrush( QColor( Qt::white ), Qt::NoBrush ) );
138  if ( qgsMapToPixel )
139  {
140  const int w = qgsMapToPixel->mapWidth();
141  const int h = qgsMapToPixel->mapHeight();
142  const double rotation = qgsMapToPixel->mapRotation();
143  if ( rotation )
144  {
145  // both viewPort and image sizes are dependent on scale
146  const double cx = w / 2.0;
147  const double cy = h / 2.0;
148  p->translate( cx, cy );
149  p->rotate( rotation );
150  p->translate( -cx, -cy );
151  }
152  }
153 
154  p->drawImage( tlPoint, dpiScaleFactor != 1.0 ? img.scaledToHeight( std::ceil( img.height() / dpiScaleFactor ) ) : img );
155 
156 #if 0
157  // For debugging:
158  QRectF br = QRectF( tlPoint, img.size() );
159  QPointF c = br.center();
160  double rad = std::max( br.width(), br.height() ) / 10;
161  p->drawRoundedRect( br, rad, rad );
162  p->drawLine( QLineF( br.x(), br.y(), br.x() + br.width(), br.y() + br.height() ) );
163  p->drawLine( QLineF( br.x() + br.width(), br.y(), br.x(), br.y() + br.height() ) );
164 
165  double nw = br.width() * 0.5;
166  double nh = br.height() * 0.5;
167  br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
168  p->drawRoundedRect( br, rad, rad );
169 
170  nw = br.width() * 0.5;
171  nh = br.height() * 0.5;
172  br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
173  p->drawRoundedRect( br, rad, rad );
174 #endif
175 }
176 
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
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:63
Q_GADGET double x
Definition: qgspointxy.h:62
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.
QgsRasterDrawer(QgsRasterIterator *iterator, double dpiTarget=-1.0)
The QgsRasterDrawer constructor.
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
Iterator for sequentially processing raster cells.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
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
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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.
qgssize mWidth
Width, number of columns to be rendered.