新部落格地址:blog.songchunmin.com
0. Core Image
作為設計和體驗方面的領導者,蘋果自己對圖片效果和圖片處理的支援一定是非常好的,在iOS平臺上,5.0之後就出現了Core Image的API。Core Image的API被放在CoreImage.framework庫中。
在iOS和OS X平臺上,Core Image都提供了大量的濾鏡(Filter),這也是Core Image庫中比較核心的東西之一。按照官方文件記載,在OS X上有120多種Filter,而在iOS上也有90多。
下面是一段Core Image做模糊的示例程式碼:
1 2 3 4 5 6 7 8 |
CIContext *context = [CIContext contextWithOptions:nil]; CIImage *image = [CIImage imageWithContentsOfURL:imageURL];
CIFilter *filter = [CIFilter filterWithName:@ "CIGaussianBlur" ];
[filter setValue:image forKey:kCIInputImageKey];
[filter setValue:@2.0f forKey: @ "inputRadius" ];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef outImage = [context createCGImage: result fromRect:[result extent]]; UIImage * blurImage = [UIImage imageWithCGImage:outImage];
|
這裡可以看到,Core Image為了做得比較靈活,Filter都是按字串的名字去建立的,比如高斯模糊濾鏡就是“CIGaussianBlur”,這裡有一個官方列表可以參看。
除了這裡提到的多種Filter之外,Core Image還提供了CIDetector等類,可以支援人臉識別等,在OS X上Core Image也做了更多支援。
1. GPUImage
除了蘋果官方提供的之外,第三方也有這方面圖片處理的工具。一個叫Brad Larson的老兄就搞了一套叫做
同樣是做高斯模糊,用GPUImage可以這樣:
1 2 3 4 |
GPUImageGaussianBlurFilter * blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
blurFilter.blurRadiusInPixels = 2.0;
UIImage * image = [UIImage imageNamed:@ "xxx" ];
UIImage *blurredImage = [blurFilter imageByFilteringImage:image];
|
至少看起來,程式碼上比使用Core Image的情況簡單得多。
2. vImage
其實,說完上面的Core Image和GPUImage,很多情況下就已經足夠用了。下面我們再來看一個,那就是vImage。vImage也是蘋果推出的庫,在Accelerate.framework中。
Accelerate這個framework主要是用來做數字訊號處理、影象處理相關的向量、矩陣運算的庫。我們可以認為我們的影象都是由向量或者矩陣資料構成的,Accelerate裡既然提供了高效的數學運算API,自然就能方便我們對影象做各種各樣的處理。
基於vImage我們可以根據影象的處理原理直接做模糊效果,或者使用現有的工具。UIImage+ImageEffects是個很好的影象處理庫,看名字也知道是對UIImage做的分類擴充套件。這個工具被廣泛地使用著。
3. UIVisualEffectView(iOS8系統之後使用,有即時效果)
在iOS 8後,蘋果開放了不少建立特效的介面,其中就包括建立毛玻璃(blur)的介面。
通常要想建立一個特殊效果(如blur效果),可以建立一個UIVisualEffectView檢視物件,這個物件提供了一種簡單的方式來實現複雜的視覺效果。這個可以把這個物件看作是效果的一個容器,實際的效果會影響到該檢視物件底下的內容,或者是新增到該檢視物件的contentView中的內容。
我們舉個例子來看看如果使用UIVisualEffectView:
let bgView: UIImageView = UIImageView(image: UIImage(named: "visual")) bgView.frame = self.view.bounds self.view.addSubview(bgView) let blurEffect: UIBlurEffect = UIBlurEffect(style: .Light) let blurView: UIVisualEffectView = UIVisualEffectView(effect: blurEffect) blurView.frame = CGRectMake(50.0, 50.0, self.view.frame.width - 100.0, 200.0) self.view.addSubview(blurView)
這段程式碼是在當前檢視控制器上添加了一個UIImageView作為背景圖。然後在檢視的一小部分中使用了blur效果。
我們可以看到UIVisualEffectView還是非常簡單的。需要注意是的,不應該直接新增子檢視到UIVisualEffectView檢視中,而是應該新增到UIVisualEffectView物件的contentView中。
另外,儘量避免將UIVisualEffectView物件的alpha值設定為小於1.0的值,因為建立半透明的檢視會導致系統在離屏渲染時去對UIVisualEffectView物件及所有的相關的子檢視做混合操作。這不但消耗CPU/GPU,也可能會導致許多效果顯示不正確或者根本不顯示。
我們在上面看到,初始化一個UIVisualEffectView物件的方法是UIVisualEffectView(effect: blurEffect),其定義如下:
init(effect effect: UIVisualEffect)
這個方法的引數是一個UIVisualEffect物件。我們檢視官方文件,可以看到在UIKit中,定義了幾個專門用來建立視覺特效的,它們分別是UIVisualEffect、UIBlurEffect和UIVibrancyEffect。它們的繼承層次如下所示:
NSObject | -- UIVisualEffect | -- UIBlurEffect | -- UIVibrancyEffect
UIVisualEffect是一個繼承自NSObject的建立視覺效果的基類,然而這個類除了繼承自NSObject的屬性和方法外,沒有提供任何新的屬性和方法。其主要目的是用於初始化UIVisualEffectView,在這個初始化方法中可以傳入UIBlurEffect或者UIVibrancyEffect物件。
一個UIBlurEffect物件用於將blur(毛玻璃)效果應用於UIVisualEffectView檢視下面的內容。如上面的示例所示。不過,這個物件的效果並不影響UIVisualEffectView物件的contentView中的內容。
UIBlurEffect主要定義了三種效果,這些效果由列舉UIBlurEffectStyle來確定,該列舉的定義如下:
enum UIBlurEffectStyle : Int { case ExtraLight case Light case Dark }
其主要是根據色調(hue)來確定特效檢視與底部檢視的混合。
與UIBlurEffect不同的是,UIVibrancyEffect主要用於放大和調整UIVisualEffectView檢視下面的內容的顏色,同時讓UIVisualEffectView的contentView中的內容看起來更加生動。通常UIVibrancyEffect物件是與UIBlurEffect一起使用,主要用於處理在UIBlurEffect特效上的一些顯示效果。接上面的程式碼,我們看看在blur的檢視上新增一些新的特效,如下程式碼所示:
let vibrancyView: UIVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect)) vibrancyView.setTranslatesAutoresizingMaskIntoConstraints(false) blurView.contentView.addSubview(vibrancyView) var label: UILabel = UILabel() label.setTranslatesAutoresizingMaskIntoConstraints(false) label.text = "Vibrancy Effect" label.font = UIFont(name: "HelveticaNeue-Bold", size: 30) label.textAlignment = .Center label.textColor = UIColor.whiteColor() vibrancyView.contentView.addSubview(label)
vibrancy特效是取決於顏色值的。所有新增到contentView的子檢視都必須實現tintColorDidChange方法並更新自己。需要注意的是,我們使用UIVibrancyEffect(forBlurEffect:)方法建立UIVibrancyEffect時,引數blurEffect必須是我們想加效果的那個blurEffect,否則可能不是我們想要的效果。
另外,UIVibrancyEffect還提供了一個類方法notificationCenterVibrancyEffect,其宣告如下:
class func notificationCenterVibrancyEffect() -> UIVibrancyEffect!
這個方法建立一個用於通知中心的Today擴充套件的vibrancy特效。