QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsrasterviewport.h
qgsmaptopixel.h
QgsRasterDrawer::QgsRasterDrawer
QgsRasterDrawer(QgsRasterIterator *iterator, double dpiTarget=-1.0)
The QgsRasterDrawer constructor.
Definition: qgsrasterdrawer.cpp:32
qgsrasterdrawer.h
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsRasterViewPort::mTopLeftPoint
QgsPointXY mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
Definition: qgsrasterviewport.h:59
QgsRasterViewPort
Definition: qgsrasterviewport.h:34
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsrasteriterator.h
qgsrasterinterface.h
QgsRasterDrawer::draw
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *qgsMapToPixel, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
Definition: qgsrasterdrawer.cpp:38
qgsrasterblock.h
QgsMapToPixel::mapHeight
int mapHeight() const
Returns current map height in pixels.
Definition: qgsmaptopixel.h:247
QgsMapToPixel::mapRotation
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
Definition: qgsmaptopixel.h:269
QgsRasterIterator::startRasterRead
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
Definition: qgsrasteriterator.cpp:77
qgsrendercontext.h
QgsRasterBlockFeedback::renderPartialOutput
bool renderPartialOutput() const
Whether our painter is drawing to a temporary image used just by this layer.
Definition: qgsrasterinterface.h:85
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsRasterIterator
Iterator for sequentially processing raster cells.
Definition: qgsrasteriterator.h:34
QgsRasterIterator::readNextRasterPart
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...
Definition: qgsrasteriterator.cpp:104
QgsRasterDrawer::drawImage
void drawImage(QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *mapToPixel=nullptr) const
Draws raster part.
Definition: qgsrasterdrawer.cpp:120
QgsRasterViewPort::mHeight
qgssize mHeight
Height, number of rows to be rendered.
Definition: qgsrasterviewport.h:71
QgsRasterViewPort::mWidth
qgssize mWidth
Width, number of columns to be rendered.
Definition: qgsrasterviewport.h:68
c
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
Definition: porting_processing.dox:1
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsMapToPixel::mapWidth
int mapWidth() const
Returns the current map width in pixels.
Definition: qgsmaptopixel.h:239
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsRasterBlockFeedback
Feedback object tailored for raster block reading.
Definition: qgsrasterinterface.h:41
qgslogger.h
QgsRasterViewPort::mDrawnExtent
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.
Definition: qgsrasterviewport.h:74