30#include <QtConcurrentMap>
32using namespace Qt::StringLiterals;
36#define BLOCK_THREADS 16
42template<
typename PixelOperation>
void QgsImageOperation::runPixelOperation( QImage &image, PixelOperation &operation,
QgsFeedback *feedback )
44 if (
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
48 runPixelOperationOnWholeImage( image, operation, feedback );
53 QgsImageOperation::ProcessBlockUsingPixelOperation<PixelOperation> blockOp( operation, feedback );
54 runBlockOperationInThreads( image, blockOp, QgsImageOperation::ByRow );
58template<
typename PixelOperation>
void QgsImageOperation::runPixelOperationOnWholeImage( QImage &image, PixelOperation &operation,
QgsFeedback *feedback )
60 int height = image.height();
61 int width = image.width();
62 for (
int y = 0; y < height; ++y )
67 QRgb *ref =
reinterpret_cast< QRgb *
>( image.scanLine( y ) );
68 for (
int x = 0; x < width; ++x )
70 operation( ref[x], x, y );
77template<
typename RectOperation>
void QgsImageOperation::runRectOperation( QImage &image, RectOperation &operation )
80 if (
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
84 runRectOperationOnWholeImage( image, operation );
89 runBlockOperationInThreads( image, operation, ByRow );
93template<
class RectOperation>
void QgsImageOperation::runRectOperationOnWholeImage( QImage &image, RectOperation &operation )
96 fullImage.beginLine = 0;
97 fullImage.endLine = image.height();
98 fullImage.lineLength = image.width();
99 fullImage.image = ℑ
101 operation( fullImage );
106template<
typename LineOperation>
void QgsImageOperation::runLineOperation( QImage &image, LineOperation &operation,
QgsFeedback *feedback )
109 if (
static_cast< qgssize >( image.height() ) * image.width() < 100000 )
113 runLineOperationOnWholeImage( image, operation, feedback );
118 QgsImageOperation::ProcessBlockUsingLineOperation<LineOperation> blockOp( operation );
119 runBlockOperationInThreads( image, blockOp, operation.direction() );
123template<
class LineOperation>
void QgsImageOperation::runLineOperationOnWholeImage( QImage &image, LineOperation &operation,
QgsFeedback *feedback )
125 int height = image.height();
126 int width = image.width();
129 int bpl = image.bytesPerLine();
130 if ( operation.direction() == ByRow )
132 for (
int y = 0; y < height; ++y )
137 QRgb *ref =
reinterpret_cast< QRgb *
>( image.scanLine( y ) );
138 operation( ref, width, bpl );
144 unsigned char *ref = image.scanLine( 0 );
145 for (
int x = 0; x < width; ++x, ref += 4 )
150 operation(
reinterpret_cast< QRgb *
>( ref ), height, bpl );
158template<
typename BlockOperation>
void 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
216 grayscaleLuminosityOp( rgb );
219 grayscaleAverageOp( rgb );
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, colorizeColor.hue(), colorizeColor.saturation(), colorizeStrength );
284 runPixelOperation( image, operation, feedback );
287void QgsImageOperation::HueSaturationPixelOperation::operator()( QRgb &rgb,
const int x,
const int y )
const
291 QColor tmpColor( rgb );
293 tmpColor.getHsl( &h, &s, &l );
295 if ( mSaturation < 1.0 )
298 s = std::min(
static_cast< int >( s * mSaturation ), 255 );
300 else if ( mSaturation > 1.0 )
304 s = std::min(
static_cast< int >( 255. * ( 1 - std::pow( 1 - ( s / 255. ), std::pow( mSaturation, 2 ) ) ) ), 255 );
310 s = mColorizeSaturation;
311 if ( mColorizeStrength < 1.0 )
314 QColor colorizedColor = QColor::fromHsl( h, s, l );
315 int colorizedR, colorizedG, colorizedB;
316 colorizedColor.getRgb( &colorizedR, &colorizedG, &colorizedB );
319 int r = mColorizeStrength * colorizedR + ( 1 - mColorizeStrength ) * tmpColor.red();
320 int g = mColorizeStrength * colorizedG + ( 1 - mColorizeStrength ) * tmpColor.green();
321 int b = mColorizeStrength * colorizedB + ( 1 - mColorizeStrength ) * tmpColor.blue();
323 rgb = qRgba( r, g, b, qAlpha( rgb ) );
328 tmpColor.setHsl( h, s, l, qAlpha( rgb ) );
329 rgb = tmpColor.rgba();
341 else if ( factor < 1.0 )
345 QColor transparentFillColor = QColor( 0, 0, 0, 255 * factor );
346 if ( image.format() == QImage::Format_Indexed8 )
347 image = image.convertToFormat( QImage::Format_ARGB32 );
351 QPainter painter( &image );
352 painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
353 painter.fillRect( 0, 0, image.width(), image.height(), transparentFillColor );
360 MultiplyOpacityPixelOperation operation( factor );
361 runPixelOperation( image, operation, feedback );
365void QgsImageOperation::MultiplyOpacityPixelOperation::operator()( QRgb &rgb,
const int x,
const int y )
const
369 rgb = qRgba( qRed( rgb ), qGreen( rgb ), qBlue( rgb ), std::clamp( std::round( mFactor * qAlpha( rgb ) ), 0.0, 255.0 ) );
376 QColor opaqueColor = color;
377 opaqueColor.setAlpha( 255 );
382 QPainter painter( &image );
383 painter.setCompositionMode( QPainter::CompositionMode_SourceIn );
384 painter.fillRect( 0, 0, image.width(), image.height(), opaqueColor );
392 if ( !properties.
ramp )
394 QgsDebugError( u
"no color ramp specified for distance transform"_s );
399 std::unique_ptr<double[]> array(
new double[
static_cast< qgssize >( image.width() ) * image.height()] );
404 ConvertToArrayPixelOperation convertToArray( image.width(), array.get(), properties.
shadeExterior );
405 runPixelOperation( image, convertToArray, feedback );
410 distanceTransform2d( array.get(), image.width(), image.height(), feedback );
417 spread = std::sqrt( maxValueInDistanceTransformArray( array.get(), image.width() * image.height() ) );
421 spread = properties.
spread;
428 ShadeFromArrayOperation shadeFromArray( image.width(), array.get(), spread, properties );
429 runPixelOperation( image, shadeFromArray, feedback );
432void QgsImageOperation::ConvertToArrayPixelOperation::operator()( QRgb &rgb,
const int x,
const int y )
437 if ( qAlpha( rgb ) > 0 )
440 mArray[idx] = 1 - qAlpha( rgb ) / 255.0;
451 if ( qAlpha( rgb ) == 255 )
465void QgsImageOperation::distanceTransform1d(
double *f,
int n,
int *v,
double *z,
double *d )
471 for (
int q = 1; q <= n - 1; q++ )
473 double s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
477 s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
486 for (
int q = 0; q <= n - 1; q++ )
488 while ( z[k + 1] < q )
490 d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
494double QgsImageOperation::maxValueInDistanceTransformArray(
const double *array,
const unsigned int size )
496 double dtMaxValue = array[0];
497 for (
unsigned int i = 1; i < size; ++i )
499 if ( array[i] > dtMaxValue )
501 dtMaxValue = array[i];
508void QgsImageOperation::distanceTransform2d(
double *im,
int width,
int height, QgsFeedback *feedback )
510 int maxDimension = std::max( width, height );
512 std::unique_ptr<double[]> f(
new double[maxDimension] );
513 std::unique_ptr<int[]> v(
new int[maxDimension] );
514 std::unique_ptr<double[]> z(
new double[maxDimension + 1] );
515 std::unique_ptr<double[]> d(
new double[maxDimension] );
518 for (
int x = 0; x < width; x++ )
523 for (
int y = 0; y < height; y++ )
525 f[y] = im[x + y * width];
527 distanceTransform1d( f.get(), height, v.get(), z.get(), d.get() );
528 for (
int y = 0; y < height; y++ )
530 im[x + y * width] = d[y];
535 for (
int y = 0; y < height; y++ )
540 for (
int x = 0; x < width; x++ )
542 f[x] = im[x + y * width];
544 distanceTransform1d( f.get(), width, v.get(), z.get(), d.get() );
545 for (
int x = 0; x < width; x++ )
547 im[x + y * width] = d[x];
552void QgsImageOperation::ShadeFromArrayOperation::operator()( QRgb &rgb,
const int x,
const int y )
554 if ( !mProperties.ramp )
559 rgb = mProperties.ramp->color( 1.0 ).rgba();
563 int idx = y * mWidth + x;
566 double squaredVal = mArray[idx];
567 if ( squaredVal > mSpreadSquared )
569 rgb = Qt::transparent;
573 double distance = std::sqrt( squaredVal );
574 double val = distance / mSpread;
575 QColor rampColor = mProperties.ramp->color( val );
577 if ( ( mProperties.shadeExterior && distance > mSpread - 1 ) )
580 double alphaMultiplyFactor = mSpread - distance;
581 rampColor.setAlpha( rampColor.alpha() * alphaMultiplyFactor );
583 rgb = rampColor.rgba();
591 int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
592 int alpha = ( radius < 1 ) ? 16 : ( radius > 17 ) ? 1 : tab[radius - 1];
598 QImage::Format originalFormat = image.format();
599 QImage *pImage = ℑ
600 std::unique_ptr< QImage> convertedImage;
601 if ( !alphaOnly && originalFormat != QImage::Format_ARGB32_Premultiplied )
603 convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
604 pImage = convertedImage.get();
606 else if ( alphaOnly && originalFormat != QImage::Format_ARGB32 )
608 convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32 ) );
609 pImage = convertedImage.get();
620 i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
622 StackBlurLineOperation topToBottomBlur( alpha, QgsImageOperation::ByColumn,
true, i1, i2, feedback );
623 runLineOperation( *pImage, topToBottomBlur, feedback );
628 StackBlurLineOperation leftToRightBlur( alpha, QgsImageOperation::ByRow,
true, i1, i2, feedback );
629 runLineOperation( *pImage, leftToRightBlur, feedback );
634 StackBlurLineOperation bottomToTopBlur( alpha, QgsImageOperation::ByColumn,
false, i1, i2, feedback );
635 runLineOperation( *pImage, bottomToTopBlur, feedback );
640 StackBlurLineOperation rightToLeftBlur( alpha, QgsImageOperation::ByRow,
false, i1, i2, feedback );
641 runLineOperation( *pImage, rightToLeftBlur, feedback );
646 if ( pImage->format() != originalFormat )
648 image = pImage->convertToFormat( originalFormat );
656 int width = image.width();
657 int height = image.height();
662 QImage *copy =
new QImage( image.copy() );
666 std::unique_ptr<double[]> kernel( createGaussianKernel( radius ) );
671 QImage::Format originalFormat = image.format();
672 QImage *pImage = ℑ
673 std::unique_ptr< QImage> convertedImage;
674 if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
676 convertedImage = std::make_unique< QImage >( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
677 pImage = convertedImage.get();
687 QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
688 GaussianBlurOperation rowBlur( radius, QgsImageOperation::ByRow, &xBlurImage, kernel.get(), feedback );
689 runRectOperation( *pImage, rowBlur );
695 auto yBlurImage = std::make_unique< QImage >( width, height, QImage::Format_ARGB32_Premultiplied );
696 GaussianBlurOperation colBlur( radius, QgsImageOperation::ByColumn, yBlurImage.get(), kernel.get(), feedback );
697 runRectOperation( xBlurImage, colBlur );
704 if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
706 return new QImage( yBlurImage->convertToFormat( originalFormat ) );
709 return yBlurImage.release();
712void QgsImageOperation::GaussianBlurOperation::operator()( QgsImageOperation::ImageBlock &block )
714 if ( mFeedback && mFeedback->isCanceled() )
717 int width = block.image->width();
718 int height = block.image->height();
719 int sourceBpl = block.image->bytesPerLine();
721 unsigned char *outputLineRef = mDestImage->scanLine( block.beginLine );
722 QRgb *destRef =
nullptr;
723 if ( mDirection == ByRow )
725 unsigned char *sourceFirstLine = block.image->scanLine( 0 );
726 unsigned char *sourceRef;
729 for (
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl )
731 if ( mFeedback && mFeedback->isCanceled() )
734 sourceRef = sourceFirstLine;
735 destRef =
reinterpret_cast< QRgb *
>( outputLineRef );
736 for (
int x = 0; x < width; ++x, ++destRef, sourceRef += 4 )
738 if ( mFeedback && mFeedback->isCanceled() )
741 *destRef = gaussianBlurVertical( y, sourceRef, sourceBpl, height );
747 unsigned char *sourceRef = block.image->scanLine( block.beginLine );
748 for (
unsigned int y = block.beginLine; y < block.endLine; ++y, outputLineRef += mDestImageBpl, sourceRef += sourceBpl )
750 if ( mFeedback && mFeedback->isCanceled() )
753 destRef =
reinterpret_cast< QRgb *
>( outputLineRef );
754 for (
int x = 0; x < width; ++x, ++destRef )
756 if ( mFeedback && mFeedback->isCanceled() )
759 *destRef = gaussianBlurHorizontal( x, sourceRef, width );
765inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurVertical(
const int posy,
unsigned char *sourceFirstLine,
const int sourceBpl,
const int height )
const
774 for (
int i = 0; i <= mRadius * 2; ++i )
776 y = std::clamp( posy + ( i - mRadius ), 0, height - 1 );
777 ref = sourceFirstLine +
static_cast< std::size_t
>( sourceBpl ) * y;
779 QRgb *refRgb =
reinterpret_cast< QRgb *
>( ref );
780 r += mKernel[i] * qRed( *refRgb );
781 g += mKernel[i] * qGreen( *refRgb );
782 b += mKernel[i] * qBlue( *refRgb );
783 a += mKernel[i] * qAlpha( *refRgb );
786 return qRgba( r, g, b, a );
789inline QRgb QgsImageOperation::GaussianBlurOperation::gaussianBlurHorizontal(
const int posx,
unsigned char *sourceFirstLine,
const int width )
const
798 for (
int i = 0; i <= mRadius * 2; ++i )
800 x = std::clamp( posx + ( i - mRadius ), 0, width - 1 );
801 ref = sourceFirstLine + x * 4;
803 QRgb *refRgb =
reinterpret_cast< QRgb *
>( ref );
804 r += mKernel[i] * qRed( *refRgb );
805 g += mKernel[i] * qGreen( *refRgb );
806 b += mKernel[i] * qBlue( *refRgb );
807 a += mKernel[i] * qAlpha( *refRgb );
810 return qRgba( r, g, b, a );
814double *QgsImageOperation::createGaussianKernel(
const int radius )
816 double *kernel =
new double[radius * 2 + 1];
817 double sigma = radius / 3.0;
818 double twoSigmaSquared = 2 * sigma * sigma;
819 double coefficient = 1.0 / std::sqrt( M_PI * twoSigmaSquared );
820 double expCoefficient = -1.0 / twoSigmaSquared;
824 for (
int i = 0; i <= radius; ++i )
826 result = coefficient * std::exp( i * i * expCoefficient );
827 kernel[radius - i] = result;
831 kernel[radius + i] = result;
836 for (
int i = 0; i <= radius * 2; ++i )
850 runLineOperation( image, flipOperation );
855 int width = image.width();
856 int height = image.height();
863 for (
int y = 0; y < height; ++y )
866 const QRgb *imgScanline =
reinterpret_cast< const QRgb *
>( image.constScanLine( y ) );
867 for (
int x = 0; x < width; ++x )
869 if ( qAlpha( imgScanline[x] ) )
884 for (
int y = height - 1; y >= ymin; --y )
887 const QRgb *imgScanline =
reinterpret_cast< const QRgb *
>( image.constScanLine( y ) );
888 for (
int x = 0; x < width; ++x )
890 if ( qAlpha( imgScanline[x] ) )
893 xmin = std::min( xmin, x );
894 xmax = std::max( xmax, x );
904 for (
int y = ymin; y <= ymax; ++y )
906 const QRgb *imgScanline =
reinterpret_cast< const QRgb *
>( image.constScanLine( y ) );
907 for (
int x = 0; x < xmin; ++x )
909 if ( qAlpha( imgScanline[x] ) )
918 for (
int y = ymin; y <= ymax; ++y )
920 const QRgb *imgScanline =
reinterpret_cast< const QRgb *
>( image.constScanLine( y ) );
921 for (
int x = width - 1; x > xmax; --x )
923 if ( qAlpha( imgScanline[x] ) )
931 if ( minSize.isValid() )
933 if ( xmax - xmin < minSize.width() )
935 xmin = std::max( ( xmax + xmin ) / 2 - minSize.width() / 2, 0 );
936 xmax = xmin + minSize.width();
938 if ( ymax - ymin < minSize.height() )
940 ymin = std::max( ( ymax + ymin ) / 2 - minSize.height() / 2, 0 );
941 ymax = ymin + minSize.height();
947 const int dx = std::max( std::abs( xmax - width / 2 ), std::abs( xmin - width / 2 ) );
948 const int dy = std::max( std::abs( ymax - height / 2 ), std::abs( ymin - height / 2 ) );
949 xmin = std::max( 0, width / 2 - dx );
950 xmax = std::min( width, width / 2 + dx );
951 ymin = std::max( 0, height / 2 - dy );
952 ymax = std::min( height, height / 2 + dy );
955 return QRect( xmin, ymin, xmax - xmin, ymax - ymin );
965 if ( tolerance == 0 )
969 return std::abs( qRed( c1 ) - qRed( c2 ) ) <= tolerance
970 && std::abs( qGreen( c1 ) - qGreen( c2 ) ) <= tolerance
971 && std::abs( qBlue( c1 ) - qBlue( c2 ) ) <= tolerance
972 && std::abs( qAlpha( c1 ) - qAlpha( c2 ) ) <= tolerance;
977 if ( image.isNull() || !image.rect().contains( startPoint ) )
983 if ( image.format() != QImage::Format_ARGB32 && image.format() != QImage::Format_ARGB32_Premultiplied && image.format() != QImage::Format_RGB32 )
985 resultImage = image.convertToFormat( QImage::Format_ARGB32 );
989 resultImage = image.copy();
992 const QRgb targetColorRgb = resultImage.pixel( startPoint );
993 const QRgb newColorRgb = newColor.rgba();
999 const int width = resultImage.width();
1000 const int height = resultImage.height();
1002 std::stack<QPoint> stack;
1003 stack.push( startPoint );
1004 while ( !stack.empty() )
1011 const QPoint pt = stack.top();
1013 const int x = pt.x();
1014 const int y = pt.y();
1015 QRgb *scanline =
reinterpret_cast< QRgb *
>( resultImage.scanLine( y ) );
1025 scanline[x2] = newColorRgb;
1030 bool spanAbove =
false;
1031 bool spanBelow =
false;
1033 QRgb *scanlineAbove = ( y > 0 ) ?
reinterpret_cast< QRgb *
>( resultImage.scanLine( y - 1 ) ) :
nullptr;
1034 QRgb *scanlineBelow = ( y < height - 1 ) ?
reinterpret_cast< QRgb *
>( resultImage.scanLine( y + 1 ) ) :
nullptr;
1035 for (
int currX = x1; currX <= x2; currX++ )
1038 if ( scanlineAbove )
1041 if ( !spanAbove && match )
1043 stack.push( QPoint( currX, y - 1 ) );
1046 else if ( spanAbove && !match )
1053 if ( scanlineBelow )
1056 if ( !spanBelow && match )
1058 stack.push( QPoint( currX, y + 1 ) );
1061 else if ( spanBelow && !match )
1072void QgsImageOperation::FlipLineOperation::operator()( QRgb *startRef,
const int lineLength,
const int bytesPerLine )
const
1074 int increment = ( mDirection == QgsImageOperation::ByRow ) ? 4 : bytesPerLine;
1077 unsigned char *p =
reinterpret_cast< unsigned char *
>( startRef );
1078 unsigned char *tempLine =
new unsigned char[lineLength * 4];
1079 for (
int i = 0; i < lineLength * 4; ++i, p += increment )
1081 tempLine[i++] = *( p++ );
1082 tempLine[i++] = *( p++ );
1083 tempLine[i++] = *( p++ );
1084 tempLine[i] = *( p );
1089 p =
reinterpret_cast< unsigned char *
>( startRef );
1090 for (
int i = ( lineLength - 1 ) * 4; i >= 0; i -= 7, p += increment )
1092 *( p++ ) = tempLine[i++];
1093 *( p++ ) = tempLine[i++];
1094 *( p++ ) = tempLine[i++];
1095 *( 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 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 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.
@ 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.
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).
bool colorsMatchFloodFill(QRgb c1, QRgb c2, int tolerance)
#define QgsDebugError(str)