Как создать эффект, похожий на размытие в iOS 7?

219

Я пытаюсь воспроизвести этот размытый фон с общедоступного примера экрана Apple iOS 7:

Скриншот Центра управления iOS 7

Этот вопрос предлагает применить фильтр CI к содержимому ниже, но это совершенно другой подход. Очевидно, что iOS 7 не захватывает содержимое представлений ниже по многим причинам:

  1. Выполнение грубого тестирования, создание снимка экрана представленных ниже видов и применение фильтра CIGaussianBlur с достаточно большим радиусом, чтобы имитировать стиль размытия в iOS 7, занимает 1-2 секунды, даже на симуляторе.
  2. Размытое представление iOS 7 способно размыть динамические виды, например видео или анимацию, без заметных задержек.

Может кто-нибудь предположить, какие структуры они могли бы использовать для создания этого эффекта, и возможно ли создать аналогичный эффект с текущими общедоступными API?

Редактировать: (из комментария) Мы точно не знаем, как Apple это делает, но есть ли какие-то основные предположения, которые мы можем сделать? Мы можем предположить, что они используют оборудование, верно?

Является ли эффект самодостаточным в каждом представлении, так что эффект фактически не знает, что за ним стоит? Или, исходя из того, как размытие работает, следует учитывать содержание, стоящее за размытием?

Если содержание, лежащее в основе эффекта, имеет отношение, можем ли мы предположить, что Apple получает «поток» содержимого ниже и постоянно рендерит их с размытостью?

Снеговик
источник
(Я думаю, мы можем предположить, что в любом случае Apple использует чистый GL для рендеринга домашних экранов. Я сомневаюсь, что они абстрагируют его с помощью UIViews и других вещей, которые могут снизить производительность, поскольку это такая ключевая часть ОС)
Дейв
Как я указал в комментариях к моему ответу здесь: stackoverflow.com/a/17048668/19679 они написали ОС, поэтому, конечно, они получат ускоренный доступ к содержимому слоев, скомпонованных под текущим представлением. Мы можем увидеть некоторые из того, что они могли бы использовать в частном API IOSurface: stackoverflow.com/questions/14135215/… . Размытие по Гауссу можно сделать намного быстрее, чем обобщенные случаи размытия по Гауссу, если они имеют фиксированный радиус или даже используют интересные оптимизации, такие как интегральные изображения.
Брэд Ларсон
@BradLarson - Перефразируя Джессику Симпсон ... Я понятия не имею, что все это значит, но это звучит круто, черт возьми! А если серьезно, вы хотите сказать, что вы можете использовать частично прозрачный вид с фильтром размытия и наложить его на другой вид, чтобы добиться этого эффекта?
Сангони
stackoverflow.com/a/25706250/2308190 отлично сработал для меня, когда я впервые попробовал это, и был лаконичен
Бен Уилер

Ответы:

134

Зачем воспроизводить эффект? Просто нарисуйте UIToolbar позади вашего представления.

myView.backgroundColor = [UIColor clearColor];
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:myView.frame];
bgToolbar.barStyle = UIBarStyleDefault;
[myView.superview insertSubview:bgToolbar belowSubview:myView];
user2342340
источник
8
Я не согласен с Кризвальдом. Я не думаю, что это хорошая интерпретация правил ожидания того, что сделает APple.
Эндрю Джонсон
117
Я применил этот подход инженером Apple UIKit на этой неделе в их лаборатории Tech Talks. Хотя он, конечно, не одобрил бы этот подход, он признал необходимость эффекта и отсутствие реального публичного API для этого и сказал, что этот подход на данный момент является «наименее злым» вариантом и довольно безопасен, как написано. В частности, он сказал, не пытайтесь делать какие-либо анимации frameили transformэтой панели инструментов / представления или что-то в этом роде, иначе произойдут плохие вещи. Он также настоятельно предложил подать отчеты об ошибках Radar по этому вопросу, чтобы создать внутреннее дело, чтобы мы могли получить настоящий публичный API для этого эффекта!
смайлиборг
44
Интересно ... похоже, учетная запись @ user2342340 была создана только для того, чтобы анонимно ответить на этот вопрос. Заставляет задуматься, не является ли это неофициальным сообщением того, кто знает об этих вещах больше, чем остальные из нас :)
smileyborg
4
Это не работает на iPhone 4 под управлением iOS 7. Вероятно, это связано с тем, что на iPhone 4, поскольку мощность графического процессора слишком мала, система не добавляет обычного эффекта размытия к UITabBarсамому себе.
Аюш Гоэль
2
Как мне сделать его небелым? Если я изменю цвет фона для панели инструментов, он не показывает размытие.
Никита П
64

Apple выпустила код на WWDC как категорию на UIImage, которая включает в себя эту функциональность. Если у вас есть учетная запись разработчика, вы можете получить категорию UIImage (и остальную часть примера кода), перейдя по этой ссылке: https://developer.apple. com / wwdc / schedule / и просматривая раздел 226 и нажимая на детали. Я еще не играл с ним, но думаю, что эффект будет намного медленнее в iOS 6, есть некоторые усовершенствования в iOS 7, которые делают захват начального снимка экрана, который используется в качестве входных данных для размытия, намного быстрее.

Прямая ссылка: https://developer.apple.com/downloads/download.action?path=wwdc_2013/wwdc_2013_sample_code/ios_uiimageeffects.zip

FreaknBigPanda
источник
1
Я вижу видео, я могу его посмотреть, но не могу понять, где можно загрузить образец кода!
Натан Х
Я не видел большой разницы по сравнению с простым альфа-изменением фона; возможно, это потому, что я показываю видео, и им просто нужно больше размытия ...
Ja͢ck
37

На самом деле я бы поспорил, что это будет довольно просто достичь. Это, вероятно, не будет работать или выглядеть точно так, как Apple, но может быть очень близко.

Прежде всего, вам нужно определить CGRect UIView, который вы будете представлять. Как только вы определите, что вам просто нужно получить изображение части пользовательского интерфейса, чтобы его можно было размыть. Что-то вроде этого...

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

Gaussian Blur - рекомендуется

Используя UIImage+ImageEffectsкатегорию Apple, представленную здесь , вы получите размытие по Гауссу, которое очень похоже на размытие в iOS 7.

Box Blur

Вы также можете использовать размытие окна, используя следующую boxBlurImageWithBlur:категорию UIImage. Это основано на алгоритме, который вы можете найти здесь .

@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

Теперь, когда вы вычисляете область экрана для размытия, переводите ее в категорию размытия и получаете обратно размытое изображение UIImage, теперь осталось только установить размытое изображение в качестве фона представления, которое вы будете представлять. Как я уже сказал, это не будет идеальным совпадением с тем, что делает Apple, но все равно должно выглядеть довольно круто.

Надеюсь, поможет.

Джереми Фокс
источник
Кажется, что синий цвет размытого изображения и красный цвет выбиты.
Генри
Похоже, кто-то использовал ваш код для создания этого проекта: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/… но, к сожалению, авторства нет, и они добавили заявление об авторских правах «All Rights Reserved» на вершине.
Марк Эрдманн
@ Марк, спасибо за советы. Однако этот алгоритм размытия не мой. Я уже упоминал, откуда я взял это в моем посте выше. Как говорится в моем посте: «Это основано на алгоритме, который вы можете найти здесь». со ссылкой на indieambitions.com/idevblogaday/… Я обязательно отправлю этому человеку сообщение и сообщу ему, что ему не хватает атрибуции. Спасибо
Джереми Фокс
@MarkErdmann взгляните на свои собственные файлы в xcode. Имеет «Все права защищены». Это общая вещь, которую добавляет XCode. Также автор добавил только что добавленный license.md, в котором говорится, что он лицензирован по лицензии
Дед Мороз
Не используйте renderInContext, используйте новый drawViewHierarchyInRect:или snapshotView:. В докладе WWDC 216 «Внедрение привлекательного пользовательского интерфейса на iOS7» утверждается, что повышение производительности в 5–15 раз.
скот
25

iOS8 ответила на эти вопросы.

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

или Свифт:

init(effect effect: UIVisualEffect)

Адам Уэйт
источник
Я думаю, что это решение в основном бесполезно до выхода iOS 9. Большинство приложений по-прежнему поддерживают iOS 7, и это решение там не поддерживается.
Дмитрий Соболев
правда верно, вы можете использовать такие вещи сейчас: github.com/nicklockwood/FXBlurView
Адам Уэйт
Я реализовал это с помощью набора инструментов Xcode 6 с iOS8, и он прекрасно работает. Я пытался реализовать с помощью процессора, но работает заметно медленнее, чем этот метод.
Jon
Зачем кодировать, когда Xcode предоставляет в раскадровке саму !!!!! Спасибо @AdamWaite
Михир Оза
20

Я только что написал свой маленький подкласс UIView, который имеет возможность создавать естественное размытие iOS 7 для любого пользовательского представления. Он использует UIToolbar, но безопасным способом для изменения его рамки, границ, цвета и альфа-канала с анимацией в реальном времени.

Пожалуйста, дайте мне знать, если вы заметите какие-либо проблемы.

https://github.com/ivoleko/ILTranslucentView

ILTranslucentПросмотреть примеры

Иво Леко
источник
Я пробовал некоторые другие подходы (например, добавление UIToolbar или категории Apple UIImage + ImageEffects.h); Ваше было лучшим и самым простым решением. Спасибо!
Юнус Недим Мехел
4
Насколько хорошо он реагирует на новую загрузку iOS 7.0.3? Другие классы, которые использовали эту технику, больше не отображаются правильно: [
achi
@achi, я не заметил никаких проблем с iOS 7.0.3.
Иво Леко
Знаете ли вы, если какие-либо приложения, которые анимируются с использованием вашего подхода и были приняты Apple?
Брэд Госс
Привет, ребята. Да, приложение, использующее этот класс, будет одобрено Apple!
Иво Леко
10

Ходят слухи, что инженеры Apple утверждают, что для обеспечения этой производительности они читают напрямую из буфера gpu, что поднимает проблемы безопасности, поэтому пока еще нет общедоступного API для этого.

Коди С
источник
6
Если это правда, то это - безусловно - худшее решение за всю историю.
elslooo
2
ааааа и размытие убрано из iOS 7.
Code Guru
3
Он был удален только на устройствах с проблемами производительности.
Коди С
24
Является ли этот пост источником слухов? :)
Jano
11
Этот слух, вероятно, койка. OpenGL ES 2.0 на iOS позволяет читать и записывать в кадровые буферы без какого-либо риска для безопасности. Размытие выполняется с помощью шейдеров GLSL, поэтому он работает быстро.
Бентфорд
7

Это решение, которое вы можете увидеть в видео WWDC. Вы должны сделать Gaussian Blur, поэтому первое, что вы должны сделать, это добавить новый файл .m и .h с кодом, который я пишу здесь, затем вы должны сделать снимок экрана, использовать желаемый эффект и добавьте его к своему виду, затем к вашему UITable UIView или к тому, что когда-либо должно быть прозрачным, вы можете поиграть с applyBlurWithRadius, чтобы заархивировать желаемый эффект, этот вызов работает с любым UIImage.

В конце размытое изображение станет фоном, а остальные элементы управления должны быть прозрачными.

Для этого вам нужно добавить следующие библиотеки:

Acelerate.framework, 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;
    }
Марко Антонио Узкатеги Пескоз
источник
7

Вы можете найти свое решение от Apple DEMO на этой странице: WWDC 2013 , найдите и загрузите пример кода 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];
}

Надеюсь, что это поможет вам.

Senry
источник
7

Вот действительно простой способ сделать это: https://github.com/JagCesar/iOS-blur

Просто скопируйте слой UIToolbar, и все готово, AMBlurView сделает это за вас. Хорошо, это не так размыто, как центр управления, но достаточно размыто.

Помните, что iOS7 находится под NDA.

Саймон
источник
6

Каждый ответ здесь использует vImageBoxConvolve_ARGB8888 эта функция очень, очень медленная, это хорошо, если производительность не является требованием высокого приоритета, но если вы используете это для перехода между двумя контроллерами представления (например), такой подход означает время более 1 во-вторых, а может и больше, это очень плохо сказывается на работе вашего приложения.

Если вы предпочитаете оставить всю эту обработку изображений на GPU (и вы должны это сделать), вы можете получить гораздо лучший эффект, а также отличные времена, округляющие 50 мс (предположим, что у вас есть время в 1 секунду при первом подходе), так что давайте сделаем это ,

Сначала загрузите GPUImage Framework (BSD Licensed) здесь .

Затем добавьте следующие классы (.m и .h) из GPUImage (я не уверен, что это минимум, необходимый только для эффекта размытия)

  • 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

Затем создайте категорию на UIImage, которая добавит эффект размытия к существующему 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

И наконец, добавьте следующие рамки в ваш проект:

AVFoundation CoreMedia CoreVideo OpenGLES

Да, повеселился с этим гораздо более быстрым подходом;)

D33pN16h7
источник
4

Вы можете попробовать использовать мой пользовательский вид, который имеет возможность размыть фон. Он делает это путем фальсификации, снимая фон и размывая его, как в коде Apple WWDC. Это очень просто в использовании.

Я также сделал некоторые улучшения, чтобы имитировать динамическое размытие без потери производительности. Фоном моего вида является scrollView, который прокручивается вместе с видом, таким образом обеспечивая эффект размытия для остальной части суперпредставления.

Смотрите пример и код на моем GitHub

Байт
источник