¿Cómo puedo producir un efecto similar a la vista borrosa de iOS 7?

219

Estoy tratando de replicar este fondo borroso de la pantalla de ejemplo de iOS 7 lanzada públicamente de Apple:

Captura de pantalla del Centro de control de iOS 7

Esta pregunta sugiere aplicar un filtro CI al contenido a continuación, pero ese es un enfoque completamente diferente. Es obvio que iOS 7 no captura el contenido de las vistas a continuación, por muchas razones:

  1. Hacer algunas pruebas aproximadas, capturar una captura de pantalla de las vistas a continuación y aplicar un filtro CIGaussianBlur con un radio lo suficientemente grande para imitar el estilo de desenfoque de iOS 7 toma 1-2 segundos, incluso en un simulador.
  2. La vista borrosa de iOS 7 puede difuminarse sobre vistas dinámicas, como un video o animaciones, sin un retraso notable.

¿Alguien puede formular una hipótesis sobre qué marcos podrían estar usando para crear este efecto y si es posible crear un efecto similar con las API públicas actuales?

Editar: (del comentario) No sabemos exactamente cómo lo está haciendo Apple, pero ¿hay alguna suposición básica que podamos hacer? Podemos suponer que están usando hardware, ¿verdad?

¿El efecto es autónomo en cada vista, de modo que el efecto no sabe realmente qué hay detrás? ¿O, en función de cómo funcionan los desenfoques, se debe tener en cuenta el contenido detrás del desenfoque?

Si los contenidos detrás del efecto son relevantes, ¿podemos suponer que Apple está recibiendo un "feed" de los contenidos a continuación y los procesa continuamente con un desenfoque?

Monigote de nieve
fuente
(Creo que podemos asumir que Apple está usando GL puro para renderizar las pantallas de inicio de todos modos. Dudo que lo estén abstrayendo con UIViews y otras cosas que degradarían el rendimiento, ya que es una parte clave del sistema operativo)
Dave
Como indiqué en los comentarios a mi respuesta aquí: stackoverflow.com/a/17048668/19679 escribieron el sistema operativo, por lo que, por supuesto, tendrán acceso acelerado al contenido de las capas compuestas debajo de la vista actual. Podemos ver algo de lo que podrían estar usando en la API privada de IOSurface: stackoverflow.com/questions/14135215/… . Los desenfoques gaussianos se pueden hacer mucho más rápido que los casos de desenfoque gaussiano generalizado si tienen un radio fijo, o incluso usan optimizaciones interesantes como imágenes integrales.
Brad Larson
@BradLarson - Parafraseando a Jessica Simpson ... No tengo idea de lo que significa todo eso, ¡pero suena genial! Pero en serio, ¿estás diciendo que puedes usar una vista parcialmente transparente con un filtro de desenfoque y colocarla sobre otra vista para lograr este efecto?
Sangony
stackoverflow.com/a/25706250/2308190 funcionó perfectamente para mí la primera vez que lo probé, y fue conciso
Ben Wheeler

Respuestas:

134

¿Por qué molestarse en replicar el efecto? Simplemente dibuje una barra UIToolbar detrás de su vista.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];
usuario2342340
fuente
8
No estoy de acuerdo con Crizzwald. No creo que sea una buena interpretación de las reglas de expectativa de lo que hará APple.
Andrew Johnson
118
Ejecuté este enfoque por un ingeniero de Apple UIKit esta semana en su laboratorio de Tech Talks. Si bien ciertamente no respaldaría este enfoque, reconoció la necesidad del efecto y la falta de una API pública real para esto, y dijo que este enfoque era la opción "menos malvada" por ahora y es bastante seguro como está escrito. Específicamente dijo que no intente hacer ninguna animación de la frameo transformde esta barra de herramientas / vista o algo así, o sucederán cosas malas. ¡También sugirió encarecidamente presentar informes de errores de radar sobre esto, para construir un caso internamente para que podamos obtener una API pública real para este efecto!
smileyborg
44
Interesante ... parece que la cuenta @ user2342340 se creó solo para responder esta pregunta de forma anónima. Te hace preguntarte si esta no es una publicación no oficial de alguien que sabe más que el resto de nosotros sobre estas cosas :)
smileyborg
4
Esto no funciona en iPhone 4 con iOS 7. Probablemente se deba a que en iPhone 4, dado que la potencia de la GPU es demasiado baja, el sistema no agrega el efecto de desenfoque habitual a sí UITabBarmismo.
Ayush Goel
2
¿Cómo hago para que no sea blanco? Si cambio el color de fondo de la barra de herramientas, no muestra el desenfoque.
Nikita P
64

Apple lanzó código en WWDC como una categoría en UIImage que incluye esta funcionalidad, si tiene una cuenta de desarrollador, puede obtener la categoría UIImage (y el resto del código de muestra) yendo a este enlace: https://developer.apple. com / wwdc / schedule / y busque la sección 226 y haga clic en los detalles. No he jugado con él todavía, pero creo que el efecto será mucho más lento en iOS 6, hay algunas mejoras en iOS 7 que hacen que capturar la captura de pantalla inicial que se usa como entrada para el desenfoque sea mucho más rápido.

Enlace directo: https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip

FreaknBigPanda
fuente
1
Veo el video, puedo verlo, ¡pero no puedo averiguar dónde descargar el código de muestra!
Nathan H
No vi mucha diferencia en comparación con un simple cambio alfa de fondo; tal vez sea porque estoy mostrando videos y solo necesitan más desenfoque ...
Ja͢ck
37

En realidad, apuesto a que esto sería bastante sencillo de lograr. Probablemente no funcionaría ni se vería exactamente como lo que está pasando Apple, pero podría estar muy cerca.

En primer lugar, debe determinar el CGRect de la UIView que presentará. Una vez que haya determinado que solo necesitará tomar una imagen de la parte de la interfaz de usuario para que pueda desenfocarse. Algo como esto...

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

Desenfoque gaussiano: recomendado

Usando la UIImage+ImageEffectscategoría que Apple proporciona aquí , obtendrá un desenfoque gaussiano que se parece mucho al desenfoque en iOS 7.

Caja de desenfoque

También puede usar un cuadro de desenfoque usando la siguiente boxBlurImageWithBlur:categoría de UIImage. Esto se basa en un algoritmo que puede encontrar aquí .

@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

Ahora que está calculando el área de la pantalla para desenfocar, pasándola a la categoría de desenfoque y recibiendo una imagen de UII que se ha desenfocado, ahora todo lo que queda es establecer esa imagen desenfocada como fondo de la vista que presentará. Como dije, esto no será una combinación perfecta para lo que está haciendo Apple, pero aún así debería verse bastante bien.

Espero eso ayude.

Jeremy Fox
fuente
Parece que el color azul y el rojo de la imagen borrosa se intercambian.
Henry
Parece que alguien usó tu código para crear este proyecto: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/… pero desafortunadamente no hay atribución, y agregaron una declaración de derechos de autor "Todos los derechos reservados". en la cima.
Mark Erdmann
@ Mark, gracias por el aviso. Sin embargo, este algoritmo de desenfoque no es mío. Ya mencioné de dónde lo obtuve en mi publicación anterior. Como dice en mi post "Esto se basa en un algoritmo que puedes encontrar aquí". con un enlace a indieambitions.com/idevblogaday/… Definitivamente le enviaré un mensaje a esta persona y le haré saber que le falta atribución. Gracias
Jeremy Fox
@MarkErdmann echa un vistazo a tus propios archivos en xcode. Tiene "Todos los derechos reservados". Es algo genérico que agrega xcode. Además, el autor acaba de agregar una licencia.md que dice que está licenciada bajo la mit lisence
Santa Claus
No use renderInContext, use el nuevo drawViewHierarchyInRect:o snapshotView:. La charla 216 de la WWDC "Implementación de una interfaz de usuario atractiva en iOS7" afirma una mejora del rendimiento de 5-15 veces.
ganado
25

iOS8 respondió estas preguntas.

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

o Swift:

init(effect effect: UIVisualEffect)

Adam Waite
fuente
Supongo que esta solución es casi inútil hasta que salga iOS 9. La mayoría de las aplicaciones aún son compatibles con iOS 7 y esta solución no es compatible allí.
Dmitry Sobolev
cierto, cierto, puedes usar este tipo de cosas por ahora: github.com/nicklockwood/FXBlurView
Adam Waite
Implementé esto con la cadena de herramientas Xcode 6 con iOS8, y funciona muy bien. Intenté implementar usando la CPU, pero funciona notablemente más lento que este método.
Jon
¿Por qué codificar cuando Xcode lo proporciona en el propio guión gráfico? Gracias @AdamWaite
Mihir Oza
20

Acabo de escribir mi pequeña subclase de UIView que tiene la capacidad de producir desenfoque nativo de iOS 7 en cualquier vista personalizada. Utiliza UIToolbar pero de una manera segura para cambiar su marco, límites, color y alfa con animación en tiempo real.

Avíseme si nota algún problema.

https://github.com/ivoleko/ILTranslucentView

Ejemplos de ILTranslucentView

Ivo Leko
fuente
He intentado algunos otros enfoques (como agregar un UIToolbar yo mismo, o la categoría UIImage + ImageEffects.h de Apple); tu fue la mejor y más fácil solución. ¡Gracias!
Yunus Nedim Mehel
4
¿Qué tan bien reacciona a la nueva descarga de iOS 7.0.3? Otras clases que han usado esta técnica ya no se procesan correctamente: [
achi
@achi, no noté ningún problema con iOS 7.0.3.
Ivo Leko
¿Sabe si alguna aplicación que se anima con su enfoque y ha sido aceptada por Apple?
Brad Goss
Hola chicos. Sí, Apple aprobará las aplicaciones que utilicen esta clase.
Ivo Leko
10

Existe un rumor de que los ingenieros de Apple afirmaron que para hacer este rendimiento están leyendo directamente del búfer de la gpu, lo que plantea problemas de seguridad, por lo que todavía no hay una API pública para hacer esto.

Cody C
fuente
6
Si esto es cierto, entonces es, con mucho, la peor solución jamás vista.
elslooo
2
aaaaaand el desenfoque se elimina de iOS 7.
Code Guru
3
Solo se eliminó en dispositivos que presentaban problemas de rendimiento.
Cody C
24
¿Es esta publicación la fuente del rumor? :)
Jano
11
Ese rumor probablemente sea una tontería. OpenGL ES 2.0 en iOS le permite leer y escribir en framebuffers sin ningún riesgo de seguridad. El desenfoque se realiza mediante sombreadores GLSL, por lo que se ejecuta rápido.
Bentford
7

Esta es una solución que puedes ver en los videos de la WWDC. Tienes que hacer un Desenfoque Gaussiano, así que lo primero que tienes que hacer es agregar un nuevo archivo .my .h con el código que estoy escribiendo aquí, luego tienes que hacer una captura de pantalla, usar el efecto deseado y agréguelo a su vista, luego su UITable UIView o lo que sea que tenga que ser transparente, puede jugar con applyBlurWithRadius, para archivar el efecto deseado, esta llamada funciona con cualquier UIImage.

Al final, la imagen borrosa será el fondo y el resto de los controles de arriba tienen que ser transparentes.

Para que esto funcione, debe agregar las siguientes bibliotecas:

Acelerate.framework, UIKit.framework, CoreGraphics.framework

Espero que te guste.

Codificación feliz.

    //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
fuente
7

Puede encontrar su solución en la DEMO de Apple en esta página: WWDC 2013 , descubra y descargue el código de muestra de UIImageEffects.

Luego con el código de @Jeremy Fox. Lo cambié a

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

Espero que esto te ayudará.

Senry
fuente
7

Aquí hay una forma realmente fácil de hacerlo: https://github.com/JagCesar/iOS-blur

Simplemente copie la capa de UIToolbar y listo, AMBlurView lo hace por usted. De acuerdo, no es tan borroso como el centro de control, pero es lo suficientemente borroso.

Recuerde que iOS7 está bajo NDA.

Simón
fuente
6

Cada respuesta aquí usa vImageBoxConvolve_ARGB8888.Esta función es muy, muy lenta, eso está bien, si el rendimiento no es un requisito de alta prioridad, pero si está utilizando esto para la transición entre dos controladores de vista (por ejemplo), este enfoque significa tiempos superiores a 1 segundo o quizás más, eso es muy malo para la experiencia del usuario de su aplicación.

Si prefiere dejar todo este procesamiento de imágenes a la GPU (y debería) puede obtener un efecto mucho mejor y también tiempos increíbles redondeando 50ms (suponiendo que tenga un tiempo de 1 segundo en el primer enfoque), entonces, hagámoslo. .

Primero descargue GPUImage Framework (con licencia BSD) aquí .

A continuación, agregue las siguientes clases (.my .h) de GPUImage (no estoy seguro de que sean el mínimo necesario solo para el efecto de desenfoque)

  • GPUImage.h
  • GPUImageAlphaBlendFilter
  • GPUImageFilter
  • GPUImageFilterGroup
  • GPUImagenGaussianBlurPositionFilter
  • GPUImagenGaussianSelectiveBlurFilter
  • GPUImageLuminanceRangeFilter
  • GPUImageOutput
  • GPUImageTwoInputFilter
  • GLProgram
  • GPUImageBoxBlurFilter
  • GPUImageGaussianBlurFilter
  • GPUImageiOSBlurFilter
  • GPUImageSaturationFilter
  • GPUImageSolidColorGenerator
  • GPUImageTwoPassFilter
  • GPUImagenDosPasadaTexturaMuestreoFiltro

  • iOS / GPUImage-Prefix.pch

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

A continuación, cree una categoría en UIImage, que agregará un efecto de desenfoque a un UIImage existente:

#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

Y por último, agregue los siguientes marcos a su proyecto:

AVFoundation CoreMedia CoreVideo OpenGLES

Sí, me divertí con este enfoque mucho más rápido;)

D33pN16h7
fuente
4

Puede intentar usar mi vista personalizada, que tiene la capacidad de desenfocar el fondo. Lo hace simulando tomar una instantánea del fondo y desenfocarlo, como en el código WWDC de Apple. Es muy facíl de usar.

También hice algunas mejoras para simular el desenfoque dinámico sin perder el rendimiento. El fondo de mi vista es un scrollView que se desplaza con la vista, por lo que proporciona el efecto de desenfoque para el resto de la supervista.

Vea el ejemplo y el código en mi GitHub

Byte
fuente