Skip to content

Commit f7f89b3

Browse files
committedJan 26, 2015
Fix calculation of blur ops with non ARGB32_Premultiplied images
1 parent 2e8df94 commit f7f89b3

File tree

9 files changed

+77
-17
lines changed

9 files changed

+77
-17
lines changed
 

‎python/core/effects/qgsimageoperation.sip

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
* Operations are written to either modify an image in place or return a new image, depending
1111
* on which is faster for the particular operation.
1212
*
13-
* \note These operations do not work using premultiplied ARGB32_Premultiplied images
14-
* - please make sure the images are converted to standard ARGB32 images prior to calling
15-
* these operations.
16-
*
1713
* \note Added in version 2.7
1814
*/
1915
class QgsImageOperation
@@ -115,6 +111,8 @@ class QgsImageOperation
115111
* @param image QImage to blur
116112
* @param radius blur radius in pixels, maximum value of 16
117113
* @param alphaOnly set to true to blur only the alpha component of the image
114+
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied if
115+
* alphaOnly is set to false, or ARGB32 if alphaOnly is true
118116
*/
119117
static void stackBlur( QImage &image, const int radius, const bool alphaOnly = false );
120118

@@ -123,6 +121,7 @@ class QgsImageOperation
123121
* @param image QImage to blur
124122
* @param radius blur radius in pixels
125123
* @returns blurred image
124+
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied
126125
*/
127126
static QImage* gaussianBlur( QImage &image, const int radius ) /Factory/;
128127

‎src/core/effects/qgsimageoperation.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -533,20 +533,38 @@ void QgsImageOperation::stackBlur( QImage &image, const int radius, const bool a
533533
int i1 = 0;
534534
int i2 = 3;
535535

536-
if ( alphaOnly ) // this seems to only work right for a black color
536+
//ensure correct source format.
537+
QImage::Format originalFormat = image.format();
538+
QImage* pImage = ℑ
539+
if ( !alphaOnly && originalFormat != QImage::Format_ARGB32_Premultiplied )
540+
{
541+
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
542+
}
543+
else if ( alphaOnly && originalFormat != QImage::Format_ARGB32 )
544+
{
545+
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32 ) );
546+
}
547+
548+
if ( alphaOnly )
537549
i1 = i2 = ( QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3 );
538550

539551
StackBlurLineOperation topToBottomBlur( alpha, QgsImageOperation::ByColumn, true, i1, i2 );
540-
runLineOperation( image, topToBottomBlur );
552+
runLineOperation( *pImage, topToBottomBlur );
541553

542554
StackBlurLineOperation leftToRightBlur( alpha, QgsImageOperation::ByRow, true, i1, i2 );
543-
runLineOperation( image, leftToRightBlur );
555+
runLineOperation( *pImage, leftToRightBlur );
544556

545557
StackBlurLineOperation bottomToTopBlur( alpha, QgsImageOperation::ByColumn, false, i1, i2 );
546-
runLineOperation( image, bottomToTopBlur );
558+
runLineOperation( *pImage, bottomToTopBlur );
547559

548560
StackBlurLineOperation rightToLeftBlur( alpha, QgsImageOperation::ByRow, false, i1, i2 );
549-
runLineOperation( image, rightToLeftBlur );
561+
runLineOperation( *pImage, rightToLeftBlur );
562+
563+
if ( pImage->format() != originalFormat )
564+
{
565+
image = pImage->convertToFormat( originalFormat );
566+
delete pImage;
567+
}
550568
}
551569

552570
void QgsImageOperation::StackBlurLineOperation::operator()( QRgb* startRef, const int lineLength, const int bytesPerLine )
@@ -591,17 +609,34 @@ QImage *QgsImageOperation::gaussianBlur( QImage &image, const int radius )
591609

592610
double* kernel = createGaussianKernel( radius );
593611

612+
//ensure correct source format.
613+
QImage::Format originalFormat = image.format();
614+
QImage* pImage = ℑ
615+
if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
616+
{
617+
pImage = new QImage( image.convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
618+
}
619+
594620
//blur along rows
595-
QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32 );
621+
QImage xBlurImage = QImage( width, height, QImage::Format_ARGB32_Premultiplied );
596622
GaussianBlurOperation rowBlur( radius, QgsImageOperation::ByRow, &xBlurImage, kernel );
597-
runRectOperation( image, rowBlur );
623+
runRectOperation( *pImage, rowBlur );
598624

599625
//blur along columns
600-
QImage* yBlurImage = new QImage( width, height, QImage::Format_ARGB32 );
626+
QImage* yBlurImage = new QImage( width, height, QImage::Format_ARGB32_Premultiplied );
601627
GaussianBlurOperation colBlur( radius, QgsImageOperation::ByColumn, yBlurImage, kernel );
602628
runRectOperation( xBlurImage, colBlur );
603629

604630
delete[] kernel;
631+
632+
if ( originalFormat != QImage::Format_ARGB32_Premultiplied )
633+
{
634+
QImage* convertedImage = new QImage( yBlurImage->convertToFormat( originalFormat ) );
635+
delete yBlurImage;
636+
delete pImage;
637+
return convertedImage;
638+
}
639+
605640
return yBlurImage;
606641
}
607642

‎src/core/effects/qgsimageoperation.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ class QgsVectorColorRampV2;
3636
* Operations are written to either modify an image in place or return a new image, depending
3737
* on which is faster for the particular operation.
3838
*
39-
* \note These operations do not work using premultiplied ARGB32_Premultiplied images
40-
* - please make sure the images are converted to standard ARGB32 images prior to calling
41-
* these operations.
42-
*
4339
* \note Added in version 2.7
4440
*/
4541
class CORE_EXPORT QgsImageOperation
@@ -145,6 +141,8 @@ class CORE_EXPORT QgsImageOperation
145141
* @param image QImage to blur
146142
* @param radius blur radius in pixels, maximum value of 16
147143
* @param alphaOnly set to true to blur only the alpha component of the image
144+
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied if
145+
* alphaOnly is set to false, or ARGB32 if alphaOnly is true
148146
*/
149147
static void stackBlur( QImage &image, const int radius, const bool alphaOnly = false );
150148

@@ -153,6 +151,7 @@ class CORE_EXPORT QgsImageOperation
153151
* @param image QImage to blur
154152
* @param radius blur radius in pixels
155153
* @returns blurred image
154+
* @note for fastest operation, ensure the source image is ARGB32_Premultiplied
156155
*/
157156
static QImage* gaussianBlur( QImage &image, const int radius );
158157

‎tests/src/core/testqgsimageoperation.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <QObject>
2121
#include <QtTest/QtTest>
2222
#include "qgsrenderchecker.h"
23+
#include "qgssymbollayerv2utils.h"
2324

2425
class TestQgsImageOperation : public QObject
2526
{
@@ -66,6 +67,7 @@ class TestQgsImageOperation : public QObject
6667

6768
//stack blur
6869
void stackBlur();
70+
void stackBlurPremultiplied();
6971
void alphaOnlyBlur();
7072

7173
//gaussian blur
@@ -327,6 +329,18 @@ void TestQgsImageOperation::stackBlur()
327329

328330
bool result = imageCheck( QString( "imageop_stackblur" ), image, 0 );
329331
QVERIFY( result );
332+
QCOMPARE( image.format(), QImage::Format_ARGB32 );
333+
}
334+
335+
void TestQgsImageOperation::stackBlurPremultiplied()
336+
{
337+
QImage image( mSampleImage );
338+
image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
339+
QgsImageOperation::stackBlur( image, 10 );
340+
341+
bool result = imageCheck( QString( "imageop_stackblur" ), image, 0 );
342+
QVERIFY( result );
343+
QCOMPARE( image.format(), QImage::Format_ARGB32_Premultiplied );
330344
}
331345

332346
void TestQgsImageOperation::alphaOnlyBlur()
@@ -336,6 +350,15 @@ void TestQgsImageOperation::alphaOnlyBlur()
336350

337351
bool result = imageCheck( QString( "imageop_stackblur_alphaonly" ), image, 0 );
338352
QVERIFY( result );
353+
QCOMPARE( image.format(), QImage::Format_ARGB32 );
354+
355+
QImage premultImage( QString( TEST_DATA_DIR ) + QDir::separator() + "small_sample_image.png" );
356+
premultImage = premultImage.convertToFormat( QImage::Format_ARGB32_Premultiplied );
357+
QgsImageOperation::stackBlur( premultImage, 10, true );
358+
359+
result = imageCheck( QString( "imageop_stackblur_alphaonly" ), premultImage, 0 );
360+
QVERIFY( result );
361+
QCOMPARE( premultImage.format(), QImage::Format_ARGB32_Premultiplied );
339362
}
340363

341364
void TestQgsImageOperation::gaussianBlur()
@@ -344,6 +367,7 @@ void TestQgsImageOperation::gaussianBlur()
344367
QImage* blurredImage = QgsImageOperation::gaussianBlur( image, 30 );
345368

346369
bool result = imageCheck( QString( "imageop_gaussianblur" ), *blurredImage, 0 );
370+
QCOMPARE( blurredImage->format(), QImage::Format_ARGB32 );
347371
delete blurredImage;
348372
QVERIFY( result );
349373
}
@@ -352,8 +376,11 @@ void TestQgsImageOperation::gaussianBlur()
352376
void TestQgsImageOperation::gaussianBlurSmall()
353377
{
354378
QImage image( QString( TEST_DATA_DIR ) + QDir::separator() + "small_sample_image.png" );
379+
image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied );
380+
355381
QImage* blurredImage = QgsImageOperation::gaussianBlur( image, 10 );
356382

383+
QCOMPARE( blurredImage->format(), QImage::Format_ARGB32_Premultiplied );
357384
bool result = imageCheck( QString( "imageop_gaussianblur_small" ), *blurredImage, 0 );
358385
delete blurredImage;
359386
QVERIFY( result );
@@ -397,7 +424,7 @@ bool TestQgsImageOperation::imageCheck( QString testName, QImage &image, int mis
397424
QgsRenderChecker checker;
398425
checker.setControlName( "expected_" + testName );
399426
checker.setRenderedImage( fileName );
400-
checker.setColorTolerance( 1 );
427+
checker.setColorTolerance( 2 );
401428
bool resultFlag = checker.compareImages( testName, mismatchCount );
402429
mReport += checker.report();
403430
return resultFlag;
Loading
Loading
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.