Skip to content
Permalink
Browse files
Fix calculation of blur ops with non ARGB32_Premultiplied images
  • Loading branch information
nyalldawson committed Jan 26, 2015
1 parent 2e8df94 commit f7f89b37b9e4dfa84ab8d24ab4a793583bedd855
@@ -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;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit f7f89b3

Please sign in to comment.