QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 "qgsfeedback.h"
27 #include <cmath>
28 
29 class QgsColorRamp;
30 class QgsFeedback;
31 
47 class CORE_EXPORT QgsImageOperation
48 {
49 
50  public:
51 
56  {
60  GrayscaleOff
61  };
62 
66  enum FlipType
67  {
69  FlipVertical
70  };
71 
78  static void convertToGrayscale( QImage &image, GrayscaleMode mode = GrayscaleLuminosity, QgsFeedback *feedback = nullptr );
79 
91  static void adjustBrightnessContrast( QImage &image, int brightness, double contrast, QgsFeedback *feedback = nullptr );
92 
102  static void adjustHueSaturation( QImage &image, double saturation, const QColor &colorizeColor = QColor(),
103  double colorizeStrength = 1.0, QgsFeedback *feedback = nullptr );
104 
111  static void multiplyOpacity( QImage &image, double factor, QgsFeedback *feedback = nullptr );
112 
119  static void overlayColor( QImage &image, const QColor &color );
120 
123  {
124 
130  bool shadeExterior = true;
131 
136  bool useMaxDistance = true;
137 
142  double spread = 10.0;
143 
147  QgsColorRamp *ramp = nullptr;
148  };
149 
158  static void distanceTransform( QImage &image, const QgsImageOperation::DistanceTransformProperties &properties, QgsFeedback *feedback = nullptr );
159 
170  static void stackBlur( QImage &image, int radius, bool alphaOnly = false, QgsFeedback *feedback = nullptr );
171 
181  static QImage *gaussianBlur( QImage &image, int radius, QgsFeedback *feedback = nullptr ) SIP_FACTORY;
182 
188  static void flipImage( QImage &image, FlipType type );
189 
200  static QRect nonTransparentImageRect( const QImage &image, QSize minSize = QSize(), bool center = false );
201 
211  static QImage cropTransparent( const QImage &image, QSize minSize = QSize(), bool center = false );
212 
213  private:
214 
215  //for blocked operations
216  enum LineOperationDirection
217  {
218  ByRow,
219  ByColumn
220  };
221  template <class BlockOperation> static void runBlockOperationInThreads( QImage &image, BlockOperation &operation, LineOperationDirection direction );
222  struct ImageBlock
223  {
224  unsigned int beginLine;
225  unsigned int endLine;
226  unsigned int lineLength;
227  QImage *image = nullptr;
228  };
229 
230  //for rect operations
231  template <typename RectOperation> static void runRectOperation( QImage &image, RectOperation &operation );
232  template <class RectOperation> static void runRectOperationOnWholeImage( QImage &image, RectOperation &operation );
233 
234  //for per pixel operations
235  template <class PixelOperation> static void runPixelOperation( QImage &image, PixelOperation &operation, QgsFeedback *feedback = nullptr );
236  template <class PixelOperation> static void runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation, QgsFeedback *feedback = nullptr );
237  template <class PixelOperation>
238  struct ProcessBlockUsingPixelOperation
239  {
240  explicit ProcessBlockUsingPixelOperation( PixelOperation &operation, QgsFeedback *feedback )
241  : mOperation( operation )
242  , mFeedback( feedback )
243  { }
244 
245  typedef void result_type;
246 
247  void operator()( ImageBlock &block )
248  {
249  for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
250  {
251  if ( mFeedback && mFeedback->isCanceled() )
252  break;
253 
254  QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
255  for ( unsigned int x = 0; x < block.lineLength; ++x )
256  {
257  mOperation( ref[x], x, y );
258  }
259  }
260  }
261 
262  PixelOperation &mOperation;
263  QgsFeedback *mFeedback = nullptr;
264  };
265 
266  //for linear operations
267  template <typename LineOperation> static void runLineOperation( QImage &image, LineOperation &operation, QgsFeedback *feedback = nullptr );
268  template <class LineOperation> static void runLineOperationOnWholeImage( QImage &image, LineOperation &operation, QgsFeedback *feedback = nullptr );
269  template <class LineOperation>
270  struct ProcessBlockUsingLineOperation
271  {
272  explicit ProcessBlockUsingLineOperation( LineOperation &operation )
273  : mOperation( operation ) { }
274 
275  typedef void result_type;
276 
277  void operator()( ImageBlock &block )
278  {
279  //do something with whole lines
280  int bpl = block.image->bytesPerLine();
281  if ( mOperation.direction() == ByRow )
282  {
283  for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
284  {
285  QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
286  mOperation( ref, block.lineLength, bpl );
287  }
288  }
289  else
290  {
291  //by column
292  unsigned char *ref = block.image->scanLine( 0 ) + 4 * block.beginLine;
293  for ( unsigned int x = block.beginLine; x < block.endLine; ++x, ref += 4 )
294  {
295  mOperation( reinterpret_cast< QRgb * >( ref ), block.lineLength, bpl );
296  }
297  }
298  }
299 
300  LineOperation &mOperation;
301  };
302 
303 
304  //individual operation implementations
305 
306  class GrayscalePixelOperation
307  {
308  public:
309  explicit GrayscalePixelOperation( const GrayscaleMode mode )
310  : mMode( mode )
311  { }
312 
313  void operator()( QRgb &rgb, int x, int y ) const;
314 
315  private:
316  GrayscaleMode mMode;
317  };
318  static void grayscaleLightnessOp( QRgb &rgb );
319  static void grayscaleLuminosityOp( QRgb &rgb );
320  static void grayscaleAverageOp( QRgb &rgb );
321 
322 
323  class BrightnessContrastPixelOperation
324  {
325  public:
326  BrightnessContrastPixelOperation( const int brightness, const double contrast )
327  : mBrightness( brightness )
328  , mContrast( contrast )
329  { }
330 
331  void operator()( QRgb &rgb, int x, int y );
332 
333  private:
334  int mBrightness;
335  double mContrast;
336  };
337 
338 
339  class HueSaturationPixelOperation
340  {
341  public:
342  HueSaturationPixelOperation( const double saturation, const bool colorize,
343  const int colorizeHue, const int colorizeSaturation,
344  const double colorizeStrength )
345  : mSaturation( saturation )
346  , mColorize( colorize )
347  , mColorizeHue( colorizeHue )
348  , mColorizeSaturation( colorizeSaturation )
349  , mColorizeStrength( colorizeStrength )
350  { }
351 
352  void operator()( QRgb &rgb, int x, int y );
353 
354  private:
355  double mSaturation; // [0, 2], 1 = no change
356  bool mColorize;
357  int mColorizeHue;
358  int mColorizeSaturation;
359  double mColorizeStrength; // [0,1]
360  };
361  static int adjustColorComponent( int colorComponent, int brightness, double contrastFactor );
362 
363 
364  class MultiplyOpacityPixelOperation
365  {
366  public:
367  explicit MultiplyOpacityPixelOperation( const double factor )
368  : mFactor( factor )
369  { }
370 
371  void operator()( QRgb &rgb, int x, int y );
372 
373  private:
374  double mFactor;
375  };
376 
377  class ConvertToArrayPixelOperation
378  {
379  public:
380  ConvertToArrayPixelOperation( const int width, double *array, const bool exterior = true )
381  : mWidth( width )
382  , mArray( array )
383  , mExterior( exterior )
384  {
385  }
386 
387  void operator()( QRgb &rgb, int x, int y );
388 
389  private:
390  int mWidth;
391  double *mArray = nullptr;
392  bool mExterior;
393  };
394 
395  class ShadeFromArrayOperation
396  {
397  public:
398  ShadeFromArrayOperation( const int width, double *array, const double spread,
399  const DistanceTransformProperties &properties )
400  : mWidth( width )
401  , mArray( array )
402  , mSpread( spread )
403  , mProperties( properties )
404  {
405  mSpreadSquared = std::pow( mSpread, 2.0 );
406  }
407 
408  void operator()( QRgb &rgb, int x, int y );
409 
410  private:
411  int mWidth;
412  double *mArray = nullptr;
413  double mSpread;
414  double mSpreadSquared;
415  const DistanceTransformProperties &mProperties;
416  };
417  static void distanceTransform2d( double *im, int width, int height, QgsFeedback *feedback = nullptr );
418  static void distanceTransform1d( double *f, int n, int *v, double *z, double *d );
419  static double maxValueInDistanceTransformArray( const double *array, unsigned int size );
420 
421 
422  class StackBlurLineOperation
423  {
424  public:
425  StackBlurLineOperation( int alpha, LineOperationDirection direction, bool forwardDirection, int i1, int i2, QgsFeedback *feedback )
426  : mAlpha( alpha )
427  , mDirection( direction )
428  , mForwardDirection( forwardDirection )
429  , mi1( i1 )
430  , mi2( i2 )
431  , mFeedback( feedback )
432  { }
433 
434  typedef void result_type;
435 
436  LineOperationDirection direction() const { return mDirection; }
437 
438  void operator()( QRgb *startRef, int lineLength, int bytesPerLine )
439  {
440  if ( mFeedback && mFeedback->isCanceled() )
441  return;
442 
443  unsigned char *p = reinterpret_cast< unsigned char * >( startRef );
444  int rgba[4];
445  int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
446  if ( !mForwardDirection )
447  {
448  p += ( lineLength - 1 ) * increment;
449  increment = -increment;
450  }
451 
452  for ( int i = mi1; i <= mi2; ++i )
453  {
454  rgba[i] = p[i] << 4;
455  }
456 
457  p += increment;
458  for ( int j = 1; j < lineLength; ++j, p += increment )
459  {
460  if ( mFeedback && mFeedback->isCanceled() )
461  break;
462 
463  for ( int i = mi1; i <= mi2; ++i )
464  {
465  p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * mAlpha / 16 ) >> 4;
466  }
467  }
468  }
469 
470  private:
471  int mAlpha;
472  LineOperationDirection mDirection;
473  bool mForwardDirection;
474  int mi1;
475  int mi2;
476  QgsFeedback *mFeedback = nullptr;
477  };
478 
479  static double *createGaussianKernel( int radius );
480 
481  class GaussianBlurOperation
482  {
483  public:
484  GaussianBlurOperation( int radius, LineOperationDirection direction, QImage *destImage, double *kernel, QgsFeedback *feedback )
485  : mRadius( radius )
486  , mDirection( direction )
487  , mDestImage( destImage )
488  , mDestImageBpl( destImage->bytesPerLine() )
489  , mKernel( kernel )
490  , mFeedback( feedback )
491  {}
492 
493  typedef void result_type;
494 
495  void operator()( ImageBlock &block );
496 
497  private:
498  int mRadius;
499  LineOperationDirection mDirection;
500  QImage *mDestImage = nullptr;
501  int mDestImageBpl;
502  double *mKernel = nullptr;
503  QgsFeedback *mFeedback = nullptr;
504 
505  inline QRgb gaussianBlurVertical( int posy, unsigned char *sourceFirstLine, int sourceBpl, int height ) const;
506  inline QRgb gaussianBlurHorizontal( int posx, unsigned char *sourceFirstLine, int width ) const;
507  };
508 
509  //flip
510 
511 
512  class FlipLineOperation
513  {
514  public:
515  explicit FlipLineOperation( LineOperationDirection direction )
516  : mDirection( direction )
517  { }
518 
519  typedef void result_type;
520 
521  LineOperationDirection direction() const { return mDirection; }
522 
523  void operator()( QRgb *startRef, int lineLength, int bytesPerLine ) const;
524 
525  private:
526  LineOperationDirection mDirection;
527  };
528 
529 
530 };
531 
532 #endif // QGSIMAGEOPERATION_H
533 
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:29
QgsImageOperation::GrayscaleLightness
@ GrayscaleLightness
Keep the lightness of the color, drops the saturation.
Definition: qgsimageoperation.h:57
QgsImageOperation::GrayscaleAverage
@ GrayscaleAverage
Grayscale by taking average of color RGB components.
Definition: qgsimageoperation.h:59
QgsImageOperation::FlipType
FlipType
Flip operation types.
Definition: qgsimageoperation.h:66
SIP_FACTORY
#define SIP_FACTORY
Definition: qgis_sip.h:76
QgsImageOperation::GrayscaleLuminosity
@ GrayscaleLuminosity
Grayscale by perceptual luminosity (weighted sum of color RGB components)
Definition: qgsimageoperation.h:58
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
qgis_sip.h
QgsImageOperation
Contains operations and filters which apply to QImages.
Definition: qgsimageoperation.h:47
QgsImageOperation::DistanceTransformProperties
Struct for storing properties of a distance transform operation.
Definition: qgsimageoperation.h:122
QgsImageOperation::FlipHorizontal
@ FlipHorizontal
Flip the image horizontally.
Definition: qgsimageoperation.h:68
qgsfeedback.h
QgsImageOperation::GrayscaleMode
GrayscaleMode
Modes for converting a QImage to grayscale.
Definition: qgsimageoperation.h:55