QGIS API Documentation  2.17.0-Master (0497e4a)
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 "qgsrasterdrawer.h"
20 #include "qgsrasterinterface.h"
21 #include "qgsrasteriterator.h"
22 #include "qgsrasterviewport.h"
23 #include "qgsmaptopixel.h"
24 #include "qgsrendercontext.h"
25 #include <QImage>
26 #include <QPainter>
27 #include <QPrinter>
28 
29 QgsRasterDrawer::QgsRasterDrawer( QgsRasterIterator* iterator ): mIterator( iterator )
30 {
31 }
32 
33 void QgsRasterDrawer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel, const QgsRenderContext *ctx, QgsRasterBlockFeedback* feedback )
34 {
35  QgsDebugMsgLevel( "Entered", 4 );
36  if ( !p || !mIterator || !viewPort || !theQgsMapToPixel )
37  {
38  return;
39  }
40 
41  // last pipe filter has only 1 band
42  int bandNumber = 1;
43  mIterator->startRasterRead( bandNumber, viewPort->mWidth, viewPort->mHeight, viewPort->mDrawnExtent, feedback );
44 
45  //number of cols/rows in output pixels
46  int nCols = 0;
47  int nRows = 0;
48  //shift to top left point for the raster part
49  int topLeftCol = 0;
50  int topLeftRow = 0;
51 
52  // We know that the output data type of last pipe filter is QImage data
53 
54  QgsRasterBlock *block;
55 
56  // readNextRasterPart calcs and resets nCols, nRows, topLeftCol, topLeftRow
57  while ( mIterator->readNextRasterPart( bandNumber, nCols, nRows,
58  &block, topLeftCol, topLeftRow ) )
59  {
60  if ( !block )
61  {
62  QgsDebugMsg( "Cannot get block" );
63  continue;
64  }
65 
66  QImage img = block->image();
67 
68  // Because of bug in Acrobat Reader we must use "white" transparent color instead
69  // of "black" for PDF. See #9101.
70  QPrinter *printer = dynamic_cast<QPrinter *>( p->device() );
71  if ( printer && printer->outputFormat() == QPrinter::PdfFormat )
72  {
73  QgsDebugMsgLevel( "PdfFormat", 4 );
74 
75  img = img.convertToFormat( QImage::Format_ARGB32 );
76  QRgb transparentBlack = qRgba( 0, 0, 0, 0 );
77  QRgb transparentWhite = qRgba( 255, 255, 255, 0 );
78  for ( int x = 0; x < img.width(); x++ )
79  {
80  for ( int y = 0; y < img.height(); y++ )
81  {
82  if ( img.pixel( x, y ) == transparentBlack )
83  {
84  img.setPixel( x, y, transparentWhite );
85  }
86  }
87  }
88  }
89 
90  if ( feedback && feedback->renderPartialOutput() )
91  {
92  // there could have been partial preview written before
93  // so overwrite anything with the resulting image.
94  // (we are guaranteed to have a temporary image for this layer, see QgsMapRendererJob::needTemporaryImage)
95  p->setCompositionMode( QPainter::CompositionMode_Source );
96  }
97 
98  drawImage( p, viewPort, img, topLeftCol, topLeftRow, theQgsMapToPixel );
99 
100  delete block;
101 
102  p->setCompositionMode( QPainter::CompositionMode_SourceOver ); // go back to the default composition mode
103 
104  // ok this does not matter much anyway as the tile size quite big so most of the time
105  // there would be just one tile for the whole display area, but it won't hurt...
106  if ( feedback && feedback->isCancelled() )
107  break;
108 
109  // for compatibility
110  if ( ctx && ctx->renderingStopped() )
111  break;
112  }
113 }
114 
115 void QgsRasterDrawer::drawImage( QPainter* p, QgsRasterViewPort* viewPort, const QImage& img, int topLeftCol, int topLeftRow, const QgsMapToPixel* theQgsMapToPixel ) const
116 {
117  if ( !p || !viewPort )
118  {
119  return;
120  }
121 
122  //top left position in device coords
123  QPoint tlPoint = QPoint( viewPort->mTopLeftPoint.x() + topLeftCol, viewPort->mTopLeftPoint.y() + topLeftRow );
124  p->save();
125  p->setRenderHint( QPainter::Antialiasing, false );
126 
127  // Blending problem was reported with PDF output if background color has alpha < 255
128  // in #7766, it seems to be a bug in Qt, setting a brush with alpha 255 is a workaround
129  // which should not harm anything
130  p->setBrush( QBrush( QColor( Qt::white ), Qt::NoBrush ) );
131 
132  if ( theQgsMapToPixel )
133  {
134  int w = theQgsMapToPixel->mapWidth();
135  int h = theQgsMapToPixel->mapHeight();
136 
137  double rotation = theQgsMapToPixel->mapRotation();
138  if ( rotation )
139  {
140  // both viewPort and image sizes are dependent on scale
141  double cx = w / 2.0;
142  double cy = h / 2.0;
143  p->translate( cx, cy );
144  p->rotate( rotation );
145  p->translate( -cx, -cy );
146  }
147  }
148 
149  p->drawImage( tlPoint, img );
150 
151 #if 0
152  // For debugging:
153  QRectF br = QRectF( tlPoint, img.size() );
154  QPointF c = br.center();
155  double rad = std::max( br.width(), br.height() ) / 10;
156  p->drawRoundedRect( br, rad, rad );
157  p->drawLine( QLineF( br.x(), br.y(), br.x() + br.width(), br.y() + br.height() ) );
158  p->drawLine( QLineF( br.x() + br.width(), br.y(), br.x(), br.y() + br.height() ) );
159 
160  double nw = br.width() * 0.5;
161  double nh = br.height() * 0.5;
162  br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
163  p->drawRoundedRect( br, rad, rad );
164 
165  nw = br.width() * 0.5;
166  nh = br.height() * 0.5;
167  br = QRectF( c - QPointF( nw / 2, nh / 2 ), QSize( nw, nh ) );
168  p->drawRoundedRect( br, rad, rad );
169 #endif
170 
171  p->restore();
172 }
173 
void drawImage(QPainter *p, QgsRasterViewPort *viewPort, const QImage &img, int topLeftCol, int topLeftRow, const QgsMapToPixel *mapToPixel=nullptr) const
Draws raster part.
QImage convertToFormat(Format format, QFlags< Qt::ImageConversionFlag > flags) const
bool renderPartialOutput() const
Whether our painter is drawing to a temporary image used just by this layer.
Iterator for sequentially processing raster cells.
void setCompositionMode(CompositionMode mode)
void setRenderHint(RenderHint hint, bool on)
qreal x() const
qreal y() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setPixel(int x, int y, uint index_or_rgb)
int mWidth
Width, number of columns to be rendered.
bool renderingStopped() const
void save()
void rotate(qreal angle)
void drawLine(const QLineF &line)
bool isCancelled() const
Tells whether the operation has been cancelled already.
Definition: qgsfeedback.h:62
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
double mapRotation() const
Return current map rotation in degrees.
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
QRgb pixel(int x, int y) const
int mapWidth() const
Return current map width in pixels The information is only known if setRotation was used...
int mapHeight() const
Return current map height in pixels.
Raster data container.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
int width() const
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void draw(QPainter *p, QgsRasterViewPort *viewPort, const QgsMapToPixel *theQgsMapToPixel, const QgsRenderContext *ctx=nullptr, QgsRasterBlockFeedback *feedback=nullptr)
Draws raster data.
QPaintDevice * device() const
QgsRasterDrawer(QgsRasterIterator *iterator)
void setBrush(const QBrush &brush)
QPointF center() const
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...
QImage image() const
Get image if type is color.
void restore()
Contains information about the context of a rendering operation.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
qreal width() const
int mHeight
Distance in map units from bottom edge to top edge for the part of the raster that is to be rendered...
QSize size() const
void translate(const QPointF &offset)
OutputFormat outputFormat() const
qreal height() const
int height() const
QgsPoint mTopLeftPoint
Coordinate (in output device coordinate system) of top left corner of the part of the raster that is ...
This class provides details of the viewable area that a raster will be rendered into.
Feedback object tailored for raster block reading.
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
QgsRectangle mDrawnExtent
Intersection of current map extent and layer extent.