Jak mogę uzyskać efekt podobny do widoku rozmycia w iOS 7?

219

Próbuję odtworzyć to rozmyte tło z publicznie opublikowanego przykładowego ekranu iOS 7:

iOS 7 Control Center screenshot

To pytanie sugeruje zastosowanie filtra CI do treści poniżej, ale to zupełnie inne podejście. Oczywiste jest, że iOS 7 nie przechwytuje zawartości poniższych widoków z wielu powodów:

  1. Przeprowadzenie zgrubnych testów, zrobienie zrzutu ekranu poniższych widoków i zastosowanie filtra CIGaussianBlur o wystarczająco dużym promieniu, aby naśladować styl rozmycia iOS 7, zajmuje nawet 1-2 sekundy, nawet na symulatorze.
  2. Widok rozmycia w iOS 7 może zamazywać dynamiczne widoki, takie jak wideo lub animacje, bez zauważalnego opóźnienia.

Czy ktoś może postawić hipotezę, jakich ram mógłby użyć do stworzenia tego efektu i czy można stworzyć podobny efekt za pomocą obecnych publicznych interfejsów API?

Edycja: (z komentarza) Nie wiemy dokładnie, jak Apple to robi, ale czy możemy przyjąć jakieś podstawowe założenia? Możemy założyć, że używają sprzętu, prawda?

Czy efekt jest samowystarczalny w każdym widoku, tak że efekt tak naprawdę nie wie, co się za nim kryje? A może, biorąc pod uwagę sposób działania rozmycia, należy wziąć pod uwagę treść stojącą za rozmyciem?

Jeśli treść kryjąca się za efektem jest istotna, czy możemy założyć, że Apple otrzymuje „kanał” treści poniżej i stale renderuje je z rozmyciem?

Bałwan
źródło
(Wydaje mi się, że możemy założyć, że Apple i tak używa renderowania ekranu głównego za pomocą czystego GL. Wątpię, czy abstrakcyjnie to z UIViews i innymi rzeczami, które obniżyłyby wydajność, ponieważ jest to tak kluczowa część systemu operacyjnego)
Dave
Jak wskazałem w komentarzach do mojej odpowiedzi tutaj: stackoverflow.com/a/17048668/19679 , napisali oni system operacyjny, więc oczywiście będą mieli przyspieszony dostęp do zawartości warstw ułożonych poniżej bieżącego widoku. Widzimy część tego, co mogliby używać w prywatnym IOSurface API: stackoverflow.com/questions/14135215/... . Rozmycia gaussowskie można wykonać znacznie szybciej niż uogólnione przypadki rozmycia gaussowskiego, jeśli mają stały promień, lub nawet zastosować ciekawe optymalizacje, takie jak zintegrowane obrazy.
Brad Larson
@BradLarson - Parafrazując Jessicę Simpson ... Nie mam pojęcia, co to wszystko znaczy, ale brzmi fajnie jak cholera! Ale poważnie, czy mówisz, że możesz użyć częściowo przezroczystego widoku z filtrem rozmycia i nałożyć go na inny widok, aby osiągnąć ten efekt?
sangony
stackoverflow.com/a/25706250/2308190 działał dla mnie idealnie za pierwszym razem, gdy go wypróbowałem, i był zwięzły
Ben Wheeler

Odpowiedzi:

134

Po co zawracać sobie głowę powtarzaniem efektu? Po prostu narysuj pasek narzędzi UITool za swoim widokiem.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];
użytkownik2342340
źródło
8
Nie zgadzam się z Crizzwaldem. Nie sądzę, żeby to była dobra interpretacja zasad oczekiwania na to, co zrobi APple.
Andrew Johnson,
117
W tym tygodniu zastosowałem to podejście przez inżyniera Apple UIKit w ich laboratorium Tech Talks. Chociaż z pewnością nie poparłby tego podejścia, zdał sobie sprawę z potrzeby efektu i braku prawdziwego publicznego API dla tego, i powiedział, że takie podejście było na razie opcją „najmniej zła” i jest dość bezpieczne, jak napisano. Konkretnie powiedział nie starają się robić żadnych animacji Spośród framelub transformz tego paska / widoku lub coś podobnego, albo złych rzeczy się wydarzy. Zdecydowanie zasugerował również złożenie raportów o błędach radaru w tej sprawie, aby zbudować wewnętrzną skrzynkę, abyśmy mogli uzyskać prawdziwy publiczny interfejs API dla tego efektu!
smileyborg,
44
Ciekawe ... wygląda na to, że konto @ user2342340 zostało utworzone tylko po to, aby anonimowo odpowiedzieć na to pytanie. Sprawia, że ​​zastanawiasz się, czy nie jest to nieoficjalny post autorstwa kogoś, kto wie o tych sprawach więcej niż reszta :)
smileyborg
4
Nie działa to na iPhonie 4 z systemem iOS 7. Prawdopodobnie dlatego, że na iPhonie 4, ponieważ moc GPU jest zbyt niska, system nie dodaje do siebie zwykłego efektu rozmycia UITabBar.
Ayush Goel,
2
Jak mogę sprawić, żeby nie był biały? Jeśli zmienię kolor tła paska narzędzi, nie pokazuje rozmycia.
Nikita P,
64

Apple wydał kod w WWDC jako kategorię na UIImage, która zawiera tę funkcjonalność, jeśli masz konto programisty, możesz pobrać kategorię UIImage (i resztę przykładowego kodu), przechodząc do tego linku: https://developer.apple. com / wwdc / schedule / oraz przeglądanie sekcji 226 i klikanie szczegółów. Jeszcze się z tym nie bawiłem, ale myślę, że efekt będzie znacznie wolniejszy na iOS 6, jest kilka ulepszeń w iOS 7, które sprawiają, że chwytanie początkowego zrzutu ekranu, który jest używany jako sygnał wejściowy do rozmycia, jest znacznie szybszy.

Bezpośredni link: https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip

FreaknBigPanda
źródło
1
Widzę wideo, mogę je obejrzeć, ale nie mogę dowiedzieć się, skąd pobrać przykładowy kod!
Nathan H
Nie widziałem dużej różnicy w porównaniu do prostej zmiany alfa tła; może dlatego, że wyświetlam filmy, a one po prostu potrzebują więcej rozmycia ...
Ja͢ck
37

Założę się, że osiągnięcie tego byłoby raczej proste. Prawdopodobnie nie działałby ani nie wyglądał dokładnie tak, jak dzieje się Apple, ale może być bardzo blisko.

Przede wszystkim musisz określić CGRect UIView, który będziesz prezentować. Po ustaleniu, że wystarczy uchwycić obraz części interfejsu użytkownika, aby można go było rozmazać. Coś takiego...

- (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;
}

Rozmycie gaussowskie - zalecane

Korzystając z UIImage+ImageEffectspodanej tutaj kategorii Apple , uzyskasz rozmycie gaussowskie, które wygląda bardzo podobnie do rozmycia w iOS 7.

Rozmycie pola

Możesz także użyć rozmycia pola, używając następującej boxBlurImageWithBlur:kategorii UIImage. Jest to oparte na algorytmie, który można znaleźć tutaj .

@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

Teraz, gdy obliczasz obszar ekranu do rozmycia, przekazujesz go do kategorii rozmycia i otrzymujesz obraz UIImage, który został zamazany, teraz pozostaje tylko ustawić zamazany obraz jako tło widoku, który będziesz prezentować. Jak powiedziałem, nie będzie to idealne dopasowanie do tego, co robi Apple, ale nadal powinno wyglądać całkiem fajnie.

Mam nadzieję, że to pomoże.

Jeremy Fox
źródło
Wygląda na to, że niebieski i czerwony kolor zamazanego obrazu są zamienione.
Henry
Wygląda na to, że ktoś użył twojego kodu do stworzenia tego projektu: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/... ale niestety nie ma przypisania, i dodał oświadczenie o prawach autorskich „Wszelkie prawa zastrzeżone” na górze.
Mark Erdmann
@ Mark, dziękuję za zgłoszenie się. Jednak ten algorytm rozmycia nie jest mój. Wspomniałem już, skąd go wziąłem w moim poście powyżej. Jak napisano w moim poście „Jest to oparty na algorytmie, który można znaleźć tutaj”. z linkiem do indieambitions.com/idevblogaday/… Na pewno wyślę tej osobie wiadomość i poinformuję ją, że brakuje jej atrybucji. Dzięki
Jeremy Fox
@ MarkErdmann spójrz na swoje własne pliki w xcode. Ma „Wszelkie prawa zastrzeżone”. Jest to ogólna rzecz, którą dodaje xcode. Również autor dodał właśnie dodał license.md, który mówi, że został zwolniony pod mit lisence
Święty Mikołaj
Nie używaj renderInContext, używaj nowego drawViewHierarchyInRect:lub snapshotView:. Dyskusja WWDC 216 „Implementing Engaging UI on iOS7” twierdzi, że poprawia wydajność 5-15x.
bydło
25

iOS8 odpowiedział na te pytania.

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

lub Szybki:

init(effect effect: UIVisualEffect)

Adam Waite
źródło
Myślę, że to rozwiązanie jest w większości bezużyteczne, dopóki iOS 9 nie zostanie wydany. Większość aplikacji nadal obsługuje iOS 7, a to rozwiązanie nie jest tam obsługiwane.
Dmitrij Sobolev
prawda prawda, na razie możesz użyć tego rodzaju rzeczy: github.com/nicklockwood/FXBlurView
Adam Waite
Zaimplementowałem to przy pomocy Xcode 6 Toolchain z iOS8 i działa świetnie. Próbowałem zaimplementować za pomocą procesora, ale działa zauważalnie wolniej niż ta metoda.
Jon
Po co kodować, gdy Xcode sam w scenorysie !!!!! Dzięki @AdamWaite
Mihir Oza
20

Właśnie napisałem moją małą podklasę UIView, która ma zdolność do generowania natywnego rozmycia w iOS 7 w dowolnym widoku niestandardowym. Korzysta z paska narzędzi UIToolbar, ale w bezpieczny sposób zmienia ramkę, obwiednie, kolor i alfa z animacją w czasie rzeczywistym.

Daj mi znać, jeśli zauważysz jakiekolwiek problemy.

https://github.com/ivoleko/ILTranslucentView

Przykłady ILTranslucentView

Ivo Leko
źródło
Wypróbowałem kilka innych metod (np. Dodanie paska narzędzi UIToolbar lub kategoria Apple UIImage + ImageEffects.h); twoje było najlepszym i najłatwiejszym rozwiązaniem. Dzięki!
Yunus Nedim Mehel
4
Jak dobrze reaguje na nowe pobieranie iOS 7.0.3? Inne klasy, które wykorzystały tę technikę, nie renderują już poprawnie: [
achi
@achi, nie zauważyłem żadnego problemu z iOS 7.0.3.
Ivo Leko,
Czy wiesz, czy są jakieś aplikacje animowane przy użyciu Twojego podejścia i zaakceptowane przez Apple?
Brad Goss
Cześć chłopaki. Tak, aplikacja korzystająca z tej klasy zostanie zatwierdzona przez Apple!
Ivo Leko
10

Plotka głosi, że inżynierowie Apple twierdzili, że aby zwiększyć wydajność, czytają bezpośrednio z bufora GPU, co rodzi problemy z bezpieczeństwem, dlatego nie ma jeszcze publicznego interfejsu API, aby to zrobić.

Cody C.
źródło
6
Jeśli to prawda, jest to - jak dotąd - najgorsze rozwiązanie w historii.
elslooo,
2
aaaaa i rozmycie zostało usunięte z iOS 7.
Code Guru
3
Został usunięty tylko na urządzeniach, które miały problemy z wydajnością.
Cody C
24
Czy ten post jest źródłem plotek? :)
Jano
11
Ta plotka jest prawdopodobnie koją. OpenGL ES 2.0 na iOS umożliwia czytanie i zapisywanie w buforach ramek bez żadnego ryzyka bezpieczeństwa. Rozmycie odbywa się za pomocą shaderów GLSL, dlatego działa szybko.
Bentford
7

To rozwiązanie można zobaczyć w vidios WWDC. Musisz zrobić rozmycie gaussowskie, więc pierwszą rzeczą, którą musisz zrobić, to dodać nowy plik .m i .h z kodem, który tu piszę, następnie musisz zrobić i zrobić zrzut ekranu, użyć pożądanego efektu i dodaj go do swojego widoku, a następnie UITable UIView lub co jeszcze musi być przezroczyste, możesz grać z applyBlurWithRadius, aby zarchiwizować pożądany efekt, to wywołanie działa z dowolnym magiem UIImage.

Na końcu zamazany obraz będzie tłem, a pozostałe elementy sterujące powyżej muszą być przezroczyste.

Aby to zadziałało, musisz dodać kolejne biblioteki:

Acelerate.framework, UIKit.framework, CoreGraphics.framework

Mam nadzieję, że to lubisz.

Szczęśliwego kodowania.

    //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;
    }
Marco Antonio Uzcategui Pescoz
źródło
7

Możesz znaleźć rozwiązanie z Apple DEMO na tej stronie: WWDC 2013 , dowiedz się i pobierz przykładowy kod UIImageEffects.

Następnie z kodem @Jeremy Fox. Zmieniłem to na

- (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];
}

Mam nadzieję, że to ci pomoże.

Senry
źródło
7

Oto naprawdę prosty sposób: https://github.com/JagCesar/iOS-blur

Po prostu skopiuj warstwę UIToolbar i gotowe - AMBlurView zrobi to za Ciebie. Okej, nie jest tak rozmazany jak centrum sterowania, ale jest wystarczająco rozmazany.

Pamiętaj, że iOS7 jest objęty umową NDA.

Szymon
źródło
6

Każda odpowiedź tutaj używa vImageBoxConvolve_ARGB8888 ta funkcja jest naprawdę, bardzo powolna, to dobrze, jeśli wydajność nie jest wymogiem o wysokim priorytecie, ale jeśli używasz tego do przejścia między dwoma kontrolerami widoku (na przykład) to podejście oznacza czasy ponad 1 po drugie, a może nawet więcej, jest to bardzo niekorzystne dla wrażeń użytkownika aplikacji.

Jeśli wolisz pozostawić to przetwarzanie obrazu GPU (i powinieneś), możesz uzyskać znacznie lepszy efekt, a także niesamowite czasy zaokrąglające 50 ms (zakładając, że masz czas 1 sekundy w pierwszym podejściu), więc zróbmy to .

Najpierw pobierz ramowa GPUImage (BSD Licencjonowany) tutaj .

Następnie dodaj następujące klasy (.m i .h) z GPUImage (nie jestem pewien, czy są to minimum potrzebne tylko do efektu rozmycia)

  • GPUImage.h
  • GPUImageAlphaBlendFilter
  • GPUImageFilter
  • GPUImageFilterGroup
  • GPUImageGaussianBlurPositionFilter
  • GPUImageGaussianSelectiveBlurFilter
  • GPUImageLuminanceRangeFilter
  • GPUImageOutput
  • GPUImageTwoInputFilter
  • GLProgram
  • GPUImageBoxBlurFilter
  • GPUImageGaussianBlurFilter
  • GPUImageiOSBlurFilter
  • GPUImageSaturationFilter
  • GPUImageSolidColorGenerator
  • GPUImageTwoPassFilter
  • GPUImageTwoPassTextureSamplingFilter

  • iOS / GPUImage-Prefix.pch

  • iOS / GPUImageContext
  • iOS / GPUImageMovieWriter
  • iOS / GPUImagePicture
  • iOS / GPUImageView

Następnie utwórz kategorię w UIImage, która doda efekt rozmycia do istniejącego UIImage:

#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

I na koniec dodaj następujące ramy do swojego projektu:

AVFoundation CoreMedia CoreVideo OpenGLES

Tak, dobrze się bawiłem dzięki temu znacznie szybszemu podejściu;)

D33pN16h7
źródło
4

Możesz spróbować użyć mojego niestandardowego widoku, który ma możliwość rozmycia tła. Robi to poprzez sfałszowanie zdjęcia migawki tła i rozmycie go, tak jak w kodzie WWDC firmy Apple. Jest bardzo prosty w użyciu.

Poczyniłem też pewne udoskonalenia, aby sfałszować dynamiczne rozmycie bez utraty wydajności. Tłem mojego widoku jest scrollView, który przewija się wraz z widokiem, zapewniając w ten sposób efekt rozmycia dla reszty podglądu.

Zobacz przykład i kod na moim GitHub

Bajt
źródło