sourcetip

어떻게 하면 iOS 7 블러 뷰와 비슷한 효과를 낼 수 있습니까?

fileupload 2023. 5. 3. 21:40
반응형

어떻게 하면 iOS 7 블러 뷰와 비슷한 효과를 낼 수 있습니까?

애플이 공개한 iOS 7 예제 화면에서 이 흐릿한 배경을 복제하려고 합니다.

iOS 7 Control Center 스크린샷

이 질문에서는 아래 내용에 CI 필터를 적용할 것을 제안하지만, 이는 완전히 다른 접근 방식입니다.iOS 7은 다음과 같은 여러 가지 이유로 아래 보기의 내용을 캡처하지 않습니다.

  1. 대략적인 테스트를 통해 아래 뷰의 스크린샷을 캡처하고 iOS 7의 블러 스타일을 모방할 수 있을 정도로 충분히 큰 반경의 CIGaussianBlur 필터를 적용하는 것은 시뮬레이터에서도 1-2초가 걸립니다.
  2. iOS 7 블러 뷰는 동영상이나 애니메이션과 같은 동적 뷰를 눈에 띄는 지연 없이 흐릴 수 있습니다.

이 효과를 내기 위해 어떤 프레임워크를 사용할 수 있는지, 그리고 현재 공개 API와 유사한 효과를 낼 수 있는지에 대해 가설을 세울 수 있는 사람이 있습니까?

편집: (댓글에서) 우리는 애플이 어떻게 하고 있는지 정확히 알지 못하지만, 우리가 할 수 있는 기본적인 가정이 있습니까?우리는 그들이 하드웨어를 사용하고 있다고 가정할 수 있습니다, 그렇죠?

효과는 각 관점에 포함되어 있어서 효과가 실제로 그 이면에 무엇이 있는지 알 수 없는 것입니까?아니면 블러의 작동 방식에 따라 블러 뒤에 있는 내용을 고려해야 합니까?

효과의 이면에 있는 내용들이 관련이 있다면, 애플이 아래 내용들에 대한 "피드"를 받고 그것들을 계속 흐리게 렌더링하고 있다고 가정할 수 있습니까?

왜 효과를 복제하려고 합니까?보기 뒤에 UI 도구 모음을 그리기만 하면 됩니다.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];

Apple은 WWDC에서 이 기능을 포함하는 UIImage의 범주로 코드를 릴리스했습니다. 개발자 계정이 있는 경우 https://developer.apple.com/wwdc/schedule/ 링크로 이동하여 섹션 226을 검색하고 세부 정보를 클릭하여 UIImage 범주(및 나머지 샘플 코드)를 가져올 수 있습니다.나는 아직 그것을 가지고 놀지 않았지만 iOS 6에서 효과가 훨씬 더 느릴 것이라고 생각합니다, iOS 7에는 블러에 대한 입력으로 사용되는 초기 스크린샷을 훨씬 더 빨리 잡을 수 있도록 하는 몇 가지 향상된 기능이 있습니다.

직접 링크: https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip

사실 저는 이것이 달성하기에 다소 간단할 것이라고 장담합니다.그것은 아마도 애플이 진행하고 있는 것처럼 작동하지 않거나 정확하게 보이지만 매우 가까울 수 있습니다.

우선 발표할 UIView의 CGRect를 결정해야 합니다.UI 부분의 이미지를 캡처하여 흐리게 하면 됩니다.이런 거...

- (UIImage*)getBlurredImage {
    // You will want to calculate this in code based on the view you will be presenting.
    CGSize size = CGSizeMake(200,200);

    UIGraphicsBeginImageContext(size);
    [view drawViewHierarchyInRect:(CGRect){CGPointZero, w, h} afterScreenUpdates:YES]; // view is the view you are grabbing the screen shot of. The view that is to be blurred.
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Gaussian Blur
    image = [image applyLightEffect];

    // Box Blur
    // image = [image boxblurImageWithBlur:0.2f];

    return image;
}

가우스 블러 - 권장

UIImage+ImageEffects카테고리 애플은 여기에 제공되며, iOS 7의 블러와 매우 유사한 가우스 블러를 얻을 수 있습니다.

상자 블러

여러분은 의 음을사여블사있수습다니도용할을 사용하여 .boxBlurImageWithBlur:UI 이미지 범주입니다.이는 여기서 찾을 수 있는 알고리즘을 기반으로 합니다.

@implementation UIImage (Blur)

-(UIImage *)boxblurImageWithBlur:(CGFloat)blur {
    if (blur < 0.f || blur > 1.f) {
        blur = 0.5f;
    }
    int boxSize = (int)(blur * 50);
    boxSize = boxSize - (boxSize % 2) + 1;

    CGImageRef img = self.CGImage;

    vImage_Buffer inBuffer, outBuffer;

    vImage_Error error;

    void *pixelBuffer;

    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);

    inBuffer.width = CGImageGetWidth(img);
    inBuffer.height = CGImageGetHeight(img);
    inBuffer.rowBytes = CGImageGetBytesPerRow(img);

    inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);

    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));

    if(pixelBuffer == NULL)
        NSLog(@"No pixelbuffer");

    outBuffer.data = pixelBuffer;
    outBuffer.width = CGImageGetWidth(img);
    outBuffer.height = CGImageGetHeight(img);
    outBuffer.rowBytes = CGImageGetBytesPerRow(img);

    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);

    if (error) {
        NSLog(@"JFDepthView: error from convolution %ld", error);
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
                                         outBuffer.width,
                                         outBuffer.height,
                                         8,
                                         outBuffer.rowBytes,
                                         colorSpace,
                                         kCGImageAlphaNoneSkipLast);
    CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];

    //clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);

    free(pixelBuffer);
    CFRelease(inBitmapData);

    CGImageRelease(imageRef);

    return returnImage;
}

@end

이제 화면 영역을 흐리게 계산하여 흐리게 범주에 전달하고 흐리게 표시된 UI 이미지를 다시 수신하면 표시할 보기의 배경으로 해당 흐리게 표시된 이미지를 설정할 수 있습니다.제가 말씀드린 것처럼, 이것은 애플이 하고 있는 것과 완벽하게 일치하지는 않겠지만, 여전히 꽤 멋져 보일 것입니다.

도움이 되길 바랍니다.

iOS8은 이러한 질문에 답했습니다.

UIV 시각 효과

- (instancetype)initWithEffect:(UIVisualEffect *)effect

또는 Swift:

init(effect effect: UIVisualEffect)

저는 사용자 정의 보기에서 네이티브 iOS 7 블러를 생성할 수 있는 기능이 있는 UIV View의 작은 하위 클래스를 방금 작성했습니다.UIT 도구 모음을 사용하지만 실시간 애니메이션을 통해 프레임, 경계, 색상 및 알파를 안전하게 변경할 수 있습니다.

문제가 발견되면 알려주시기 바랍니다.

https://github.com/ivoleko/ILTranslucentView

IL 반투명 보기 예제

애플 엔지니어들이 이 성능을 내기 위해 GPU 버퍼에서 직접 읽고 있다고 주장했다는 소문이 있는데, 이는 보안 문제를 제기하는 이유입니다.

이것은 WWDC의 비디오에서 볼 수 있는 해결책입니다.가우스 블러(Gaussian Blur)를 사용해야 하므로, 먼저 제가 여기에 쓰고 있는 코드로 새로운 .m과 .h 파일을 추가하고, 원하는 효과를 사용하여 스크린샷을 하고, 원하는 효과를 사용하여 뷰에 추가한 다음, UITable UIView 또는 투명해야 하는 것을 사용하여 원하는 효과를 보관하고, 플레이할 수 있습니다.이 통화는 모든 UI 이미지에서 작동합니다.

마지막에 흐릿한 이미지가 배경이 되고 위의 나머지 컨트롤은 투명해야 합니다.

이 작업을 수행하려면 다음 라이브러리를 추가해야 합니다.

가속기, 프레임 워크,UIKit.framework, CoreGraphics.framework

마음에 드셨으면 좋겠습니다.

해피 코딩.

    //Screen capture.
    UIGraphicsBeginImageContext(self.view.bounds.size);

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(c, 0, 0);
    [self.view.layer renderInContext:c];

    UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
    viewImage = [viewImage applyLightEffect];

    UIGraphicsEndImageContext();

    //.h FILE
    #import <UIKit/UIKit.h>

    @interface UIImage (ImageEffects)

   - (UIImage *)applyLightEffect;
   - (UIImage *)applyExtraLightEffect;
   - (UIImage *)applyDarkEffect;
   - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;

   - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;

   @end

    //.m FILE
    #import "cGaussianEffect.h"
    #import <Accelerate/Accelerate.h>
    #import <float.h>


     @implementation UIImage (ImageEffects)


    - (UIImage *)applyLightEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyExtraLightEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyDarkEffect
    {
        UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
        return [self applyBlurWithRadius:1 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
    }


    - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
    {
        const CGFloat EffectColorAlpha = 0.6;
        UIColor *effectColor = tintColor;
        int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
        if (componentCount == 2) {
            CGFloat b;
            if ([tintColor getWhite:&b alpha:NULL]) {
                effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
            }
        }
        else {
            CGFloat r, g, b;
            if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
                effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
            }
        }
        return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
    }


    - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
    {
        if (self.size.width < 1 || self.size.height < 1) {
            NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
            return nil;
        }
        if (!self.CGImage) {
            NSLog (@"*** error: image must be backed by a CGImage: %@", self);
            return nil;
        }
        if (maskImage && !maskImage.CGImage) {
            NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
            return nil;
        }

        CGRect imageRect = { CGPointZero, self.size };
        UIImage *effectImage = self;

        BOOL hasBlur = blurRadius > __FLT_EPSILON__;
        BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
        if (hasBlur || hasSaturationChange) {
            UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
            CGContextRef effectInContext = UIGraphicsGetCurrentContext();
            CGContextScaleCTM(effectInContext, 1.0, -1.0);
            CGContextTranslateCTM(effectInContext, 0, -self.size.height);
            CGContextDrawImage(effectInContext, imageRect, self.CGImage);

            vImage_Buffer effectInBuffer;
            effectInBuffer.data     = CGBitmapContextGetData(effectInContext);
            effectInBuffer.width    = CGBitmapContextGetWidth(effectInContext);
            effectInBuffer.height   = CGBitmapContextGetHeight(effectInContext);
            effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);

            UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
            CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
            vImage_Buffer effectOutBuffer;
            effectOutBuffer.data     = CGBitmapContextGetData(effectOutContext);
            effectOutBuffer.width    = CGBitmapContextGetWidth(effectOutContext);
            effectOutBuffer.height   = CGBitmapContextGetHeight(effectOutContext);
            effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);

            if (hasBlur) {
                CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
                NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
                if (radius % 2 != 1) {
                    radius += 1;
                }
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
                vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
            }
            BOOL effectImageBuffersAreSwapped = NO;
            if (hasSaturationChange) {
                CGFloat s = saturationDeltaFactor;
                CGFloat floatingPointSaturationMatrix[] = {
                    0.0722 + 0.9278 * s,  0.0722 - 0.0722 * s,  0.0722 - 0.0722 * s,  0,
                    0.7152 - 0.7152 * s,  0.7152 + 0.2848 * s,  0.7152 - 0.7152 * s,  0,
                    0.2126 - 0.2126 * s,  0.2126 - 0.2126 * s,  0.2126 + 0.7873 * s,  0,
                                  0,                    0,                    0,  1,
                };
                const int32_t divisor = 256;
                NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
                int16_t saturationMatrix[matrixSize];
                for (NSUInteger i = 0; i < matrixSize; ++i) {
                    saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
                }
                if (hasBlur) {
                    vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
                    effectImageBuffersAreSwapped = YES;
                }
                else {
                    vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
                }
            }
            if (!effectImageBuffersAreSwapped)
                effectImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();

            if (effectImageBuffersAreSwapped)
                effectImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
        }

        UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
        CGContextRef outputContext = UIGraphicsGetCurrentContext();
        CGContextScaleCTM(outputContext, 1.0, -1.0);
        CGContextTranslateCTM(outputContext, 0, -self.size.height);

        CGContextDrawImage(outputContext, imageRect, self.CGImage);

        if (hasBlur) {
            CGContextSaveGState(outputContext);
            if (maskImage) {
                CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
            }
            CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
            CGContextRestoreGState(outputContext);
        }

        if (tintColor) {
            CGContextSaveGState(outputContext);
            CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
            CGContextFillRect(outputContext, imageRect);
            CGContextRestoreGState(outputContext);
        }

        UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return outputImage;
    }

WWDC 2013에서 Apple의 DEMO 솔루션을 찾을 수 있습니다. UIImageEffects 샘플 코드를 찾아 다운로드하십시오.

그리고 @제레미 폭스의 코드로.로 변경했습니다.

- (UIImage*)getDarkBlurredImageWithTargetView:(UIView *)targetView
{
    CGSize size = targetView.frame.size;

    UIGraphicsBeginImageContext(size);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(c, 0, 0);
    [targetView.layer renderInContext:c]; // view is the view you are grabbing the screen shot of. The view that is to be blurred.
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return [image applyDarkEffect];
}

이것이 당신에게 도움이 되기를 바랍니다.

다음은 정말 쉬운 방법입니다. https://github.com/JagCesar/iOS-blur

UIT 도구 모음의 계층을 복사하기만 하면 됩니다. 그러면 AMBlurView에서 이 작업을 수행할 수 있습니다.좋아요, 관제 센터만큼 흐릿하진 않지만 충분히 흐릿해요.

iOS7은 NDA 하에 있습니다.

여기에 있는 모든 응답은 vImageBoxConvolve_를 사용합니다.ARGB8888 이 기능은 매우 느립니다. 성능이 높은 우선 순위 요구 사항이 아니라면 괜찮습니다. 하지만 두 View 컨트롤러 간 전환에 이 기능을 사용하는 경우(예: 이 접근 방식은 1초 이상의 횟수를 의미합니다. 이는 애플리케이션의 사용자 환경에 매우 나쁜 영향을 미칩니다.

이 모든 이미지 처리를 GPU에 맡기는 것이 좋다면(그리고 그렇게 해야 합니다) 훨씬 더 나은 효과와 50ms를 반올림하는 놀라운 시간을 얻을 수 있습니다(첫 번째 접근 방식에서 1초의 시간이 있다고 가정하면).

먼저 여기에서 GPUI 이미지 프레임워크(BSD 라이센스)를 다운로드하십시오.

다음으로, GPI 이미지에서 다음 클래스(.m 및 .h)를 추가합니다(이것들이 블러 효과에만 필요한 최소 클래스인지는 잘 모르겠습니다).

  • GPUI이미지.h
  • GPUIimageAlphaBlend 필터
  • GPUI 이미지 필터
  • GPUI 이미지 필터 그룹
  • GPUIimageGaussianBlur 위치 필터
  • GPUIimageGaussian 선택적 블러 필터
  • GPUI 이미지 휘도 범위 필터
  • GPUI 이미지 출력
  • GPUIimage2 입력 필터
  • GL 프로그램
  • GPUIimageBoxBlurFilter
  • GPUIimageGaussianBlurFilter
  • GPUImageiOSBlurFilter
  • GPUI 이미지 포화도 필터
  • GPUI이미지 단색 생성기
  • GPUIimageTwoPass 필터
  • GPUIimageTwoPass텍스처 샘플링 필터

  • iOS/GPUIimage-Prefix.pch

  • iOS/GPUImage
  • iOS/GPUI이미지무비라이터
  • iOS/GPU 이미지 사진
  • iOS/GPUI 이미지 보기

그런 다음 UI 이미지에 기존 UI 이미지에 블러 효과를 추가하는 범주를 만듭니다.

#import "UIImage+Utils.h"

#import "GPUImagePicture.h"
#import "GPUImageSolidColorGenerator.h"
#import "GPUImageAlphaBlendFilter.h"
#import "GPUImageBoxBlurFilter.h"

@implementation UIImage (Utils)

- (UIImage*) GPUBlurredImage
{
    GPUImagePicture *source =[[GPUImagePicture alloc] initWithImage:self];

    CGSize size = CGSizeMake(self.size.width * self.scale, self.size.height * self.scale);

    GPUImageBoxBlurFilter *blur = [[GPUImageBoxBlurFilter alloc] init];
    [blur setBlurRadiusInPixels:4.0f];
    [blur setBlurPasses:2.0f];
    [blur forceProcessingAtSize:size];
    [source addTarget:blur];

    GPUImageSolidColorGenerator * white = [[GPUImageSolidColorGenerator alloc] init];

    [white setColorRed:1.0f green:1.0f blue:1.0f alpha:0.1f];
    [white forceProcessingAtSize:size];

    GPUImageAlphaBlendFilter * blend = [[GPUImageAlphaBlendFilter alloc] init];
    blend.mix = 0.9f;

    [blur addTarget:blend];
    [white addTarget:blend];

    [blend forceProcessingAtSize:size];
    [source processImage];

    return [blend imageFromCurrentlyProcessedOutput];
}

@end

마지막으로 다음 프레임워크를 프로젝트에 추가합니다.

AV Foundation 코어 미디어 코어 비디오 오픈GLES

네, 훨씬 더 빠른 접근법으로 재미를 보았습니다 ;)

배경을 흐리게 하는 기능이 있는 내 사용자 정의 보기를 사용해 볼 수 있습니다.Apple의 WWDC 코드에 있는 것처럼 배경 스냅샷을 가장하여 흐리게 함으로써 이를 수행합니다.이것은 사용하기 매우 간단합니다.

저는 또한 성능을 잃지 않고 역동적인 블러를 가짜로 만들기 위해 약간의 개선을 했습니다.내 보기의 배경은 보기와 함께 스크롤되는 스크롤 보기이므로 나머지 수퍼 보기에 블러 효과를 제공합니다.

GitHub의 예제 및 코드 보기

코어 배경은 원하는 iOS 7 효과를 구현합니다.

https://github.com/justinmfischer/core-background

고지 사항:저는 이 프로젝트의 저자입니다.

언급URL : https://stackoverflow.com/questions/17055740/how-can-i-produce-an-effect-similar-to-the-ios-7-blur-view

반응형