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 f7f89b3
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 17 deletions.
@@ -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;
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f7f89b3

Please sign in to comment.