Skip to content

Commit

Permalink
Fix calculation of blur ops with non ARGB32_Premultiplied images
Browse files Browse the repository at this point in the history
  • 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.
7 changes: 3 additions & 4 deletions python/core/effects/qgsimageoperation.sip
Expand Up @@ -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
Expand Down Expand Up @@ -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 );

Expand All @@ -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/;

Expand Down
51 changes: 43 additions & 8 deletions src/core/effects/qgsimageoperation.cpp
Expand Up @@ -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 )
Expand Down Expand Up @@ -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;
}

Expand Down
7 changes: 3 additions & 4 deletions src/core/effects/qgsimageoperation.h
Expand Up @@ -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
Expand Down Expand Up @@ -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 );

Expand All @@ -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 );

Expand Down
29 changes: 28 additions & 1 deletion tests/src/core/testqgsimageoperation.cpp
Expand Up @@ -20,6 +20,7 @@
#include <QObject>
#include <QtTest/QtTest>
#include "qgsrenderchecker.h"
#include "qgssymbollayerv2utils.h"

class TestQgsImageOperation : public QObject
{
Expand Down Expand Up @@ -66,6 +67,7 @@ class TestQgsImageOperation : public QObject

//stack blur
void stackBlur();
void stackBlurPremultiplied();
void alphaOnlyBlur();

//gaussian blur
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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 );
}
Expand All @@ -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 );
Expand Down Expand Up @@ -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;
Expand Down
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.