diff --git a/UIImage+BlurredFrame.h b/UIImage+BlurredFrame.h index 3ed6c60..b8ed80f 100644 --- a/UIImage+BlurredFrame.h +++ b/UIImage+BlurredFrame.h @@ -20,4 +20,10 @@ saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage atFrame:(CGRect)frame; +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius + iterationsCount:(NSInteger)iterationsCount + tintColor:(UIColor *)tintColor + saturationDeltaFactor:(CGFloat)saturationDeltaFactor + maskImage:(UIImage *)maskImage + atFrame:(CGRect)frame; @end diff --git a/UIImage+BlurredFrame.m b/UIImage+BlurredFrame.m index d91b95c..a3c7502 100644 --- a/UIImage+BlurredFrame.m +++ b/UIImage+BlurredFrame.m @@ -75,7 +75,17 @@ - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius maskImage:(UIImage *)maskImage atFrame:(CGRect)frame { - UIImage *blurredFrame = [[self croppedImageAtFrame:frame] applyBlurWithRadius:blurRadius tintColor:tintColor saturationDeltaFactor:saturationDeltaFactor maskImage:maskImage]; + return [self applyBlurWithRadius:blurRadius iterationsCount:3 tintColor:tintColor saturationDeltaFactor:saturationDeltaFactor maskImage:maskImage atFrame:frame]; +} + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius + iterationsCount:(NSInteger)iterationsCount + tintColor:(UIColor *)tintColor + saturationDeltaFactor:(CGFloat)saturationDeltaFactor + maskImage:(UIImage *)maskImage + atFrame:(CGRect)frame +{ + UIImage *blurredFrame = [[self croppedImageAtFrame:frame] applyBlurWithRadius:blurRadius iterationsCount:iterationsCount tintColor:tintColor saturationDeltaFactor:saturationDeltaFactor maskImage:maskImage]; return [self addImageToImage:blurredFrame atRect:frame]; } diff --git a/UIImage+ImageEffects.h b/UIImage+ImageEffects.h index d7f151b..33d5e25 100644 --- a/UIImage+ImageEffects.h +++ b/UIImage+ImageEffects.h @@ -105,4 +105,6 @@ - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius iterationsCount:(NSInteger)iterationsCount tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; + @end diff --git a/UIImage+ImageEffects.m b/UIImage+ImageEffects.m index 8109c76..c93c6a9 100644 --- a/UIImage+ImageEffects.m +++ b/UIImage+ImageEffects.m @@ -140,6 +140,11 @@ - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor } - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage +{ + return [self applyBlurWithRadius:blurRadius iterationsCount:3 tintColor:tintColor saturationDeltaFactor:saturationDeltaFactor maskImage:maskImage]; +} + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius iterationsCount:(NSInteger)iterationsCount tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage { // check pre-conditions if (self.size.width < 1 || self.size.height < 1) { @@ -181,6 +186,7 @@ - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintCo effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); + BOOL resultImageAtInputBuffer = YES; if (hasBlur) { // A description of how to compute the box kernel width from the Gaussian // radius (aka standard deviation) appears in the SVG spec: @@ -199,11 +205,15 @@ - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintCo if (radius % 2 != 1) { radius += 1; // force radius to be odd so that the three box-blur methodology works. } - vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); - vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); - vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + for (int i = 0; i+1 < iterationsCount; i+=2) { + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + } + if (iterationsCount % 2) { + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (uint32_t)radius, (uint32_t)radius, 0, kvImageEdgeExtend); + resultImageAtInputBuffer = NO; + } } - BOOL effectImageBuffersAreSwapped = NO; if (hasSaturationChange) { CGFloat s = saturationDeltaFactor; CGFloat floatingPointSaturationMatrix[] = { @@ -218,19 +228,18 @@ - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintCo for (NSUInteger i = 0; i < matrixSize; ++i) { saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); } - if (hasBlur) { + if (hasBlur ^ resultImageAtInputBuffer) { vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); - effectImageBuffersAreSwapped = YES; } else { vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); } } - if (!effectImageBuffersAreSwapped) + if (!resultImageAtInputBuffer) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - if (effectImageBuffersAreSwapped) + if (resultImageAtInputBuffer) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); }