QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
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
29class QgsColorRamp;
30class QgsFeedback;
31
47class CORE_EXPORT QgsImageOperation
48{
49
50 public:
51
56 {
60 GrayscaleOff
61 };
62
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
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Contains operations and filters which apply to QImages.
FlipType
Flip operation types.
@ FlipHorizontal
Flip the image horizontally.
GrayscaleMode
Modes for converting a QImage to grayscale.
@ GrayscaleLightness
Keep the lightness of the color, drops the saturation.
@ GrayscaleLuminosity
Grayscale by perceptual luminosity (weighted sum of color RGB components)
@ GrayscaleAverage
Grayscale by taking average of color RGB components.
#define SIP_FACTORY
Definition: qgis_sip.h:76
Struct for storing properties of a distance transform operation.