ฉันจะสร้างเอฟเฟกต์ที่คล้ายกับมุมมองเบลอของ iOS 7 ได้อย่างไร


219

ฉันพยายามทำซ้ำพื้นหลังเบลอนี้จากหน้าจอตัวอย่าง iOS 7 ที่เผยแพร่สู่สาธารณะของ Apple:

ภาพหน้าจอศูนย์ควบคุม iOS 7

คำถามนี้แนะนำให้ใช้ตัวกรอง CI กับเนื้อหาด้านล่าง แต่นั่นเป็นวิธีการที่แตกต่างกันโดยสิ้นเชิง เห็นได้ชัดว่า iOS 7 ไม่ได้รวบรวมเนื้อหาของมุมมองด้านล่างด้วยเหตุผลหลายประการ:

  1. ทำการทดสอบอย่างคร่าวๆจับภาพหน้าจอของมุมมองด้านล่างและใช้ตัวกรอง CIGaussianBlur ที่มีรัศมีมากพอที่จะเลียนแบบสไตล์การเบลอของ iOS 7 ใช้เวลา 1-2 วินาทีแม้กระทั่งบนเครื่องจำลอง
  2. มุมมองเบลอ iOS 7 สามารถเบลอมุมมองแบบไดนามิกเช่นวิดีโอหรือภาพเคลื่อนไหวโดยไม่มีความล่าช้าอย่างเห็นได้ชัด

ทุกคนสามารถตั้งสมมติฐานว่ากรอบงานใดที่พวกเขาสามารถใช้เพื่อสร้างเอฟเฟกต์นี้และถ้าเป็นไปได้ที่จะสร้างเอฟเฟกต์ที่คล้ายกันกับ API สาธารณะปัจจุบัน

แก้ไข: (จากความคิดเห็น) เราไม่รู้แน่ชัดว่า Apple กำลังทำอะไรอยู่ แต่มีสมมติฐานพื้นฐานที่เราสามารถทำได้หรือไม่? เราสามารถสรุปได้ว่าพวกเขากำลังใช้ฮาร์ดแวร์ใช่ไหม?

เอฟเฟกต์มีอยู่ในแต่ละมุมมองเช่นนี้เอฟเฟกต์ไม่ทราบว่ามีอะไรอยู่เบื้องหลัง หรือต้องพิจารณาเนื้อหาที่อยู่เบื้องหลังความพร่ามัวที่พิจารณาว่าเป็นพร่ามัวหรือไม่

หากเนื้อหาที่อยู่เบื้องหลังเอฟเฟกต์มีความเกี่ยวข้องเราสามารถสมมติว่า Apple ได้รับ "ฟีด" ของเนื้อหาด้านล่างและแสดงผลอย่างเบลออย่างต่อเนื่องหรือไม่?


(ฉันคิดว่าเราสามารถสันนิษฐานได้ว่าแอปเปิ้ลกำลังใช้ GL บริสุทธิ์เพื่อแสดงผลหน้าจอหลักต่อไปฉันสงสัยว่าพวกเขากำลังสรุปเอาไว้กับ UIViews และสิ่งอื่น ๆ ที่จะทำให้ประสิทธิภาพลดลงเนื่องจากเป็นส่วนสำคัญของระบบปฏิบัติการ)
Dave

ตามที่ฉันระบุไว้ในความคิดเห็นต่อคำตอบของฉันที่นี่: stackoverflow.com/a/17048668/19679พวกเขาเขียนระบบปฏิบัติการดังนั้นแน่นอนว่าพวกเขากำลังเร่งการเข้าถึงเนื้อหาของเลเยอร์ที่ผสมด้านล่างมุมมองปัจจุบัน เราสามารถมองเห็นบางส่วนของสิ่งที่พวกเขาอาจจะใช้ในส่วนตัว IOSurface API: stackoverflow.com/questions/14135215/... เบลอส์แบบเกาส์เซียนนั้นสามารถทำได้เร็วกว่ากรณีเบลอแบบเกาส์ทั่วไปหากพวกมันมีรัศมีคงที่หรือแม้แต่ใช้การปรับแต่งที่น่าสนใจเช่นภาพอินทิกรัล
Brad Larson

@BradLarson - เพื่อถอดความ Jessica Simpson ... ฉันไม่รู้ว่ามันหมายถึงอะไร แต่มันฟังดูเจ๋ง! แต่อย่างจริงจังคุณกำลังบอกว่าคุณสามารถใช้มุมมองที่โปร่งใสบางส่วนด้วยตัวกรอง aa blur และวางมันบนมุมมองอื่นเพื่อให้ได้ผลนี้
sangony

stackoverflow.com/a/25706250/2308190ทำงานได้อย่างสมบูรณ์แบบสำหรับฉันในครั้งแรกที่ฉันลองและกระชับ
Ben Wheeler

คำตอบ:


134

ทำไมต้องเลียนแบบเอฟเฟกต์? เพียงแค่วาด UIToolbar ด้านหลังมุมมองของคุณ

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

8
ฉันไม่เห็นด้วยกับ crizzwald ฉันไม่คิดว่าเป็นการตีความที่ดีของกฎความคาดหวังของ APple ที่จะทำ
Andrew Johnson

117
ฉันใช้วิธีนี้โดยวิศวกร Apple UIKit ในสัปดาห์นี้ที่ห้องปฏิบัติการ Tech Talks ของพวกเขา แม้ว่าเขาจะไม่รับรองวิธีการนี้อย่างแน่นอน แต่เขาก็ตระหนักถึงความต้องการผลกระทบและการขาด API สาธารณะที่แท้จริงสำหรับเรื่องนี้และกล่าวว่าวิธีนี้เป็นตัวเลือกที่ "ชั่วร้ายน้อยที่สุด" ในตอนนี้และค่อนข้างปลอดภัยตามที่เขียนไว้ โดยเฉพาะเขาบอกว่าอย่าพยายามทำภาพเคลื่อนไหวของframeหรือtransformแถบเครื่องมือ / มุมมองนี้หรืออะไรทำนองนั้นหรือสิ่งเลวร้ายจะเกิดขึ้น เขายังแนะนำอย่างยิ่งให้ยื่นรายงานข้อผิดพลาดของ Radar เกี่ยวกับเรื่องนี้เพื่อสร้างเคสภายในเพื่อให้เราได้รับ API สาธารณะที่แท้จริงสำหรับเอฟเฟกต์นี้!
smileyborg

44
น่าสนใจ ... ดูเหมือนว่าบัญชี @ user2342340 ถูกสร้างขึ้นเพียงเพื่อตอบคำถามนี้โดยไม่ระบุชื่อ ทำให้คุณสงสัยว่านี้ไม่ได้เป็นทางการโพสต์โดยคนที่รู้มากขึ้นกว่าที่เหลือของเราเกี่ยวกับสิ่งเหล่านี้ :)
smileyborg

4
สิ่งนี้ไม่ทำงานบน iPhone 4 ที่ใช้ iOS 7 อาจเป็นเพราะ iPhone 4 เนื่องจากพลังงาน GPU ต่ำเกินไประบบจะไม่เพิ่มเอฟเฟกต์เบลอตามปกติให้กับUITabBarตัวเอง
Ayush Goel

2
ฉันจะทำให้มันไม่ใช่สีขาวได้อย่างไร หากฉันเปลี่ยนสีพื้นหลังสำหรับแถบเครื่องมือแถบเครื่องมือจะไม่เบลอ
Nikita P

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


1
ฉันดูวิดีโอฉันสามารถดูได้ แต่ไม่สามารถคิดได้ว่าจะดาวน์โหลดโค้ดตัวอย่างที่ไหน!
นาธาน H

ฉันไม่เห็นความแตกต่างมากนักเมื่อเทียบกับการเปลี่ยนอัลฟ่าแบบพื้นหลังอย่างง่าย อาจเป็นเพราะฉันกำลังแสดงวิดีโอและพวกเขาต้องการเบลอมากกว่า ...
Ja͢ck

37

จริง ๆ แล้วฉันพนันได้เลยว่ามันจะง่ายกว่า มันอาจจะไม่ทำงานหรือดูเหมือนว่า Apple กำลังดำเนินการอยู่ แต่อาจใกล้เคียงกันมาก

ก่อนอื่นคุณต้องกำหนด CGRect ของ UIView ที่คุณจะนำเสนอ เมื่อคุณทราบแล้วว่าคุณจะต้องคว้าภาพส่วนหนึ่งของ 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;
}

Gaussian Blur - แนะนำ

เมื่อใช้UIImage+ImageEffectsหมวดหมู่ของ Apple ที่มีให้ที่นี่คุณจะได้รับ gaussian blur ที่ดูเหมือนเบลอมากใน iOS 7

กล่องเบลอ

คุณสามารถใช้กล่องเบลอโดยใช้วิธีต่อไปนี้ boxBlurImageWithBlur:หมวดหมู่ UIImageนี้อยู่บนพื้นฐานของ algorythem ที่คุณสามารถหาที่นี่

@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

ตอนนี้คุณกำลังคำนวณพื้นที่หน้าจอให้เบลอส่งผ่านหมวดหมู่เบลอและรับ UII ภาพหน้าจอที่เบลอตอนนี้สิ่งที่เหลืออยู่ก็คือตั้งค่าภาพเบลอเป็นพื้นหลังของมุมมองที่คุณจะนำเสนอ อย่างที่ฉันบอกว่านี่จะไม่เหมาะกับสิ่งที่ Apple กำลังทำอยู่ แต่มันก็ควรจะดูเท่ห์

หวังว่ามันจะช่วย


ดูเหมือนว่าภาพสีน้ำเงินและสีแดงจะเบลอ
Henry

ดูเหมือนว่ามีคนใช้รหัสของคุณเพื่อสร้างโครงการนี้: github.com/alexdrone/ios-realtimeblur/blob/master/RealTimeBlur/แต่น่าเสียดายที่ไม่มีการระบุแหล่งที่มาและพวกเขาได้เพิ่มคำแถลงลิขสิทธิ์ "สงวนลิขสิทธิ์" ไว้ ที่ด้านบน.
Mark Erdmann

@ มาร์คขอบคุณสำหรับหัวขึ้น อย่างไรก็ตามอัลกอริทึมเบลอนี้ไม่ใช่ของฉันเอง ฉันได้กล่าวถึงแล้วว่าฉันได้รับจากที่ใดในโพสต์ด้านบน อย่างที่มันบอกไว้ในโพสต์ของฉัน "สิ่งนี้มีพื้นฐานมาจาก algory พวกเขาที่คุณสามารถหาได้ที่นี่" พร้อมลิงก์ไปยังindieambitions.com/idevblogaday/…ฉันจะส่งข้อความถึงบุคคลนี้อย่างแน่นอนและแจ้งให้พวกเขารู้ว่าพวกเขาขาดการระบุแหล่งที่มา ขอบคุณ
Jeremy Fox

@MarkErdmann ลองดูไฟล์ของคุณเองใน xcode มันมี "สงวนลิขสิทธิ์" เป็นสิ่งทั่วไปที่ xcode เพิ่ม นอกจากนี้ผู้เขียนเพิ่มเพียงเพิ่ม license.md ซึ่งกล่าว lisenced ของตนภายใต้ lisence เอ็มไอที
ซานตาคลอส

อย่าใช้renderInContextใช้ใหม่หรือdrawViewHierarchyInRect: snapshotView:WWDC พูดคุย 216 "การใช้งานการมีส่วนร่วมกับ UI บน iOS7" อ้างว่าการปรับปรุงประสิทธิภาพ 5-15x
bcattle

25

iOS8 ตอบคำถามเหล่านี้

UIVisualEffect

- (instancetype)initWithEffect:(UIVisualEffect *)effect

หรือสวิฟท์:

init(effect effect: UIVisualEffect)


ฉันเดาว่าโซลูชันนี้ไร้ประโยชน์ส่วนใหญ่จนกว่า iOS 9 จะออก แอปพลิเคชั่นส่วนใหญ่ยังคงรองรับ iOS 7 และโซลูชันนี้ไม่รองรับ
Dmitry Sobolev

จริงจริงคุณสามารถใช้สิ่งนี้ได้ในตอนนี้: github.com/nicklockwood/FXBlurView
Adam Waite

ฉันใช้สิ่งนี้กับ Xcode 6 toolchain กับ iOS8 และใช้งานได้ดี ฉันพยายามใช้งานโดยใช้ CPU แต่ทำงานได้ช้ากว่าวิธีนี้อย่างเห็นได้ชัด
Jon

ทำไมต้องโค๊ดเมื่อ Xcode มีอยู่ในกระดานเรื่องราวเอง !!!!! ขอบคุณ @AdamWaite
Mihir Oza

20

ฉันเพิ่งเขียนคลาสย่อยเล็กน้อยของ UIView ที่มีความสามารถในการผลิตเบลอ iOS 7 แบบดั้งเดิมบนมุมมองที่กำหนดเอง มันใช้ UIToolbar แต่วิธีที่ปลอดภัยสำหรับการเปลี่ยนเฟรมขอบเขตสีและอัลฟาด้วยภาพเคลื่อนไหวแบบเรียลไทม์

โปรดแจ้งให้เราทราบหากคุณสังเกตเห็นปัญหาใด ๆ

https://github.com/ivoleko/ILTranslucentView

ตัวอย่าง ILTranslucentView


ฉันลองวิธีอื่นแล้ว (เช่นการเพิ่ม UIToolbar ด้วยตนเองหรือประเภท UIImage + ImageEffects.h ของ Apple); คุณเป็นทางออกที่ดีที่สุดและง่ายที่สุด ขอบคุณ!
Yunus Nedim Mehel

4
มันตอบสนองกับการดาวน์โหลด iOS 7.0.3 ใหม่ดีแค่ไหน? คลาสอื่น ๆ ที่ใช้เทคนิคนี้แสดงผลไม่ถูกต้องอีกต่อไป: [
achi

@achi ฉันไม่ได้สังเกตเห็นปัญหาใด ๆ กับ iOS 7.0.3
Ivo Leko

คุณรู้หรือไม่ว่าแอพใด ๆ ที่เคลื่อนไหวโดยใช้วิธีการของคุณและได้รับการยอมรับจาก Apple?
Brad Goss

ไงพวก ใช่แอปที่ใช้คลาสนี้จะได้รับการอนุมัติจาก Apple!
Ivo Leko

10

มีข่าวลือว่าวิศวกรของ Apple อ้างว่าเพื่อให้นักแสดงคนนี้กำลังอ่านข้อมูลจากบัฟเฟอร์ของ gpu โดยตรงซึ่งทำให้เกิดปัญหาด้านความปลอดภัยซึ่งเป็นสาเหตุที่ยังไม่มี API สาธารณะให้ทำ


6
หากนี่เป็นเรื่องจริงนั่นก็คือ - โดยไกล - ทางออกที่เลวร้ายที่สุด
elslooo

2
aaaaaand ความพร่ามัวถูกลบออกจาก iOS 7
Code Guru

3
มันถูกลบออกเฉพาะในอุปกรณ์ที่เห็นปัญหาด้านประสิทธิภาพ
โคดีซี

24
โพสต์นี้เป็นที่มาของข่าวลือหรือไม่? :)
Jano

11
ข่าวลือนั้นน่าจะเป็นสองชั้น OpenGL ES 2.0 บน iOS อนุญาตให้คุณอ่านและเขียนไปยัง framebuffers โดยไม่มีความเสี่ยงด้านความปลอดภัย การเบลอทำได้โดยใช้ GLSL shaders ซึ่งเป็นสาเหตุที่ทำให้มันทำงานเร็ว
bentford

7

นี่เป็นวิธีการแก้ปัญหาที่คุณสามารถเห็นได้ใน vidios ของ 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

คุณสามารถค้นหาคำตอบของคุณได้จาก DEMO ของ apple ในหน้านี้: WWDC 2013 , ค้นหาและดาวน์โหลดรหัสตัวอย่าง UIImageEffects

จากนั้นด้วยรหัสของ @Jeremy Fox ฉันเปลี่ยนเป็น

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

หวังว่านี่จะช่วยคุณได้


7

นี่เป็นวิธีที่ง่ายมากในการทำ: https://github.com/JagCesar/iOS-blur

เพียงแค่คัดลอกเลเยอร์ของ UIToolbar และคุณทำเสร็จแล้ว AMBlurView ทำเพื่อคุณ โอเคมันไม่พร่ามัวเหมือนศูนย์ควบคุม แต่มันพร่ามัวพอ

จำไว้ว่า iOS7 อยู่ภายใต้ NDA


6

ทุกการตอบกลับที่นี่ใช้vImageBoxConvolve_ARGB8888ฟังก์ชั่นนี้ช้ามากจริง ๆ ก็ดีถ้าประสิทธิภาพไม่ได้เป็นข้อกำหนดที่มีลำดับความสำคัญสูง แต่ถ้าคุณใช้สิ่งนี้เพื่อเปลี่ยนระหว่างตัวควบคุมมุมมองสองตัว (ตัวอย่างเช่น) วิธีนี้หมายถึงเวลามากกว่า 1 อย่างที่สองหรืออาจมากกว่านั้นเป็นเรื่องที่แย่มากสำหรับประสบการณ์การใช้งานแอปพลิเคชันของคุณ

หากคุณต้องการปล่อยให้การประมวลผลภาพทั้งหมดไปยัง GPU (และคุณควร) คุณจะได้รับเอฟเฟกต์ที่ดีขึ้นและเวลาที่ยอดเยี่ยมในการปัดเศษ 50ms (สมมติว่าคุณมีเวลา 1 วินาทีในวิธีแรก) ดังนั้นลองทำ .

ดาวน์โหลดแรก GPUImage กรอบ (BSD ได้รับใบอนุญาต) ที่นี่

ถัดไปเพิ่มคลาสต่อไปนี้ (.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

ใช่สนุกกับวิธีที่เร็วกว่านี้;)


4

คุณสามารถลองใช้มุมมองที่กำหนดเองของฉันซึ่งมีความสามารถในการเบลอพื้นหลัง มันทำเช่นนี้โดยแกล้งทำภาพพื้นหลังและเบลอเหมือนในรหัส WWDC ของ Apple มันง่ายมากที่จะใช้

ฉันได้ปรับปรุงบางอย่างเพื่อปลอมความเบลอแบบไดนามิกโดยไม่สูญเสียประสิทธิภาพ พื้นหลังของมุมมองของฉันคือ scrollView ซึ่งเลื่อนด้วยมุมมองดังนั้นจึงให้เอฟเฟกต์เบลอสำหรับส่วนที่เหลือของการควบคุม

ดูตัวอย่างและรหัสในGitHub ของฉัน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.