QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsimageoperation.h
Go to the documentation of this file.
1 /***************************************************************************
2  qgsimageoperation.h
3  --------------------
4  begin : January 2015
5  copyright : (C) 2015 by Nyall Dawson
6  email : [email protected]
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 #ifndef QGSIMAGEOPERATION_H
19 #define QGSIMAGEOPERATION_H
20 
21 #include <QImage>
22 #include "qgis_sip.h"
23 #include <QColor>
24 
25 #include "qgis_core.h"
26 #include <cmath>
27 
28 class QgsColorRamp;
29 
45 class CORE_EXPORT QgsImageOperation
46 {
47 
48  public:
49 
54  {
58  GrayscaleOff
59  };
60 
64  enum FlipType
65  {
67  FlipVertical
68  };
69 
75  static void convertToGrayscale( QImage &image, GrayscaleMode mode = GrayscaleLuminosity );
76 
87  static void adjustBrightnessContrast( QImage &image, int brightness, double contrast );
88 
97  static void adjustHueSaturation( QImage &image, double saturation, const QColor &colorizeColor = QColor(),
98  double colorizeStrength = 1.0 );
99 
105  static void multiplyOpacity( QImage &image, double factor );
106 
113  static void overlayColor( QImage &image, const QColor &color );
114 
117  {
118 
124  bool shadeExterior = true;
125 
130  bool useMaxDistance = true;
131 
136  double spread = 10.0;
137 
141  QgsColorRamp *ramp = nullptr;
142  };
143 
151  static void distanceTransform( QImage &image, const QgsImageOperation::DistanceTransformProperties &properties );
152 
162  static void stackBlur( QImage &image, int radius, bool alphaOnly = false );
163 
172  static QImage *gaussianBlur( QImage &image, int radius ) SIP_FACTORY;
173 
179  static void flipImage( QImage &image, FlipType type );
180 
191  static QRect nonTransparentImageRect( const QImage &image, QSize minSize = QSize(), bool center = false );
192 
202  static QImage cropTransparent( const QImage &image, QSize minSize = QSize(), bool center = false );
203 
204  private:
205 
206  //for blocked operations
207  enum LineOperationDirection
208  {
209  ByRow,
210  ByColumn
211  };
212  template <class BlockOperation> static void runBlockOperationInThreads( QImage &image, BlockOperation &operation, LineOperationDirection direction );
213  struct ImageBlock
214  {
215  unsigned int beginLine;
216  unsigned int endLine;
217  unsigned int lineLength;
218  QImage *image = nullptr;
219  };
220 
221  //for rect operations
222  template <typename RectOperation> static void runRectOperation( QImage &image, RectOperation &operation );
223  template <class RectOperation> static void runRectOperationOnWholeImage( QImage &image, RectOperation &operation );
224 
225  //for per pixel operations
226  template <class PixelOperation> static void runPixelOperation( QImage &image, PixelOperation &operation );
227  template <class PixelOperation> static void runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation );
228  template <class PixelOperation>
229  struct ProcessBlockUsingPixelOperation
230  {
231  explicit ProcessBlockUsingPixelOperation( PixelOperation &operation )
232  : mOperation( operation ) { }
233 
234  typedef void result_type;
235 
236  void operator()( ImageBlock &block )
237  {
238  for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
239  {
240  QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
241  for ( unsigned int x = 0; x < block.lineLength; ++x )
242  {
243  mOperation( ref[x], x, y );
244  }
245  }
246  }
247 
248  PixelOperation &mOperation;
249  };
250 
251  //for linear operations
252  template <typename LineOperation> static void runLineOperation( QImage &image, LineOperation &operation );
253  template <class LineOperation> static void runLineOperationOnWholeImage( QImage &image, LineOperation &operation );
254  template <class LineOperation>
255  struct ProcessBlockUsingLineOperation
256  {
257  explicit ProcessBlockUsingLineOperation( LineOperation &operation )
258  : mOperation( operation ) { }
259 
260  typedef void result_type;
261 
262  void operator()( ImageBlock &block )
263  {
264  //do something with whole lines
265  int bpl = block.image->bytesPerLine();
266  if ( mOperation.direction() == ByRow )
267  {
268  for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
269  {
270  QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
271  mOperation( ref, block.lineLength, bpl );
272  }
273  }
274  else
275  {
276  //by column
277  unsigned char *ref = block.image->scanLine( 0 ) + 4 * block.beginLine;
278  for ( unsigned int x = block.beginLine; x < block.endLine; ++x, ref += 4 )
279  {
280  mOperation( reinterpret_cast< QRgb * >( ref ), block.lineLength, bpl );
281  }
282  }
283  }
284 
285  LineOperation &mOperation;
286  };
287 
288 
289  //individual operation implementations
290 
291  class GrayscalePixelOperation
292  {
293  public:
294  explicit GrayscalePixelOperation( const GrayscaleMode mode )
295  : mMode( mode )
296  { }
297 
298  void operator()( QRgb &rgb, int x, int y );
299 
300  private:
301  GrayscaleMode mMode;
302  };
303  static void grayscaleLightnessOp( QRgb &rgb );
304  static void grayscaleLuminosityOp( QRgb &rgb );
305  static void grayscaleAverageOp( QRgb &rgb );
306 
307 
308  class BrightnessContrastPixelOperation
309  {
310  public:
311  BrightnessContrastPixelOperation( const int brightness, const double contrast )
312  : mBrightness( brightness )
313  , mContrast( contrast )
314  { }
315 
316  void operator()( QRgb &rgb, int x, int y );
317 
318  private:
319  int mBrightness;
320  double mContrast;
321  };
322 
323 
324  class HueSaturationPixelOperation
325  {
326  public:
327  HueSaturationPixelOperation( const double saturation, const bool colorize,
328  const int colorizeHue, const int colorizeSaturation,
329  const double colorizeStrength )
330  : mSaturation( saturation )
331  , mColorize( colorize )
332  , mColorizeHue( colorizeHue )
333  , mColorizeSaturation( colorizeSaturation )
334  , mColorizeStrength( colorizeStrength )
335  { }
336 
337  void operator()( QRgb &rgb, int x, int y );
338 
339  private:
340  double mSaturation; // [0, 2], 1 = no change
341  bool mColorize;
342  int mColorizeHue;
343  int mColorizeSaturation;
344  double mColorizeStrength; // [0,1]
345  };
346  static int adjustColorComponent( int colorComponent, int brightness, double contrastFactor );
347 
348 
349  class MultiplyOpacityPixelOperation
350  {
351  public:
352  explicit MultiplyOpacityPixelOperation( const double factor )
353  : mFactor( factor )
354  { }
355 
356  void operator()( QRgb &rgb, int x, int y );
357 
358  private:
359  double mFactor;
360  };
361 
362  class ConvertToArrayPixelOperation
363  {
364  public:
365  ConvertToArrayPixelOperation( const int width, double *array, const bool exterior = true )
366  : mWidth( width )
367  , mArray( array )
368  , mExterior( exterior )
369  {
370  }
371 
372  void operator()( QRgb &rgb, int x, int y );
373 
374  private:
375  int mWidth;
376  double *mArray = nullptr;
377  bool mExterior;
378  };
379 
380  class ShadeFromArrayOperation
381  {
382  public:
383  ShadeFromArrayOperation( const int width, double *array, const double spread,
384  const DistanceTransformProperties &properties )
385  : mWidth( width )
386  , mArray( array )
387  , mSpread( spread )
388  , mProperties( properties )
389  {
390  mSpreadSquared = std::pow( mSpread, 2.0 );
391  }
392 
393  void operator()( QRgb &rgb, int x, int y );
394 
395  private:
396  int mWidth;
397  double *mArray = nullptr;
398  double mSpread;
399  double mSpreadSquared;
400  const DistanceTransformProperties &mProperties;
401  };
402  static void distanceTransform2d( double *im, int width, int height );
403  static void distanceTransform1d( double *f, int n, int *v, double *z, double *d );
404  static double maxValueInDistanceTransformArray( const double *array, unsigned int size );
405 
406 
407  class StackBlurLineOperation
408  {
409  public:
410  StackBlurLineOperation( int alpha, LineOperationDirection direction, bool forwardDirection, int i1, int i2 )
411  : mAlpha( alpha )
412  , mDirection( direction )
413  , mForwardDirection( forwardDirection )
414  , mi1( i1 )
415  , mi2( i2 )
416  { }
417 
418  typedef void result_type;
419 
420  LineOperationDirection direction() { return mDirection; }
421 
422  void operator()( QRgb *startRef, int lineLength, int bytesPerLine )
423  {
424  unsigned char *p = reinterpret_cast< unsigned char * >( startRef );
425  int rgba[4];
426  int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
427  if ( !mForwardDirection )
428  {
429  p += ( lineLength - 1 ) * increment;
430  increment = -increment;
431  }
432 
433  for ( int i = mi1; i <= mi2; ++i )
434  {
435  rgba[i] = p[i] << 4;
436  }
437 
438  p += increment;
439  for ( int j = 1; j < lineLength; ++j, p += increment )
440  {
441  for ( int i = mi1; i <= mi2; ++i )
442  {
443  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * mAlpha / 16 ) >> 4;
444  }
445  }
446  }
447 
448  private:
449  int mAlpha;
450  LineOperationDirection mDirection;
451  bool mForwardDirection;
452  int mi1;
453  int mi2;
454  };
455 
456  static double *createGaussianKernel( int radius );
457 
458  class GaussianBlurOperation
459  {
460  public:
461  GaussianBlurOperation( int radius, LineOperationDirection direction, QImage *destImage, double *kernel )
462  : mRadius( radius )
463  , mDirection( direction )
464  , mDestImage( destImage )
465  , mDestImageBpl( destImage->bytesPerLine() )
466  , mKernel( kernel )
467  {}
468 
469  typedef void result_type;
470 
471  void operator()( ImageBlock &block );
472 
473  private:
474  int mRadius;
475  LineOperationDirection mDirection;
476  QImage *mDestImage = nullptr;
477  int mDestImageBpl;
478  double *mKernel = nullptr;
479 
480  inline QRgb gaussianBlurVertical( int posy, unsigned char *sourceFirstLine, int sourceBpl, int height );
481  inline QRgb gaussianBlurHorizontal( int posx, unsigned char *sourceFirstLine, int width );
482  };
483 
484  //flip
485 
486 
487  class FlipLineOperation
488  {
489  public:
490  explicit FlipLineOperation( LineOperationDirection direction )
491  : mDirection( direction )
492  { }
493 
494  typedef void result_type;
495 
496  LineOperationDirection direction() { return mDirection; }
497 
498  void operator()( QRgb *startRef, int lineLength, int bytesPerLine );
499 
500  private:
501  LineOperationDirection mDirection;
502  };
503 
504 
505 };
506 
507 #endif // QGSIMAGEOPERATION_H
508 
Flip the image horizontally.
Contains operations and filters which apply to QImages.
Keep the lightness of the color, drops the saturation.
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
FlipType
Flip operation types.
Grayscale by perceptual luminosity (weighted sum of color RGB components)
Grayscale by taking average of color RGB components.
#define SIP_FACTORY
Definition: qgis_sip.h:76
GrayscaleMode
Modes for converting a QImage to grayscale.
Struct for storing properties of a distance transform operation.