23#include <QtConcurrentMap> 
   29#define BLOCK_THREADS 16 
   35template <
typename PixelOperation>
 
   36void QgsImageOperation::runPixelOperation( QImage &image, PixelOperation &operation, 
QgsFeedback *feedback )
 
   38  if ( 
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
 
   42    runPixelOperationOnWholeImage( image, operation, feedback );
 
   47    QgsImageOperation::ProcessBlockUsingPixelOperation<PixelOperation> blockOp( operation, feedback );
 
   48    runBlockOperationInThreads( image, blockOp, QgsImageOperation::ByRow );
 
   52template <
typename PixelOperation>
 
   53void QgsImageOperation::runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation, 
QgsFeedback *feedback )
 
   55  int height = image.height();
 
   56  int width = image.width();
 
   57  for ( 
int y = 0; y < height; ++y )
 
   62    QRgb *ref = 
reinterpret_cast< QRgb * 
>( image.scanLine( y ) );
 
   63    for ( 
int x = 0; x < width; ++x )
 
   65      operation( ref[x], x, y );
 
   72template <
typename RectOperation>
 
   73void QgsImageOperation::runRectOperation( QImage &image, RectOperation &operation )
 
   76  if ( 
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
 
   80    runRectOperationOnWholeImage( image, operation );
 
   85    runBlockOperationInThreads( image, operation, ByRow );
 
   89template <
class RectOperation>
 
   90void QgsImageOperation::runRectOperationOnWholeImage( QImage &image, RectOperation &operation )
 
   93  fullImage.beginLine = 0;
 
   94  fullImage.endLine = image.height();
 
   95  fullImage.lineLength = image.width();
 
   96  fullImage.image = ℑ
 
   98  operation( fullImage );
 
  103template <
typename LineOperation>
 
  104void QgsImageOperation::runLineOperation( QImage &image, LineOperation &operation, 
QgsFeedback *feedback )
 
  107  if ( 
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
 
  111    runLineOperationOnWholeImage( image, operation, feedback );
 
  116    QgsImageOperation::ProcessBlockUsingLineOperation<LineOperation> blockOp( operation );
 
  117    runBlockOperationInThreads( image, blockOp, operation.direction() );
 
  121template <
class LineOperation>
 
  122void QgsImageOperation::runLineOperationOnWholeImage( QImage &image, LineOperation &operation, 
QgsFeedback *feedback )
 
  124  int height = image.height();
 
  125  int width = image.width();
 
  128  int bpl = image.bytesPerLine();
 
  129  if ( operation.direction() == ByRow )
 
  131    for ( 
int y = 0; y < height; ++y )
 
  136      QRgb *ref = 
reinterpret_cast< QRgb * 
>( image.scanLine( y ) );
 
  137      operation( ref, width, bpl );
 
  143    unsigned char *ref = image.scanLine( 0 );
 
  144    for ( 
int x = 0; x < width; ++x, ref += 4 )
 
  149      operation( 
reinterpret_cast< QRgb * 
>( ref ), height, bpl );
 
  157template <
typename BlockOperation>
 
  158void QgsImageOperation::runBlockOperationInThreads( QImage &image, BlockOperation &operation, LineOperationDirection direction )
 
  160  QList< ImageBlock > blocks;
 
  161  unsigned int height = image.height();
 
  162  unsigned int width = image.width();
 
  164  unsigned int blockDimension1 = ( direction == QgsImageOperation::ByRow ) ? height : width;
 
  165  unsigned int blockDimension2 = ( direction == QgsImageOperation::ByRow ) ? width : height;
 
  169  unsigned int begin = 0;
 
  171  for ( 
unsigned int block = 0; block < 
BLOCK_THREADS; ++block, begin += blockLen )
 
  174    newBlock.beginLine = begin;
 
  176    newBlock.endLine = block < ( 
BLOCK_THREADS - 1 ) ? begin + blockLen : blockDimension1;
 
  177    newBlock.lineLength = blockDimension2;
 
  178    newBlock.image = ℑ
 
  183  QtConcurrent::blockingMap( blocks, operation );
 
  203  GrayscalePixelOperation operation( mode );
 
  204  runPixelOperation( image, operation, feedback );
 
 
  207void QgsImageOperation::GrayscalePixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 const 
  215    case GrayscaleLuminosity:
 
  216      grayscaleLuminosityOp( rgb );
 
  218    case GrayscaleAverage:
 
  219      grayscaleAverageOp( rgb );
 
  221    case GrayscaleLightness:
 
  223      grayscaleLightnessOp( rgb );
 
  228void QgsImageOperation::grayscaleLightnessOp( QRgb &rgb )
 
  230  int red = qRed( rgb );
 
  231  int green = qGreen( rgb );
 
  232  int blue = qBlue( rgb );
 
  234  int min = std::min( std::min( red, green ), blue );
 
  235  int max = std::max( std::max( red, green ), blue );
 
  237  int lightness = std::min( ( min + max ) / 2, 255 );
 
  238  rgb = qRgba( lightness, lightness, lightness, qAlpha( rgb ) );
 
  241void QgsImageOperation::grayscaleLuminosityOp( QRgb &rgb )
 
  243  int luminosity = 0.21 * qRed( rgb ) + 0.72 * qGreen( rgb ) + 0.07 * qBlue( rgb );
 
  244  rgb = qRgba( luminosity, luminosity, luminosity, qAlpha( rgb ) );
 
  247void QgsImageOperation::grayscaleAverageOp( QRgb &rgb )
 
  249  int average = ( qRed( rgb ) + qGreen( rgb ) + qBlue( rgb ) ) / 3;
 
  250  rgb = qRgba( average, average, average, qAlpha( rgb ) );
 
  259  BrightnessContrastPixelOperation operation( brightness, contrast );
 
  260  runPixelOperation( image, operation, feedback );
 
 
  263void QgsImageOperation::BrightnessContrastPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 const 
  267  int red = adjustColorComponent( qRed( rgb ), mBrightness, mContrast );
 
  268  int blue = adjustColorComponent( qBlue( rgb ), mBrightness, mContrast );
 
  269  int green = adjustColorComponent( qGreen( rgb ), mBrightness, mContrast );
 
  270  rgb = qRgba( red, green, blue, qAlpha( rgb ) );
 
  273int QgsImageOperation::adjustColorComponent( 
int colorComponent, 
int brightness, 
double contrastFactor )
 
  275  return std::clamp( 
static_cast< int >( ( ( ( ( ( colorComponent / 255.0 ) - 0.5 ) * contrastFactor ) + 0.5 ) * 255 ) + brightness ), 0, 255 );
 
  283  HueSaturationPixelOperation operation( saturation, colorizeColor.isValid() && colorizeStrength > 0.0,
 
  284                                         colorizeColor.hue(), colorizeColor.saturation(), colorizeStrength );
 
  285  runPixelOperation( image, operation, feedback );
 
 
  288void QgsImageOperation::HueSaturationPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  292  QColor tmpColor( rgb );
 
  294  tmpColor.getHsl( &h, &s, &l );
 
  296  if ( mSaturation < 1.0 )
 
  299    s = std::min( 
static_cast< int >( s * mSaturation ), 255 );
 
  301  else if ( mSaturation > 1.0 )
 
  305    s = std::min( 
static_cast< int >( 255. * ( 1 - std::pow( 1 - ( s / 255. ), std::pow( mSaturation, 2 ) ) ) ), 255 );
 
  311    s = mColorizeSaturation;
 
  312    if ( mColorizeStrength < 1.0 )
 
  315      QColor colorizedColor = QColor::fromHsl( h, s, l );
 
  316      int colorizedR, colorizedG, colorizedB;
 
  317      colorizedColor.getRgb( &colorizedR, &colorizedG, &colorizedB );
 
  320      int r = mColorizeStrength * colorizedR + ( 1 - mColorizeStrength ) * tmpColor.red();
 
  321      int g = mColorizeStrength * colorizedG + ( 1 - mColorizeStrength ) * tmpColor.green();
 
  322      int b = mColorizeStrength * colorizedB + ( 1 - mColorizeStrength ) * tmpColor.blue();
 
  324      rgb = qRgba( r, g, b, qAlpha( rgb ) );
 
  329  tmpColor.setHsl( h, s, l, qAlpha( rgb ) );
 
  330  rgb = tmpColor.rgba();
 
  342  else if ( factor < 1.0 )
 
  346    QColor transparentFillColor = QColor( 0, 0, 0, 255 * factor );
 
  347    if ( image.format() == QImage::Format_Indexed8 )
 
  348      image = image.convertToFormat( QImage::Format_ARGB32 );
 
  352    QPainter painter( &image );
 
  353    painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
  354    painter.fillRect( 0, 0, image.width(), image.height(), transparentFillColor );
 
  361    MultiplyOpacityPixelOperation operation( factor );
 
  362    runPixelOperation( image, operation, feedback );
 
 
  366void QgsImageOperation::MultiplyOpacityPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  370  rgb = qRgba( qRed( rgb ), qGreen( rgb ), qBlue( rgb ), std::clamp( std::round( mFactor * qAlpha( rgb ) ), 0.0, 255.0 ) );
 
  377  QColor opaqueColor = color;
 
  378  opaqueColor.setAlpha( 255 );
 
  383  QPainter painter( &image );
 
  384  painter.setCompositionMode( QPainter::CompositionMode_SourceIn );
 
  385  painter.fillRect( 0, 0, image.width(), image.height(), opaqueColor );
 
 
  393  if ( ! properties.
ramp )
 
  395    QgsDebugError( QStringLiteral( 
"no color ramp specified for distance transform" ) );
 
  400  std::unique_ptr<double[]> array( 
new double[ 
static_cast< qgssize >( image.width() ) * image.height()] );
 
  405  ConvertToArrayPixelOperation convertToArray( image.width(), array.get(), properties.
shadeExterior );
 
  406  runPixelOperation( image, convertToArray, feedback );
 
  411  distanceTransform2d( array.get(), image.width(), image.height(), feedback );
 
  418    spread = std::sqrt( maxValueInDistanceTransformArray( array.get(), image.width() * image.height() ) );
 
  422    spread = properties.
spread;
 
  429  ShadeFromArrayOperation shadeFromArray( image.width(), array.get(), spread, properties );
 
  430  runPixelOperation( image, shadeFromArray, feedback );
 
 
  433void QgsImageOperation::ConvertToArrayPixelOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  438    if ( qAlpha( rgb ) > 0 )
 
  441      mArray[ idx ] = 1 - qAlpha( rgb ) / 255.0;
 
  452    if ( qAlpha( rgb ) == 255 )
 
  466void QgsImageOperation::distanceTransform1d( 
double *f, 
int n, 
int *v, 
double *z, 
double *d )
 
  472  for ( 
int q = 1; q <= n - 1; q++ )
 
  474    double s  = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
 
  478      s  = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
 
  487  for ( 
int q = 0; q <= n - 1; q++ )
 
  489    while ( z[k + 1] < q )
 
  491    d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
 
  495double QgsImageOperation::maxValueInDistanceTransformArray( 
const double *array, 
const unsigned int size )
 
  497  double dtMaxValue = array[0];
 
  498  for ( 
unsigned int i = 1; i < size; ++i )
 
  500    if ( array[i] > dtMaxValue )
 
  502      dtMaxValue = array[i];
 
  509void QgsImageOperation::distanceTransform2d( 
double *im, 
int width, 
int height, 
QgsFeedback *feedback )
 
  511  int maxDimension = std::max( width, height );
 
  513  std::unique_ptr<double[]> f( 
new double[ maxDimension ] );
 
  514  std::unique_ptr<int []> v( 
new int[ maxDimension ] );
 
  515  std::unique_ptr<double[]>z( 
new double[ maxDimension + 1 ] );
 
  516  std::unique_ptr<double[]>d( 
new double[ maxDimension ] );
 
  519  for ( 
int x = 0; x < width; x++ )
 
  524    for ( 
int y = 0; y < height; y++ )
 
  526      f[y] = im[ x + y * width ];
 
  528    distanceTransform1d( f.get(), height, v.get(), z.get(), d.get() );
 
  529    for ( 
int y = 0; y < height; y++ )
 
  531      im[ x + y * width ] = d[y];
 
  536  for ( 
int y = 0; y < height; y++ )
 
  541    for ( 
int x = 0; x < width; x++ )
 
  543      f[x] = im[  x + y * width ];
 
  545    distanceTransform1d( f.get(), width, v.get(), z.get(), d.get() );
 
  546    for ( 
int x = 0; x < width; x++ )
 
  548      im[  x + y * width ] = d[x];
 
  553void QgsImageOperation::ShadeFromArrayOperation::operator()( QRgb &rgb, 
const int x, 
const int y )
 
  555  if ( ! mProperties.ramp )
 
  560    rgb = mProperties.ramp->color( 1.0 ).rgba();
 
  564  int idx = y * mWidth + x;
 
  567  double squaredVal = mArray[ idx ];
 
  568  if ( squaredVal > mSpreadSquared )
 
  570    rgb = Qt::transparent;
 
  574  double distance = std::sqrt( squaredVal );
 
  575  double val = distance / mSpread;
 
  576  QColor rampColor = mProperties.ramp->color( val );
 
  578  if ( ( mProperties.shadeExterior && distance > mSpread - 1 ) )
 
  581    double alphaMultiplyFactor = mSpread - distance;
 
  582    rampColor.setAlpha( rampColor.alpha() * alphaMultiplyFactor );
 
  584  rgb = rampColor.rgba();
 
  592  int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
 
  593  int alpha = ( radius < 1 )  ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
 
  599  QImage::Format originalFormat = image.format();
 
  600  QImage *pImage = ℑ
 
  601  std::unique_ptr< QImage> convertedImage;
 
  602  if ( !alphaOnly && originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  604    convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
 
  605    pImage = convertedImage.get();
 
  607  else if ( alphaOnly && originalFormat != QImage::Format_ARGB32 )
 
  609    convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32 ) );
 
  610    pImage = convertedImage.get();
 
  621    i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
 
  623  StackBlurLineOperation topToBottomBlur( alpha, QgsImageOperation::ByColumn, 
true, i1, i2, feedback );
 
  624  runLineOperation( *pImage, topToBottomBlur, feedback );
 
  629  StackBlurLineOperation leftToRightBlur( alpha, QgsImageOperation::ByRow, 
true, i1, i2, feedback );
 
  630  runLineOperation( *pImage, leftToRightBlur, feedback );
 
  635  StackBlurLineOperation bottomToTopBlur( alpha, QgsImageOperation::ByColumn, 
false, i1, i2, feedback );
 
  636  runLineOperation( *pImage, bottomToTopBlur, feedback );
 
  641  StackBlurLineOperation rightToLeftBlur( alpha, QgsImageOperation::ByRow, 
false, i1, i2, feedback );
 
  642  runLineOperation( *pImage, rightToLeftBlur, feedback );
 
  647  if ( pImage->format() != originalFormat )
 
  649    image = pImage->convertToFormat( originalFormat );
 
 
  657  int width = image.width();
 
  658  int height = image.height();
 
  663    QImage *copy = 
new QImage( image.copy() );
 
  667  std::unique_ptr<double[]>kernel( createGaussianKernel( radius ) );
 
  672  QImage::Format originalFormat = image.format();
 
  673  QImage *pImage = ℑ
 
  674  std::unique_ptr< QImage> convertedImage;
 
  675  if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  677    convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
 
  678    pImage = convertedImage.get();
 
  688  QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
 
  689  GaussianBlurOperation rowBlur( radius, QgsImageOperation::ByRow, &xBlurImage, kernel.get(), feedback );
 
  690  runRectOperation( *pImage, rowBlur );
 
  696  auto yBlurImage = std::make_unique< QImage >( width, height, QImage::Format_ARGB32_Premultiplied );
 
  697  GaussianBlurOperation colBlur( radius, QgsImageOperation::ByColumn, yBlurImage.get(), kernel.get(), feedback );
 
  698  runRectOperation( xBlurImage, colBlur );
 
  705  if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
 
  707    return new QImage( yBlurImage->convertToFormat( originalFormat ) );
 
  710  return yBlurImage.release();
 
 
  713void QgsImageOperation::GaussianBlurOperation::operator()( QgsImageOperation::ImageBlock &block )
 
  715  if ( mFeedback && mFeedback->isCanceled() )
 
  718  int width = block.image->width();
 
  719  int height = block.image->height();
 
  720  int sourceBpl = block.image->bytesPerLine();
 
  722  unsigned char *outputLineRef = mDestImage->scanLine( block.beginLine );
 
  723  QRgb *destRef = 
nullptr;
 
  724  if ( mDirection == ByRow )
 
  726    unsigned char *sourceFirstLine = block.image->scanLine( 0 );
 
  727    unsigned char *sourceRef;
 
  730    for ( 
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl )
 
  732      if ( mFeedback && mFeedback->isCanceled() )
 
  735      sourceRef = sourceFirstLine;
 
  736      destRef = 
reinterpret_cast< QRgb * 
>( outputLineRef );
 
  737      for ( 
int x = 0; x < width; ++x, ++destRef, sourceRef += 4 )
 
  739        if ( mFeedback && mFeedback->isCanceled() )
 
  742        *destRef = gaussianBlurVertical( y, sourceRef, sourceBpl, height );
 
  748    unsigned char *sourceRef = block.image->scanLine( block.beginLine );
 
  749    for ( 
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl, sourceRef += sourceBpl )
 
  751      if ( mFeedback && mFeedback->isCanceled() )
 
  754      destRef = 
reinterpret_cast< QRgb * 
>( outputLineRef );
 
  755      for ( 
int x = 0; x < width; ++x, ++destRef )
 
  757        if ( mFeedback && mFeedback->isCanceled() )
 
  760        *destRef = gaussianBlurHorizontal( x, sourceRef, width );
 
  766inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurVertical( 
const int posy, 
unsigned char *sourceFirstLine, 
const int sourceBpl, 
const int height )
 const 
  775  for ( 
int i = 0; i <= mRadius * 2; ++i )
 
  777    y = std::clamp( posy + ( i - mRadius ), 0, height - 1 );
 
  778    ref = sourceFirstLine + 
static_cast< std::size_t 
>( sourceBpl ) * y;
 
  780    QRgb *refRgb = 
reinterpret_cast< QRgb * 
>( ref );
 
  781    r += mKernel[i] * qRed( *refRgb );
 
  782    g += mKernel[i] * qGreen( *refRgb );
 
  783    b += mKernel[i] * qBlue( *refRgb );
 
  784    a += mKernel[i] * qAlpha( *refRgb );
 
  787  return qRgba( r, g, b, a );
 
  790inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurHorizontal( 
const int posx, 
unsigned char *sourceFirstLine, 
const int width )
 const 
  799  for ( 
int i = 0; i <= mRadius * 2; ++i )
 
  801    x = std::clamp( posx + ( i - mRadius ), 0, width - 1 );
 
  802    ref = sourceFirstLine + x * 4;
 
  804    QRgb *refRgb = 
reinterpret_cast< QRgb * 
>( ref );
 
  805    r += mKernel[i] * qRed( *refRgb );
 
  806    g += mKernel[i] * qGreen( *refRgb );
 
  807    b += mKernel[i] * qBlue( *refRgb );
 
  808    a += mKernel[i] * qAlpha( *refRgb );
 
  811  return qRgba( r, g, b, a );
 
  815double *QgsImageOperation::createGaussianKernel( 
const int radius )
 
  817  double *kernel = 
new double[ radius * 2 + 1 ];
 
  818  double sigma = radius / 3.0;
 
  819  double twoSigmaSquared = 2 * sigma * sigma;
 
  820  double coefficient = 1.0 / std::sqrt( M_PI * twoSigmaSquared );
 
  821  double expCoefficient = -1.0 / twoSigmaSquared;
 
  825  for ( 
int i = 0; i <= radius; ++i )
 
  827    result = coefficient * std::exp( i * i * expCoefficient );
 
  828    kernel[ radius - i ] = result;
 
  832      kernel[radius + i] = result;
 
  837  for ( 
int i = 0; i <= radius * 2; ++i )
 
  851  runLineOperation( image, flipOperation );
 
 
  856  int width = image.width();
 
  857  int height = image.height();
 
  864  for ( 
int y = 0; y < height; ++y )
 
  867    const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  868    for ( 
int x = 0; x < width; ++x )
 
  870      if ( qAlpha( imgScanline[x] ) )
 
  885  for ( 
int y = height - 1; y >= ymin; --y )
 
  888    const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  889    for ( 
int x = 0; x < width; ++x )
 
  891      if ( qAlpha( imgScanline[x] ) )
 
  894        xmin = std::min( xmin, x );
 
  895        xmax = std::max( xmax, x );
 
  905  for ( 
int y = ymin; y <= ymax; ++y )
 
  907    const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  908    for ( 
int x = 0; x < xmin; ++x )
 
  910      if ( qAlpha( imgScanline[x] ) )
 
  919  for ( 
int y = ymin; y <= ymax; ++y )
 
  921    const QRgb *imgScanline = 
reinterpret_cast< const QRgb * 
>( image.constScanLine( y ) );
 
  922    for ( 
int x = width - 1; x > xmax; --x )
 
  924      if ( qAlpha( imgScanline[x] ) )
 
  932  if ( minSize.isValid() )
 
  934    if ( xmax - xmin < minSize.width() ) 
 
  936      xmin = std::max( ( xmax + xmin ) / 2 - minSize.width() / 2, 0 );
 
  937      xmax = xmin + minSize.width();
 
  939    if ( ymax - ymin < minSize.height() ) 
 
  941      ymin = std::max( ( ymax + ymin ) / 2 - minSize.height() / 2, 0 );
 
  942      ymax = ymin + minSize.height();
 
  948    const int dx = std::max( std::abs( xmax - width / 2 ), std::abs( xmin - width / 2 ) );
 
  949    const int dy = std::max( std::abs( ymax - height / 2 ), std::abs( ymin - height / 2 ) );
 
  950    xmin = std::max( 0, width / 2 - dx );
 
  951    xmax = std::min( width, width / 2 + dx );
 
  952    ymin = std::max( 0, height / 2 - dy );
 
  953    ymax = std::min( height, height / 2 + dy );
 
  956  return QRect( xmin, ymin, xmax - xmin, ymax - ymin );
 
 
  964void QgsImageOperation::FlipLineOperation::operator()( QRgb *startRef, 
const int lineLength, 
const int bytesPerLine )
 const 
  966  int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
 
  969  unsigned char *p = 
reinterpret_cast< unsigned char * 
>( startRef );
 
  970  unsigned char *tempLine = 
new unsigned char[ lineLength * 4 ];
 
  971  for ( 
int i = 0; i < lineLength * 4; ++i, p += increment )
 
  973    tempLine[i++] = *( p++ );
 
  974    tempLine[i++] = *( p++ );
 
  975    tempLine[i++] = *( p++ );
 
  976    tempLine[i] = *( p );
 
  981  p = 
reinterpret_cast< unsigned char * 
>( startRef );
 
  982  for ( 
int i = ( lineLength - 1 ) * 4; i >= 0; i -= 7, p += increment )
 
  984    *( p++ ) = tempLine[i++];
 
  985    *( p++ ) = tempLine[i++];
 
  986    *( p++ ) = tempLine[i++];
 
  987    *( p ) = tempLine[i];
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
static void adjustHueSaturation(QImage &image, double saturation, const QColor &colorizeColor=QColor(), double colorizeStrength=1.0, QgsFeedback *feedback=nullptr)
Alter the hue or saturation of a QImage.
 
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
 
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.
 
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
 
static void flipImage(QImage &image, FlipType type)
Flips an image horizontally or vertically.
 
static void adjustBrightnessContrast(QImage &image, int brightness, double contrast, QgsFeedback *feedback=nullptr)
Alter the brightness or contrast of a QImage.
 
static QImage * gaussianBlur(QImage &image, int radius, QgsFeedback *feedback=nullptr)
Performs a gaussian blur on an image.
 
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.
 
static void convertToGrayscale(QImage &image, GrayscaleMode mode=GrayscaleLuminosity, QgsFeedback *feedback=nullptr)
Convert a QImage to a grayscale image.
 
GrayscaleMode
Modes for converting a QImage to grayscale.
 
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)
 
#define QgsDebugError(str)