QGIS API Documentation 4.3.0-Master (389d690bb77)
Loading...
Searching...
No Matches
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 : nyall.dawson@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#ifndef QGSIMAGEOPERATION_H
19#define QGSIMAGEOPERATION_H
20
21#include <cmath>
22
23#include "qgis_core.h"
24#include "qgis_sip.h"
25#include "qgsfeedback.h"
26
27#include <QColor>
28#include <QImage>
29
30class QgsColorRamp;
31class QgsFeedback;
32
47class CORE_EXPORT QgsImageOperation
48{
49 public:
60
69
76 static void convertToGrayscale( QImage &image, GrayscaleMode mode = GrayscaleLuminosity, QgsFeedback *feedback = nullptr );
77
89 static void adjustBrightnessContrast( QImage &image, int brightness, double contrast, QgsFeedback *feedback = nullptr );
90
100 static void adjustHueSaturation( QImage &image, double saturation, const QColor &colorizeColor = QColor(), double colorizeStrength = 1.0, QgsFeedback *feedback = nullptr );
101
108 static void multiplyOpacity( QImage &image, double factor, QgsFeedback *feedback = nullptr );
109
116 static void overlayColor( QImage &image, const QColor &color );
117
120 {
126 bool shadeExterior = true;
127
132 bool useMaxDistance = true;
133
138 double spread = 10.0;
139
143 QgsColorRamp *ramp = nullptr;
144 };
145
154 static void distanceTransform( QImage &image, const QgsImageOperation::DistanceTransformProperties &properties, QgsFeedback *feedback = nullptr );
155
166 static void stackBlur( QImage &image, int radius, bool alphaOnly = false, QgsFeedback *feedback = nullptr );
167
177 static QImage *gaussianBlur( QImage &image, int radius, QgsFeedback *feedback = nullptr ) SIP_FACTORY;
178
184 static void flipImage( QImage &image, FlipType type );
185
195 static QRect nonTransparentImageRect( const QImage &image, QSize minSize = QSize(), bool center = false );
196
205 static QImage cropTransparent( const QImage &image, QSize minSize = QSize(), bool center = false );
206
216 static bool isBlankImage( const QImage &image );
217
224 static bool isSingleColor( const QImage &image, const QColor &color );
225
235 static QImage floodFill( const QImage &image, const QPoint &startPoint, const QColor &newColor, int tolerance = 0, QgsFeedback *feedback = nullptr );
236
237 private:
238 //for blocked operations
239 enum LineOperationDirection
240 {
241 ByRow,
242 ByColumn
243 };
244 template<class BlockOperation> static void runBlockOperationInThreads( QImage &image, BlockOperation &operation, LineOperationDirection direction );
245 struct ImageBlock
246 {
247 unsigned int beginLine;
248 unsigned int endLine;
249 unsigned int lineLength;
250 QImage *image = nullptr;
251 };
252
253 //for rect operations
254 template<typename RectOperation> static void runRectOperation( QImage &image, RectOperation &operation );
255 template<class RectOperation> static void runRectOperationOnWholeImage( QImage &image, RectOperation &operation );
256
257 //for per pixel operations
258 template<class PixelOperation> static void runPixelOperation( QImage &image, PixelOperation &operation, QgsFeedback *feedback = nullptr );
259 template<class PixelOperation> static void runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation, QgsFeedback *feedback = nullptr );
260 template<class PixelOperation> struct ProcessBlockUsingPixelOperation
261 {
262 explicit ProcessBlockUsingPixelOperation( PixelOperation &operation, QgsFeedback *feedback )
263 : mOperation( operation )
264 , mFeedback( feedback )
265 {}
266
267 typedef void result_type;
268
269 void operator()( ImageBlock &block )
270 {
271 for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
272 {
273 if ( mFeedback && mFeedback->isCanceled() )
274 break;
275
276 QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
277 for ( unsigned int x = 0; x < block.lineLength; ++x )
278 {
279 mOperation( ref[x], x, y );
280 }
281 }
282 }
283
284 PixelOperation &mOperation;
285 QgsFeedback *mFeedback = nullptr;
286 };
287
288 //for linear operations
289 template<typename LineOperation> static void runLineOperation( QImage &image, LineOperation &operation, QgsFeedback *feedback = nullptr );
290 template<class LineOperation> static void runLineOperationOnWholeImage( QImage &image, LineOperation &operation, QgsFeedback *feedback = nullptr );
291 template<class LineOperation> struct ProcessBlockUsingLineOperation
292 {
293 explicit ProcessBlockUsingLineOperation( LineOperation &operation )
294 : mOperation( operation )
295 {}
296
297 typedef void result_type;
298
299 void operator()( ImageBlock &block )
300 {
301 //do something with whole lines
302 int bpl = block.image->bytesPerLine();
303 if ( mOperation.direction() == ByRow )
304 {
305 for ( unsigned int y = block.beginLine; y < block.endLine; ++y )
306 {
307 QRgb *ref = reinterpret_cast< QRgb * >( block.image->scanLine( y ) );
308 mOperation( ref, block.lineLength, bpl );
309 }
310 }
311 else
312 {
313 //by column
314 unsigned char *ref = block.image->scanLine( 0 ) + 4 * block.beginLine;
315 for ( unsigned int x = block.beginLine; x < block.endLine; ++x, ref += 4 )
316 {
317 mOperation( reinterpret_cast< QRgb * >( ref ), block.lineLength, bpl );
318 }
319 }
320 }
321
322 LineOperation &mOperation;
323 };
324
325
326 //individual operation implementations
327
328 class GrayscalePixelOperation
329 {
330 public:
331 explicit GrayscalePixelOperation( const GrayscaleMode mode )
332 : mMode( mode )
333 {}
334
335 void operator()( QRgb &rgb, int x, int y ) const;
336
337 private:
338 GrayscaleMode mMode;
339 };
340 static void grayscaleLightnessOp( QRgb &rgb );
341 static void grayscaleLuminosityOp( QRgb &rgb );
342 static void grayscaleAverageOp( QRgb &rgb );
343
344
345 class BrightnessContrastPixelOperation
346 {
347 public:
348 BrightnessContrastPixelOperation( const int brightness, const double contrast )
349 : mBrightness( brightness )
350 , mContrast( contrast )
351 {}
352
353 void operator()( QRgb &rgb, int x, int y ) const;
354
355 private:
356 int mBrightness;
357 double mContrast;
358 };
359
360
361 class HueSaturationPixelOperation
362 {
363 public:
364 HueSaturationPixelOperation( const double saturation, const bool colorize, const int colorizeHue, const int colorizeSaturation, const double colorizeStrength )
365 : mSaturation( saturation )
366 , mColorize( colorize )
367 , mColorizeHue( colorizeHue )
368 , mColorizeSaturation( colorizeSaturation )
369 , mColorizeStrength( colorizeStrength )
370 {}
371
372 void operator()( QRgb &rgb, int x, int y ) const;
373
374 private:
375 double mSaturation; // [0, 2], 1 = no change
376 bool mColorize;
377 int mColorizeHue;
378 int mColorizeSaturation;
379 double mColorizeStrength; // [0,1]
380 };
381 static int adjustColorComponent( int colorComponent, int brightness, double contrastFactor );
382
383
384 class MultiplyOpacityPixelOperation
385 {
386 public:
387 explicit MultiplyOpacityPixelOperation( const double factor )
388 : mFactor( factor )
389 {}
390
391 void operator()( QRgb &rgb, int x, int y ) const;
392
393 private:
394 double mFactor;
395 };
396
397 class ConvertToArrayPixelOperation
398 {
399 public:
400 ConvertToArrayPixelOperation( const int width, double *array, const bool exterior = true )
401 : mWidth( width )
402 , mArray( array )
403 , mExterior( exterior )
404 {}
405
406 void operator()( QRgb &rgb, int x, int y );
407
408 private:
409 int mWidth;
410 double *mArray = nullptr;
411 bool mExterior;
412 };
413
414 class ShadeFromArrayOperation
415 {
416 public:
417 ShadeFromArrayOperation( const int width, double *array, const double spread, const DistanceTransformProperties &properties )
418 : mWidth( width )
419 , mArray( array )
420 , mSpread( spread )
421 , mProperties( properties )
422 {
423 mSpreadSquared = std::pow( mSpread, 2.0 );
424 }
425
426 void operator()( QRgb &rgb, int x, int y );
427
428 private:
429 int mWidth;
430 double *mArray = nullptr;
431 double mSpread;
432 double mSpreadSquared;
433 const DistanceTransformProperties &mProperties;
434 };
435 static void distanceTransform2d( double *im, int width, int height, QgsFeedback *feedback = nullptr );
436 static void distanceTransform1d( double *f, int n, int *v, double *z, double *d );
437 static double maxValueInDistanceTransformArray( const double *array, unsigned int size );
438
439
440 class StackBlurLineOperation
441 {
442 public:
443 StackBlurLineOperation( int alpha, LineOperationDirection direction, bool forwardDirection, int i1, int i2, QgsFeedback *feedback )
444 : mAlpha( alpha )
445 , mDirection( direction )
446 , mForwardDirection( forwardDirection )
447 , mi1( i1 )
448 , mi2( i2 )
449 , mFeedback( feedback )
450 {}
451
452 typedef void result_type;
453
454 LineOperationDirection direction() const { return mDirection; }
455
456 void operator()( QRgb *startRef, int lineLength, int bytesPerLine )
457 {
458 if ( mFeedback && mFeedback->isCanceled() )
459 return;
460
461 unsigned char *p = reinterpret_cast< unsigned char * >( startRef );
462 int rgba[4];
463 int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
464 if ( !mForwardDirection )
465 {
466 p += static_cast< std::size_t >( lineLength - 1 ) * increment;
467 increment = -increment;
468 }
469
470 for ( int i = mi1; i <= mi2; ++i )
471 {
472 rgba[i] = p[i] << 4;
473 }
474
475 p += increment;
476 for ( int j = 1; j < lineLength; ++j, p += increment )
477 {
478 if ( mFeedback && mFeedback->isCanceled() )
479 break;
480
481 for ( int i = mi1; i <= mi2; ++i )
482 {
483 p[i] = ( rgba[i] += ( ( p[i] << 4 ) - rgba[i] ) * mAlpha / 16 ) >> 4;
484 }
485 }
486 }
487
488 private:
489 int mAlpha;
490 LineOperationDirection mDirection;
491 bool mForwardDirection;
492 int mi1;
493 int mi2;
494 QgsFeedback *mFeedback = nullptr;
495 };
496
497 static double *createGaussianKernel( int radius );
498
499 class GaussianBlurOperation
500 {
501 public:
502 GaussianBlurOperation( int radius, LineOperationDirection direction, QImage *destImage, double *kernel, QgsFeedback *feedback )
503 : mRadius( radius )
504 , mDirection( direction )
505 , mDestImage( destImage )
506 , mDestImageBpl( destImage->bytesPerLine() )
507 , mKernel( kernel )
508 , mFeedback( feedback )
509 {}
510
511 typedef void result_type;
512
513 void operator()( ImageBlock &block );
514
515 private:
516 int mRadius;
517 LineOperationDirection mDirection;
518 QImage *mDestImage = nullptr;
519 int mDestImageBpl;
520 double *mKernel = nullptr;
521 QgsFeedback *mFeedback = nullptr;
522
523 inline QRgb gaussianBlurVertical( int posy, unsigned char *sourceFirstLine, int sourceBpl, int height ) const;
524 inline QRgb gaussianBlurHorizontal( int posx, unsigned char *sourceFirstLine, int width ) const;
525 };
526
527 //flip
528
529
530 class FlipLineOperation
531 {
532 public:
533 explicit FlipLineOperation( LineOperationDirection direction )
534 : mDirection( direction )
535 {}
536
537 typedef void result_type;
538
539 LineOperationDirection direction() const { return mDirection; }
540
541 void operator()( QRgb *startRef, int lineLength, int bytesPerLine ) const;
542
543 private:
544 LineOperationDirection mDirection;
545 };
546};
547
548#endif // QGSIMAGEOPERATION_H
Abstract base class for color ramps.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
Contains operations and filters which apply to QImages.
static void distanceTransform(QImage &image, const QgsImageOperation::DistanceTransformProperties &properties, QgsFeedback *feedback=nullptr)
Performs a distance transform on the source image and shades the result using a color ramp.
FlipType
Flip operation types.
@ FlipHorizontal
Flip the image horizontally.
@ FlipVertical
Flip the image vertically.
static QImage floodFill(const QImage &image, const QPoint &startPoint, const QColor &newColor, int tolerance=0, QgsFeedback *feedback=nullptr)
Performs a flood fill operation on an image, replacing contiguous areas of the same color.
static void flipImage(QImage &image, FlipType type)
Flips an image horizontally or vertically.
static bool isBlankImage(const QImage &image)
Tests whether an image is completely blank, i.e.
static QImage * gaussianBlur(QImage &image, int radius, QgsFeedback *feedback=nullptr)
Performs a gaussian blur on an image.
static bool isSingleColor(const QImage &image, const QColor &color)
Tests whether an image is consists only of pixels matching the specified color.
static QRect nonTransparentImageRect(const QImage &image, QSize minSize=QSize(), bool center=false)
Calculates the non-transparent region of an image.
static void stackBlur(QImage &image, int radius, bool alphaOnly=false, QgsFeedback *feedback=nullptr)
Performs a stack blur on an image.
static QImage cropTransparent(const QImage &image, QSize minSize=QSize(), bool center=false)
Crop any transparent border from around an image.
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:83
Struct for storing properties of a distance transform operation.
bool useMaxDistance
Set to true to automatically calculate the maximum distance in the transform to use as the spread val...
bool shadeExterior
Set to true to perform the distance transform on transparent pixels in the source image,...
double spread
Maximum distance (in pixels) for the distance transform shading to spread.
QgsColorRamp * ramp
Color ramp to use for shading the distance transform.