Fix calculation of blur ops with non ARGB32_Premultiplied images
@ -10,10 +10,6 @@
|
||||
* Operations are written to either modify an image in place or return a new image, depending
|
||||
* on which is faster for the particular operation.
|
||||
*
|
||||
* \note These operations do not work using premultiplied ARGB32_Premultiplied images
|
||||
* - please make sure the images are converted to standard ARGB32 images prior to calling
|
||||
* these operations.
|
||||
*
|
||||
* \note Added in version 2.7
|
||||
*/
|
||||
class QgsImageOperation
|
||||
@ -115,6 +111,8 @@ class QgsImageOperation
|
||||
* @param image QImage to blur
|
||||
* @param radius blur radius in pixels, maximum value of 16
|
||||
* @param alphaOnly set to true to blur only the alpha component of the image
|
||||
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied if
|
||||
* alphaOnly is set to false, or ARGB32 if alphaOnly is true
|
||||
*/
|
||||
static void stackBlur( QImage &image, const int radius, const bool alphaOnly = false );
|
||||
|
||||
@ -123,6 +121,7 @@ class QgsImageOperation
|
||||
* @param image QImage to blur
|
||||
* @param radius blur radius in pixels
|
||||
* @returns blurred image
|
||||
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied
|
||||
*/
|
||||
static QImage* gaussianBlur( QImage &image, const int radius ) /Factory/;
|
||||
|
||||
|
@ -533,20 +533,38 @@ void QgsImageOperation::stackBlur( QImage &image, const int radius, const bool a
|
||||
int i1 = 0;
|
||||
int i2 = 3;
|
||||
|
||||
if ( alphaOnly ) // this seems to only work right for a black color
|
||||
//ensure correct source format.
|
||||
QImage::Format originalFormat = image.format();
|
||||
QImage* pImage = ℑ
|
||||
if ( !alphaOnly && originalFormat != QImage::Format_ARGB32_Premultiplied )
|
||||
{
|
||||
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
|
||||
}
|
||||
else if ( alphaOnly && originalFormat != QImage::Format_ARGB32 )
|
||||
{
|
||||
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32 ) );
|
||||
}
|
||||
|
||||
if ( alphaOnly )
|
||||
i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
|
||||
|
||||
StackBlurLineOperation topToBottomBlur( alpha, QgsImageOperation::ByColumn, true, i1, i2 );
|
||||
runLineOperation( image, topToBottomBlur );
|
||||
runLineOperation( *pImage, topToBottomBlur );
|
||||
|
||||
StackBlurLineOperation leftToRightBlur( alpha, QgsImageOperation::ByRow, true, i1, i2 );
|
||||
runLineOperation( image, leftToRightBlur );
|
||||
runLineOperation( *pImage, leftToRightBlur );
|
||||
|
||||
StackBlurLineOperation bottomToTopBlur( alpha, QgsImageOperation::ByColumn, false, i1, i2 );
|
||||
runLineOperation( image, bottomToTopBlur );
|
||||
runLineOperation( *pImage, bottomToTopBlur );
|
||||
|
||||
StackBlurLineOperation rightToLeftBlur( alpha, QgsImageOperation::ByRow, false, i1, i2 );
|
||||
runLineOperation( image, rightToLeftBlur );
|
||||
runLineOperation( *pImage, rightToLeftBlur );
|
||||
|
||||
if ( pImage->format() != originalFormat )
|
||||
{
|
||||
image = pImage->convertToFormat( originalFormat );
|
||||
delete pImage;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsImageOperation::StackBlurLineOperation::operator()( QRgb* startRef, const int lineLength, const int bytesPerLine )
|
||||
@ -591,17 +609,34 @@ QImage *QgsImageOperation::gaussianBlur( QImage &image, const int radius )
|
||||
|
||||
double* kernel = createGaussianKernel( radius );
|
||||
|
||||
//ensure correct source format.
|
||||
QImage::Format originalFormat = image.format();
|
||||
QImage* pImage = ℑ
|
||||
if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
|
||||
{
|
||||
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
|
||||
}
|
||||
|
||||
//blur along rows
|
||||
QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32 );
|
||||
QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
|
||||
GaussianBlurOperation rowBlur( radius, QgsImageOperation::ByRow, &xBlurImage, kernel );
|
||||
runRectOperation( image, rowBlur );
|
||||
runRectOperation( *pImage, rowBlur );
|
||||
|
||||
//blur along columns
|
||||
QImage* yBlurImage = new QImage( width, height, QImage::Format_ARGB32 );
|
||||
QImage* yBlurImage = new QImage( width, height, QImage::Format_ARGB32_Premultiplied );
|
||||
GaussianBlurOperation colBlur( radius, QgsImageOperation::ByColumn, yBlurImage, kernel );
|
||||
runRectOperation( xBlurImage, colBlur );
|
||||
|
||||
delete[] kernel;
|
||||
|
||||
if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
|
||||
{
|
||||
QImage* convertedImage = new QImage( yBlurImage->convertToFormat( originalFormat ) );
|
||||
delete yBlurImage;
|
||||
delete pImage;
|
||||
return convertedImage;
|
||||
}
|
||||
|
||||
return yBlurImage;
|
||||
}
|
||||
|
||||
|
@ -36,10 +36,6 @@ class QgsVectorColorRampV2;
|
||||
* Operations are written to either modify an image in place or return a new image, depending
|
||||
* on which is faster for the particular operation.
|
||||
*
|
||||
* \note These operations do not work using premultiplied ARGB32_Premultiplied images
|
||||
* - please make sure the images are converted to standard ARGB32 images prior to calling
|
||||
* these operations.
|
||||
*
|
||||
* \note Added in version 2.7
|
||||
*/
|
||||
class CORE_EXPORT QgsImageOperation
|
||||
@ -145,6 +141,8 @@ class CORE_EXPORT QgsImageOperation
|
||||
* @param image QImage to blur
|
||||
* @param radius blur radius in pixels, maximum value of 16
|
||||
* @param alphaOnly set to true to blur only the alpha component of the image
|
||||
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied if
|
||||
* alphaOnly is set to false, or ARGB32 if alphaOnly is true
|
||||
*/
|
||||
static void stackBlur( QImage &image, const int radius, const bool alphaOnly = false );
|
||||
|
||||
@ -153,6 +151,7 @@ class CORE_EXPORT QgsImageOperation
|
||||
* @param image QImage to blur
|
||||
* @param radius blur radius in pixels
|
||||
* @returns blurred image
|
||||
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied
|
||||
*/
|
||||
static QImage* gaussianBlur( QImage &image, const int radius );
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <QObject>
|
||||
#include <QtTest/QtTest>
|
||||
#include "qgsrenderchecker.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
|
||||
class TestQgsImageOperation : public QObject
|
||||
{
|
||||
@ -66,6 +67,7 @@ class TestQgsImageOperation : public QObject
|
||||
|
||||
//stack blur
|
||||
void stackBlur();
|
||||
void stackBlurPremultiplied();
|
||||
void alphaOnlyBlur();
|
||||
|
||||
//gaussian blur
|
||||
@ -327,6 +329,18 @@ void TestQgsImageOperation::stackBlur()
|
||||
|
||||
bool result = imageCheck( QString( "imageop_stackblur" ), image, 0 );
|
||||
QVERIFY( result );
|
||||
QCOMPARE( image.format(), QImage::Format_ARGB32 );
|
||||
}
|
||||
|
||||
void TestQgsImageOperation::stackBlurPremultiplied()
|
||||
{
|
||||
QImage image( mSampleImage );
|
||||
image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
|
||||
QgsImageOperation::stackBlur( image, 10 );
|
||||
|
||||
bool result = imageCheck( QString( "imageop_stackblur" ), image, 0 );
|
||||
QVERIFY( result );
|
||||
QCOMPARE( image.format(), QImage::Format_ARGB32_Premultiplied );
|
||||
}
|
||||
|
||||
void TestQgsImageOperation::alphaOnlyBlur()
|
||||
@ -336,6 +350,15 @@ void TestQgsImageOperation::alphaOnlyBlur()
|
||||
|
||||
bool result = imageCheck( QString( "imageop_stackblur_alphaonly" ), image, 0 );
|
||||
QVERIFY( result );
|
||||
QCOMPARE( image.format(), QImage::Format_ARGB32 );
|
||||
|
||||
QImage premultImage( QString( TEST_DATA_DIR ) + QDir::separator() + "small_sample_image.png" );
|
||||
premultImage = premultImage.convertToFormat( QImage::Format_ARGB32_Premultiplied );
|
||||
QgsImageOperation::stackBlur( premultImage, 10, true );
|
||||
|
||||
result = imageCheck( QString( "imageop_stackblur_alphaonly" ), premultImage, 0 );
|
||||
QVERIFY( result );
|
||||
QCOMPARE( premultImage.format(), QImage::Format_ARGB32_Premultiplied );
|
||||
}
|
||||
|
||||
void TestQgsImageOperation::gaussianBlur()
|
||||
@ -344,6 +367,7 @@ void TestQgsImageOperation::gaussianBlur()
|
||||
QImage* blurredImage = QgsImageOperation::gaussianBlur( image, 30 );
|
||||
|
||||
bool result = imageCheck( QString( "imageop_gaussianblur" ), *blurredImage, 0 );
|
||||
QCOMPARE( blurredImage->format(), QImage::Format_ARGB32 );
|
||||
delete blurredImage;
|
||||
QVERIFY( result );
|
||||
}
|
||||
@ -352,8 +376,11 @@ void TestQgsImageOperation::gaussianBlur()
|
||||
void TestQgsImageOperation::gaussianBlurSmall()
|
||||
{
|
||||
QImage image( QString( TEST_DATA_DIR ) + QDir::separator() + "small_sample_image.png" );
|
||||
image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
|
||||
|
||||
QImage* blurredImage = QgsImageOperation::gaussianBlur( image, 10 );
|
||||
|
||||
QCOMPARE( blurredImage->format(), QImage::Format_ARGB32_Premultiplied );
|
||||
bool result = imageCheck( QString( "imageop_gaussianblur_small" ), *blurredImage, 0 );
|
||||
delete blurredImage;
|
||||
QVERIFY( result );
|
||||
@ -397,7 +424,7 @@ bool TestQgsImageOperation::imageCheck( QString testName, QImage &image, int mis
|
||||
QgsRenderChecker checker;
|
||||
checker.setControlName( "expected_" + testName );
|
||||
checker.setRenderedImage( fileName );
|
||||
checker.setColorTolerance( 1 );
|
||||
checker.setColorTolerance( 2 );
|
||||
bool resultFlag = checker.compareImages( testName, mismatchCount );
|
||||
mReport += checker.report();
|
||||
return resultFlag;
|
||||
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 161 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 136 KiB |
BIN
tests/testdata/control_images/expected_painteffect_blur/painteffect_blur.png
vendored
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
tests/testdata/control_images/expected_painteffect_dropshadow/expected_painteffect_dropshadow.png
vendored
Normal file
After Width: | Height: | Size: 8.2 KiB |