Fix the blur effect logic by avoid color convert and always use three box-blur methodology

This commit is contained in:
DreamPiggy 2023-03-03 18:54:08 +08:00
parent 8d09564f27
commit e0b7cc5241
1 changed files with 11 additions and 20 deletions

View File

@ -701,15 +701,8 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
#endif
CGImageRef imageRef = self.CGImage;
//convert to BGRA if it isn't
if (CGImageGetBitsPerPixel(imageRef) != 32 ||
CGImageGetBitsPerComponent(imageRef) != 8 ||
!((CGImageGetBitmapInfo(imageRef) & kCGBitmapAlphaInfoMask))) {
SDGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
imageRef = SDGraphicsGetImageFromCurrentImageContext().CGImage;
SDGraphicsEndImageContext();
if (!imageRef) {
return nil;
}
vImage_Buffer effect = {}, scratch = {};
@ -726,7 +719,7 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
};
vImage_Error err;
err = vImageBuffer_InitWithCGImage(&effect, &format, NULL, imageRef, kvImageNoFlags);
err = vImageBuffer_InitWithCGImage(&effect, &format, NULL, imageRef, kvImageNoFlags); // vImage will convert to format we requests, no need `vImageConvert`
if (err != kvImageNoError) {
NSLog(@"UIImage+Transform error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", err, self);
return nil;
@ -740,6 +733,7 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
input = &effect;
output = &scratch;
// See: https://developer.apple.com/library/archive/samplecode/UIImageEffects/Introduction/Intro.html
if (hasBlur) {
// A description of how to compute the box kernel width from the Gaussian
// radius (aka standard deviation) appears in the SVG spec:
@ -756,19 +750,16 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
if (inputRadius - 2.0 < __FLT_EPSILON__) inputRadius = 2.0;
uint32_t radius = floor(inputRadius * 3.0 * sqrt(2 * M_PI) / 4 + 0.5);
radius |= 1; // force radius to be odd so that the three box-blur methodology works.
int iterations;
if (blurRadius * scale < 0.5) iterations = 1;
else if (blurRadius * scale < 1.5) iterations = 2;
else iterations = 3;
NSInteger tempSize = vImageBoxConvolve_ARGB8888(input, output, NULL, 0, 0, radius, radius, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend);
void *temp = malloc(tempSize);
for (int i = 0; i < iterations; i++) {
vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
vImage_Buffer *tmp = input;
input = output;
output = tmp;
}
vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
vImageBoxConvolve_ARGB8888(output, input, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
vImageBoxConvolve_ARGB8888(input, output, temp, 0, 0, radius, radius, NULL, kvImageEdgeExtend);
free(temp);
vImage_Buffer *tmp = input;
input = output;
output = tmp;
}
CGImageRef effectCGImage = NULL;