22 #include <QtConcurrentMap> 
   28 #define BLOCK_THREADS 16 
   34 template <
typename PixelOperation>
 
   35 void QgsImageOperation::runPixelOperation( QImage &image, PixelOperation &operation )
 
   37   if ( image.height() * image.width() < 100000 )
 
   41     runPixelOperationOnWholeImage( image, operation );
 
   46     QgsImageOperation::ProcessBlockUsingPixelOperation<PixelOperation> blockOp( operation );
 
   47     runBlockOperationInThreads( image, blockOp, QgsImageOperation::ByRow );
 
   51 template <
typename PixelOperation>
 
   52 void QgsImageOperation::runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation )
 
   54   int height = image.height();
 
   55   int width = image.width();
 
   56   for ( 
int y = 0; y < height; ++y )
 
   58     QRgb *ref = 
reinterpret_cast< QRgb * 
>( image.scanLine( y ) );
 
   59     for ( 
int x = 0; x < width; ++x )
 
   61       operation( ref[x], x, y );
 
   68 template <
typename RectOperation>
 
   69 void QgsImageOperation::runRectOperation( QImage &image, RectOperation &operation )
 
   72   if ( image.height() * image.width() < 100000 )
 
   76     runRectOperationOnWholeImage( image, operation );
 
   81     runBlockOperationInThreads( image, operation, ByRow );
 
   85 template <
class RectOperation>
 
   86 void QgsImageOperation::runRectOperationOnWholeImage( QImage &image, RectOperation &operation )
 
   89   fullImage.beginLine = 0;
 
   90   fullImage.endLine = image.height();
 
   91   fullImage.lineLength = image.width();
 
   92   fullImage.image = ℑ
 
   94   operation( fullImage );
 
   99 template <
typename LineOperation>
 
  100 void QgsImageOperation::runLineOperation( QImage &image, LineOperation &operation )
 
  103   if ( image.height() * image.width() < 100000 )
 
  107     runLineOperationOnWholeImage( image, operation );
 
  112     QgsImageOperation::ProcessBlockUsingLineOperation<LineOperation> blockOp( operation );
 
  113     runBlockOperationInThreads( image, blockOp, operation.direction() );
 
  117 template <
class LineOperation>
 
  118 void QgsImageOperation::runLineOperationOnWholeImage( QImage &image, LineOperation &operation )
 
  120   int height = image.height();
 
  121   int width = image.width();
 
  124   int bpl = image.bytesPerLine();
 
  125   if ( operation.direction() == ByRow )
 
  127     for ( 
int y = 0; y < height; ++y )
 
  129       QRgb *ref = 
reinterpret_cast< QRgb * 
>( image.scanLine( y ) );
 
  130       operation( ref, width, bpl );
 
  136     unsigned char *ref = image.scanLine( 0 );
 
  137     for ( 
int x = 0; x < width; ++x, ref += 4 )
 
  139       operation( 
reinterpret_cast< QRgb * 
>( ref ), height, bpl );
 
  147 template <
typename BlockOperation>
 
  148 void QgsImageOperation::runBlockOperationInThreads( QImage &image, BlockOperation &operation, LineOperationDirection direction )
 
  150   QList< ImageBlock > blocks;
 
  151   unsigned int height = image.height();
 
  152   unsigned int width = image.width();
 
  154   unsigned int blockDimension1 = ( direction == QgsImageOperation::ByRow ) ? height : width;
 
  155   unsigned int blockDimension2 = ( direction == QgsImageOperation::ByRow ) ? width : height;
 
  159   unsigned int begin = 0;
 
  161   for ( 
unsigned int block = 0; block < 
BLOCK_THREADS; ++block, begin += blockLen )
 
  164     newBlock.beginLine = begin;
 
  166     newBlock.endLine = block < ( 
BLOCK_THREADS - 1 ) ? begin + blockLen : blockDimension1;
 
  167     newBlock.lineLength = blockDimension2;
 
  168     newBlock.image = ℑ
 
  173   QtConcurrent::blockingMap( blocks, operation );
 
  192   GrayscalePixelOperation operation( mode );
 
  193   runPixelOperation( image, operation );
 
  196 void QgsImageOperation::GrayscalePixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  204     case GrayscaleLuminosity:
 
  205       grayscaleLuminosityOp( rgb );
 
  207     case GrayscaleAverage:
 
  208       grayscaleAverageOp( rgb );
 
  210     case GrayscaleLightness:
 
  212       grayscaleLightnessOp( rgb );
 
  217 void QgsImageOperation::grayscaleLightnessOp( QRgb &rgb )
 
  219   int red = qRed( rgb );
 
  220   int green = qGreen( rgb );
 
  221   int blue = qBlue( rgb );
 
  223   int min = std::min( std::min( red, green ), blue );
 
  224   int max = std::max( std::max( red, green ), blue );
 
  226   int lightness = std::min( ( min + max ) / 2, 255 );
 
  227   rgb = qRgba( lightness, lightness, lightness, qAlpha( rgb ) );
 
  230 void QgsImageOperation::grayscaleLuminosityOp( QRgb &rgb )
 
  232   int luminosity = 0.21 * qRed( rgb ) + 0.72 * qGreen( rgb ) + 0.07 * qBlue( rgb );
 
  233   rgb = qRgba( luminosity, luminosity, luminosity, qAlpha( rgb ) );
 
  236 void QgsImageOperation::grayscaleAverageOp( QRgb &rgb )
 
  238   int average = ( qRed( rgb ) + qGreen( rgb ) + qBlue( rgb ) ) / 3;
 
  239   rgb = qRgba( average, average, average, qAlpha( rgb ) );
 
  247   BrightnessContrastPixelOperation operation( brightness, contrast );
 
  248   runPixelOperation( image, operation );
 
  251 void QgsImageOperation::BrightnessContrastPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  255   int red = adjustColorComponent( qRed( rgb ), mBrightness, mContrast );
 
  256   int blue = adjustColorComponent( qBlue( rgb ), mBrightness, mContrast );
 
  257   int green = adjustColorComponent( qGreen( rgb ), mBrightness, mContrast );
 
  258   rgb = qRgba( red, green, blue, qAlpha( rgb ) );
 
  261 int QgsImageOperation::adjustColorComponent( 
int colorComponent, 
int brightness, 
double contrastFactor )
 
  263   return qBound( 0, 
static_cast< int >( ( ( ( ( ( colorComponent / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 255 );
 
  270   HueSaturationPixelOperation operation( saturation, colorizeColor.isValid() && colorizeStrength > 0.0,
 
  271                                          colorizeColor.hue(), colorizeColor.saturation(), colorizeStrength );
 
  272   runPixelOperation( image, operation );
 
  275 void QgsImageOperation::HueSaturationPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  279   QColor tmpColor( rgb );
 
  281   tmpColor.getHsl( &h, &s, &l );
 
  283   if ( mSaturation < 1.0 )
 
  286     s = std::min( 
static_cast< int >( s * mSaturation ), 255 );
 
  288   else if ( mSaturation > 1.0 )
 
  292     s = std::min( 
static_cast< int >( 255. * ( 1 - std::pow( 1 - ( s / 255. ), std::pow( mSaturation, 2 ) ) ) ), 255 );
 
  298     s = mColorizeSaturation;
 
  299     if ( mColorizeStrength < 1.0 )
 
  302       QColor colorizedColor = QColor::fromHsl( h, s, l );
 
  303       int colorizedR, colorizedG, colorizedB;
 
  304       colorizedColor.getRgb( &colorizedR, &colorizedG, &colorizedB );
 
  307       int r = mColorizeStrength * colorizedR + ( 1 - mColorizeStrength ) * tmpColor.red();
 
  308       int g = mColorizeStrength * colorizedG + ( 1 - mColorizeStrength ) * tmpColor.green();
 
  309       int b = mColorizeStrength * colorizedB + ( 1 - mColorizeStrength ) * tmpColor.blue();
 
  311       rgb = qRgba( r, g, b, qAlpha( rgb ) );
 
  316   tmpColor.setHsl( h, s, l, qAlpha( rgb ) );
 
  317   rgb = tmpColor.rgba();
 
  329   else if ( factor < 1.0 )
 
  333     QColor transparentFillColor = QColor( 0, 0, 0, 255 * factor );
 
  334     QPainter painter( &image );
 
  335     painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
  336     painter.fillRect( 0, 0, image.width(), image.height(), transparentFillColor );
 
  342     MultiplyOpacityPixelOperation operation( factor );
 
  343     runPixelOperation( image, operation );
 
  347 void QgsImageOperation::MultiplyOpacityPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  351   rgb = qRgba( qRed( rgb ), qGreen( rgb ), qBlue( rgb ), qBound( 0.0, std::round( mFactor * qAlpha( rgb ) ), 255.0 ) );
 
  358   QColor opaqueColor = color;
 
  359   opaqueColor.setAlpha( 255 );
 
  363   QPainter painter( &image );
 
  364   painter.setCompositionMode( QPainter::CompositionMode_SourceIn );
 
  365   painter.fillRect( 0, 0, image.width(), image.height(), opaqueColor );
 
  373   if ( ! properties.
ramp )
 
  375     QgsDebugMsg( QStringLiteral( 
"no color ramp specified for distance transform" ) );
 
  380   double *array = 
new double[ 
static_cast< qgssize >( image.width() ) * image.height()];
 
  381   ConvertToArrayPixelOperation convertToArray( image.width(), array, properties.
shadeExterior );
 
  382   runPixelOperation( image, convertToArray );
 
  385   distanceTransform2d( array, image.width(), image.height() );
 
  390     spread = std::sqrt( maxValueInDistanceTransformArray( array, image.width() * image.height() ) );
 
  394     spread = properties.
spread;
 
  398   ShadeFromArrayOperation shadeFromArray( image.width(), array, spread, properties );
 
  399   runPixelOperation( image, shadeFromArray );
 
  403 void QgsImageOperation::ConvertToArrayPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  408     if ( qAlpha( rgb ) > 0 )
 
  411       mArray[ idx ] = 1 - qAlpha( rgb ) / 255.0;
 
  422     if ( qAlpha( rgb ) == 255 )
 
  436 void QgsImageOperation::distanceTransform1d( 
double *f, 
int n, 
int *v, 
double *z, 
double *d )
 
  442   for ( 
int q = 1; q <= n - 1; q++ )
 
  444     double s  = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
 
  448       s  = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
 
  457   for ( 
int q = 0; q <= n - 1; q++ )
 
  459     while ( z[k + 1] < q )
 
  461     d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
 
  465 double QgsImageOperation::maxValueInDistanceTransformArray( 
const double *array, 
const unsigned int size )
 
  467   double dtMaxValue = array[0];
 
  468   for ( 
unsigned int i = 1; i < size; ++i )
 
  470     if ( array[i] > dtMaxValue )
 
  472       dtMaxValue = array[i];
 
  479 void QgsImageOperation::distanceTransform2d( 
double *im, 
int width, 
int height )
 
  481   int maxDimension = std::max( width, height );
 
  483   double *f = 
new double[ maxDimension ];
 
  484   int *v = 
new int[ maxDimension ];
 
  485   double *z = 
new double[ maxDimension + 1 ];
 
  486   double *d = 
new double[ maxDimension ];
 
  489   for ( 
int x = 0; x < width; x++ )
 
  491     for ( 
int y = 0; y < height; y++ )
 
  493       f[y] = im[ x + y * width ];
 
  495     distanceTransform1d( f, height, v, z, d );
 
  496     for ( 
int y = 0; y < height; y++ )
 
  498       im[ x + y * width ] = d[y];
 
  503   for ( 
int y = 0; y < height; y++ )
 
  505     for ( 
int x = 0; x < width; x++ )
 
  507       f[x] = im[  x + y * width ];
 
  509     distanceTransform1d( f, width, v, z, d );
 
  510     for ( 
int x = 0; x < width; x++ )
 
  512       im[  x + y * width ] = d[x];
 
  522 void QgsImageOperation::ShadeFromArrayOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  524   if ( ! mProperties.ramp )
 
  529     rgb = mProperties.ramp->color( 1.0 ).rgba();
 
  533   int idx = y * mWidth + x;
 
  536   double squaredVal = mArray[ idx ];
 
  537   if ( squaredVal > mSpreadSquared )
 
  539     rgb = Qt::transparent;
 
  543   double distance = std::sqrt( squaredVal );
 
  544   double val = distance / mSpread;
 
  545   QColor rampColor = mProperties.ramp->color( val );
 
  547   if ( ( mProperties.shadeExterior && distance > mSpread - 1 ) )
 
  550     double alphaMultiplyFactor = mSpread - distance;
 
  551     rampColor.setAlpha( rampColor.alpha() * alphaMultiplyFactor );
 
  553   rgb = rampColor.rgba();
 
  561   int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
 
  562   int alpha = ( radius < 1 )  ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
 
  568   QImage::Format originalFormat = image.format();
 
  569   QImage *pImage = ℑ
 
  570   if ( !alphaOnly && originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  572     pImage = 
new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
 
  574   else if ( alphaOnly && originalFormat != QImage::Format_ARGB32 )
 
  576     pImage = 
new QImage( image.convertToFormat( QImage::Format_ARGB32 ) );
 
  580     i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
 
  582   StackBlurLineOperation topToBottomBlur( alpha, QgsImageOperation::ByColumn, 
true, i1, i2 );
 
  583   runLineOperation( *pImage, topToBottomBlur );
 
  585   StackBlurLineOperation leftToRightBlur( alpha, QgsImageOperation::ByRow, 
true, i1, i2 );
 
  586   runLineOperation( *pImage, leftToRightBlur );
 
  588   StackBlurLineOperation bottomToTopBlur( alpha, QgsImageOperation::ByColumn, 
false, i1, i2 );
 
  589   runLineOperation( *pImage, bottomToTopBlur );
 
  591   StackBlurLineOperation rightToLeftBlur( alpha, QgsImageOperation::ByRow, 
false, i1, i2 );
 
  592   runLineOperation( *pImage, rightToLeftBlur );
 
  594   if ( pImage->format() != originalFormat )
 
  596     image = pImage->convertToFormat( originalFormat );
 
  605   int width = image.width();
 
  606   int height = image.height();
 
  611     QImage *copy = 
new QImage( image.copy() );
 
  615   double *kernel = createGaussianKernel( radius );
 
  618   QImage::Format originalFormat = image.format();
 
  619   QImage *pImage = ℑ
 
  620   if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  622     pImage = 
new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
 
  626   QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
 
  627   GaussianBlurOperation rowBlur( radius, QgsImageOperation::ByRow, &xBlurImage, kernel );
 
  628   runRectOperation( *pImage, rowBlur );
 
  631   QImage *yBlurImage = 
new QImage( width, height, QImage::Format_ARGB32_Premultiplied );
 
  632   GaussianBlurOperation colBlur( radius, QgsImageOperation::ByColumn, yBlurImage, kernel );
 
  633   runRectOperation( xBlurImage, colBlur );
 
  637   if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  639     QImage *convertedImage = 
new QImage( yBlurImage->convertToFormat( originalFormat ) );
 
  642     return convertedImage;
 
  648 void QgsImageOperation::GaussianBlurOperation::operator()( QgsImageOperation::ImageBlock &block )
 
  650   int width = block.image->width();
 
  651   int height = block.image->height();
 
  652   int sourceBpl = block.image->bytesPerLine();
 
  654   unsigned char *outputLineRef = mDestImage->scanLine( block.beginLine );
 
  655   QRgb *destRef = 
nullptr;
 
  656   if ( mDirection == ByRow )
 
  658     unsigned char *sourceFirstLine = block.image->scanLine( 0 );
 
  659     unsigned char *sourceRef;
 
  662     for ( 
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl )
 
  664       sourceRef = sourceFirstLine;
 
  665       destRef = 
reinterpret_cast< QRgb * 
>( outputLineRef );
 
  666       for ( 
int x = 0; x < width; ++x, ++destRef, sourceRef += 4 )
 
  668         *destRef = gaussianBlurVertical( y, sourceRef, sourceBpl, height );
 
  674     unsigned char *sourceRef = block.image->scanLine( block.beginLine );
 
  675     for ( 
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl, sourceRef += sourceBpl )
 
  677       destRef = 
reinterpret_cast< QRgb * 
>( outputLineRef );
 
  678       for ( 
int x = 0; x < width; ++x, ++destRef )
 
  680         *destRef = gaussianBlurHorizontal( x, sourceRef, width );
 
  686 inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurVertical( 
const int posy, 
unsigned char *sourceFirstLine, 
const int sourceBpl, 
const int height )
 
  695   for ( 
int i = 0; i <= mRadius * 2; ++i )
 
  697     y = qBound( 0, posy + ( i - mRadius ), height - 1 );
 
  698     ref = sourceFirstLine + sourceBpl * y;
 
  700     QRgb *refRgb = 
reinterpret_cast< QRgb * 
>( ref );
 
  701     r += mKernel[i] * qRed( *refRgb );
 
  702     g += mKernel[i] * qGreen( *refRgb );
 
  703     b += mKernel[i] * qBlue( *refRgb );
 
  704     a += mKernel[i] * qAlpha( *refRgb );
 
  707   return qRgba( r, g, b, a );
 
  710 inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurHorizontal( 
const int posx, 
unsigned char *sourceFirstLine, 
const int width )
 
  719   for ( 
int i = 0; i <= mRadius * 2; ++i )
 
  721     x = qBound( 0, posx + ( i - mRadius ), width - 1 );
 
  722     ref = sourceFirstLine + x * 4;
 
  724     QRgb *refRgb = 
reinterpret_cast< QRgb * 
>( ref );
 
  725     r += mKernel[i] * qRed( *refRgb );
 
  726     g += mKernel[i] * qGreen( *refRgb );
 
  727     b += mKernel[i] * qBlue( *refRgb );
 
  728     a += mKernel[i] * qAlpha( *refRgb );
 
  731   return qRgba( r, g, b, a );
 
  735 double *QgsImageOperation::createGaussianKernel( 
const int radius )
 
  737   double *kernel = 
new double[ radius * 2 + 1 ];
 
  738   double sigma = radius / 3.0;
 
  739   double twoSigmaSquared = 2 * sigma * sigma;
 
  740   double coefficient = 1.0 / std::sqrt( M_PI * twoSigmaSquared );
 
  741   double expCoefficient = -1.0 / twoSigmaSquared;
 
  745   for ( 
int i = 0; i <= radius; ++i )
 
  747     result = coefficient * std::exp( i * i * expCoefficient );
 
  748     kernel[ radius - i ] = result;
 
  752       kernel[radius + i] = result;
 
  757   for ( 
int i = 0; i <= radius * 2; ++i )
 
  770   runLineOperation( image, flipOperation );
 
  775   int width = image.width();
 
  776   int height = image.height();
 
  783   for ( 
int y = 0; y < height; ++y )
 
  786     const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  787     for ( 
int x = 0; x < width; ++x )
 
  789       if ( qAlpha( imgScanline[x] ) )
 
  804   for ( 
int y = height - 1; y >= ymin; --y )
 
  807     const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  808     for ( 
int x = 0; x < width; ++x )
 
  810       if ( qAlpha( imgScanline[x] ) )
 
  813         xmin = std::min( xmin, x );
 
  814         xmax = std::max( xmax, x );
 
  824   for ( 
int y = ymin; y <= ymax; ++y )
 
  826     const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  827     for ( 
int x = 0; x < xmin; ++x )
 
  829       if ( qAlpha( imgScanline[x] ) )
 
  838   for ( 
int y = ymin; y <= ymax; ++y )
 
  840     const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  841     for ( 
int x = width - 1; x > xmax; --x )
 
  843       if ( qAlpha( imgScanline[x] ) )
 
  851   if ( minSize.isValid() )
 
  853     if ( xmax - xmin < minSize.width() ) 
 
  855       xmin = std::max( ( xmax + xmin ) / 2 - minSize.width() / 2, 0 );
 
  856       xmax = xmin + minSize.width();
 
  858     if ( ymax - ymin < minSize.height() ) 
 
  860       ymin = std::max( ( ymax + ymin ) / 2 - minSize.height() / 2, 0 );
 
  861       ymax = ymin + minSize.height();
 
  867     const int dx = std::max( std::abs( xmax - width / 2 ), std::abs( xmin - width / 2 ) );
 
  868     const int dy = std::max( std::abs( ymax - height / 2 ), std::abs( ymin - height / 2 ) );
 
  869     xmin = std::max( 0, width / 2 - dx );
 
  870     xmax = std::min( width, width / 2 + dx );
 
  871     ymin = std::max( 0, height / 2 - dy );
 
  872     ymax = std::min( height, height / 2 + dy );
 
  875   return QRect( xmin, ymin, xmax - xmin, ymax - ymin );
 
  883 void QgsImageOperation::FlipLineOperation::operator()( QRgb *startRef, 
const int lineLength, 
const int bytesPerLine )
 
  885   int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
 
  888   unsigned char *p = 
reinterpret_cast< unsigned char * 
>( startRef );
 
  889   unsigned char *tempLine = 
new unsigned char[ lineLength * 4 ];
 
  890   for ( 
int i = 0; i < lineLength * 4; ++i, p += increment )
 
  892     tempLine[i++] = *( p++ );
 
  893     tempLine[i++] = *( p++ );
 
  894     tempLine[i++] = *( p++ );
 
  895     tempLine[i] = *( p );
 
  900   p = 
reinterpret_cast< unsigned char * 
>( startRef );
 
  901   for ( 
int i = ( lineLength - 1 ) * 4; i >= 0; i -= 7, p += increment )
 
  903     *( p++ ) = tempLine[i++];
 
  904     *( p++ ) = tempLine[i++];
 
  905     *( p++ ) = tempLine[i++];
 
  906     *( p ) = tempLine[i];
 
FlipType
Flip operation types.
@ FlipHorizontal
Flip the image horizontally.
static void convertToGrayscale(QImage &image, GrayscaleMode mode=GrayscaleLuminosity)
Convert a QImage to a grayscale image.
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
static void multiplyOpacity(QImage &image, double factor)
Multiplies opacity of image pixel values by a factor.
static void stackBlur(QImage &image, int radius, bool alphaOnly=false)
Performs a stack blur on an image.
static void flipImage(QImage &image, FlipType type)
Flips an image horizontally or vertically.
static void adjustHueSaturation(QImage &image, double saturation, const QColor &colorizeColor=QColor(), double colorizeStrength=1.0)
Alter the hue or saturation of a QImage.
static void distanceTransform(QImage &image, const QgsImageOperation::DistanceTransformProperties &properties)
Performs a distance transform on the source image and shades the result using a color ramp.
static QRect nonTransparentImageRect(const QImage &image, QSize minSize=QSize(), bool center=false)
Calculates the non-transparent region of an image.
static QImage cropTransparent(const QImage &image, QSize minSize=QSize(), bool center=false)
Crop any transparent border from around an image.
static void adjustBrightnessContrast(QImage &image, int brightness, double contrast)
Alter the brightness or contrast of a QImage.
GrayscaleMode
Modes for converting a QImage to grayscale.
static QImage * gaussianBlur(QImage &image, int radius)
Performs a gaussian blur on an image.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)