iOS 中的CIFilter(基礎用法)

本文大部份內容均來自:Core Image Tutorial: Getting Startedswift

Core Image 是一個很強大的庫,PS圖片時用到的各類濾鏡就是在這個庫中。而咱們建立二維碼、建立條形碼用這裏的濾鏡,只須要短短几行代碼就能夠擼出來(後面會講怎麼用CIFilter繪製二維碼、條形碼)。bash

文中有提到在iOS 8 上,CIFilter 的API 裏有126種濾鏡可用,在 同時期 Mac OS 上有160多種濾鏡可用;而在iOS 9.3 上,我測試可使用的濾鏡已經達到174種,Mac OS上確定更多咯。dom

如何知道有哪些濾鏡效果呢?

我一度想查找API裏一共提供了多少種濾鏡,每種濾鏡分別有什麼效果。多是種類實在是太多,不一樣的濾鏡又有不少不一樣的參數(參數名,參數各類均可能不一樣)設置,基本沒有介紹每種濾鏡的文章。性能

下面提供獲取每種濾鏡名稱以及其屬性的方法:測試

// swift 版
let properties = CIFilter.filterNamesInCategory(kCICategoryBuiltIn) 
println(properties)
for fileterName : String in properties {
    let filter = CIFilter(name: fileterName)
  // 濾鏡的參數
    print(filter?.attributes)
}

// Objective-C版 (因轉換成OC版的太簡單,略😃)
複製代碼

準備工做

在iOS 中使用濾鏡效果,須要用到的重要類有三個:優化

  • CIContext. 圖片的全部處理工做都是在 CIContext中作的. 它有點相似於 Core Graphics 和 OpenGL context.
  • CIImage. 這個類持有圖片數據。能夠用UIImage或者圖片路徑或者data來建立一個CIImage對象。
  • CIFilter.濾鏡類,它有一個用來設置各類參數的字典,API已經提供了setValue: forKey:方法來設置參數。

基礎用法

對一張圖使用一個濾鏡效果,總結起來須要四步:ui

  1. 建立一個CIImage對象 .CImage 有不少初始化方法。譬如:CIImage(contentsOfURL:), CIImage(data:), CIImage(CGImage:), CIImage(bitmapData:bytesPerRow:size:format:colorSpace:),用的最多的是CIImage(contentsOfURL:)。
  2. 建立一個CIContext. CIContext 多是基於CPU,也多是基於GPU的。因此建立CIContext會消耗資源,影響性能,咱們應該儘量多的複用它。將處理事後的圖片數據,輸出爲CIImage的時候會用到CIContext。
  3. 建立一個濾鏡. 建立好濾鏡後,咱們須要爲其設置參數。有的濾鏡要設置的參數比較多,有的濾鏡卻不須要設置參數。
  4. 獲取filter output. 濾鏡會輸出一個CIImage對象,用CIContext 能夠將CIImage轉換爲UIImage。

這裏有一段示例代碼:spa

// 1.獲取本地圖片路徑
let fileURL = NSBundle.mainBundle().URLForResource("image", withExtension: "png") 
// 2.建立CIImage對象
let beginImage = CIImage(contentsOfURL: fileURL!) 
// 3. 建立濾鏡
// 建立一個棕櫚色濾鏡
let filter = CIFilter(name: "CISepiaTone")!
filter.setValue(beginImage, forKey: kCIInputImageKey)
// 設置輸入的強度係數
filter.setValue(0.5, forKey: kCIInputIntensityKey)
// 4.將CIImage轉換爲UIImage 
//  其實在這個API內部用到了CIContext,而它就是在每次使用的使用去建立一個新的CIContext,比較影響性能
let newImage = UIImage(CIImage: filter.outputImage!)
self.imageView.image = newImage
複製代碼

注意點code

由於let newImage = UIImage(CIImage: filter.outputImage)內部會每次都建立一個CIContext,這裏咱們能夠優化。用上面的方式建立的UIImage ,咱們將其轉換爲NSData的時候,NSData爲nil,緣由是:May return nil if image has no CGImageRef or invalid bitmap format,這代表咱們更應該優化。orm

將上面的第四步替換成以下代碼:

        // 1 建立一個CIContext,只須要將這個context對象存起來,其餘地方調用便可。
        let context = CIContext(options:nil)
        // 2 用CIContext將CIImage轉換爲CGImage
        let cgimg = context.createCGImage(filter.outputImage!, fromRect: filter.outputImage!.extent)
        // 3 將CGImage轉換爲UIImage
        let newImage = UIImage(CGImage: cgimg)
        self.imageView.image = newImage
複製代碼

將濾鏡處理後的圖片保存進相冊

之前咱們可能會用 UIImageWriteToSavedPhotosAlbum()。 ALAssetsLibrary 提供了將CGImage直接保存到相冊的示例方法:writeImageToSavedPhotosAlbum,只惋惜它到iOS 9.0 就棄用了☹️,當工程的最低兼容版本大於9.0時,編譯器會給你一個警告,告訴你該用什麼方法替換。

@IBAction func savePhoto(sender: UIButton) {
        // 1 獲取濾鏡輸出的圖片
        let imageToSave = filter.outputImage!
        // 2 建立一個使用CPU渲染器的CIContext
        let softwareContext = CIContext(options: [kCIContextUseSoftwareRenderer : true])
        // 3 將CIImage轉換爲CGImage
        let cgimage = softwareContext.createCGImage(imageToSave, fromRect: imageToSave.extent)
        // 4 使用 ALAssetsLibrary 保存到相冊
        let library = ALAssetsLibrary()
        library.writeImageToSavedPhotosAlbum(cgimage, metadata: imageToSave.properties, completionBlock: nil) 
    }
複製代碼

組合濾鏡

咱們能夠將多種濾鏡效果組合起來,建立一個新的濾鏡效果,這比將一個個的濾鏡加到圖片上,在輸出要有效率的多。

這裏有一個示例:

    func oldPhoto(img: CIImage, withAmount intensity: Float) -> CIImage {
        
        // 1 建立一個棕色濾鏡
        let sepiaFilter = CIFilter(name: "CISepiaTone")
        sepiaFilter?.setValue(img, forKey: kCIInputImageKey)
        sepiaFilter?.setValue(intensity, forKey: kCIInputIntensityKey)
        
        // 2 建立一個隨機點濾鏡
        let randomFilter = CIFilter(name: "CIRandomGenerator")
        
        // 3
        let lighten = CIFilter(name: "CIColorControls")
        lighten?.setValue(randomFilter?.outputImage, forKey: kCIInputImageKey)
        lighten?.setValue(1 - intensity, forKey: "inputBrightness")
        lighten?.setValue(0, forKey: "inputSaturation")
        
        // 4 將濾鏡輸出裁剪成原始圖片大小
        let croppedImage = lighten?.outputImage?.imageByCroppingToRect(beginImage.extent)
        
        // 5
        let composite = CIFilter(name: "CIHardLightBlendMode")
        composite?.setValue(sepiaFilter?.outputImage, forKey: kCIInputImageKey)
        composite?.setValue(croppedImage, forKey: kCIInputBackgroundImageKey)
        
        // 6
        let vignette = CIFilter(name: "CIVignette")
        vignette?.setValue(composite?.outputImage, forKey: kCIInputImageKey)
        vignette?.setValue(intensity * 2, forKey: "inputIntensity")
        vignette?.setValue(intensity * 30, forKey: "inputRadius")
        
        // 7
        return (vignette?.outputImage)!
    }
複製代碼

別人的圖

代碼效果圖

爲毛本身家的效果圖是這個鬼樣子,別人家的效果圖那麼好看!😒 😒

用濾鏡效果建立二維碼、條形碼

建立條形碼

+ (UIImage *)barCodeImageWithInfo:(NSString *)info
{
    // 建立條形碼
    CIFilter *filter = [CIFilter filterWithName:@"CICode128BarcodeGenerator"];
    
    // 恢復濾鏡的默認屬性
    [filter setDefaults];
    // 將字符串轉換成NSData
    NSData *data = [info dataUsingEncoding:NSUTF8StringEncoding];
    // 經過KVO設置濾鏡inputMessage數據
    [filter setValue:data forKey:@"inputMessage"];
    // 得到濾鏡輸出的圖像
    CIImage *outputImage = [filter outputImage];
    // 將CIImage 轉換爲UIImage
    UIImage *image = [UIImage imageWithCIImage:outputImage];
    
    // 若是須要將image轉NSData保存,則得用下面的方式先轉換爲CGImage,不然NSData 會爲nil
    //    CIContext *context = [CIContext contextWithOptions:nil];
    //    CGImageRef imageRef = [context createCGImage:outputImage fromRect:outputImage.extent];
    //
    //    UIImage *image = [UIImage imageWithCGImage:imageRef];
    
    return image;
}
複製代碼

條形碼

建立二維碼

+ (UIImage *)qrCodeImageWithInfo:(NSString *)info  width:(CGFloat)width
{
    if (!info) {
        return nil;
    }
    
    NSData *strData = [info dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
    //建立二維碼濾鏡
    CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    [qrFilter setValue:strData forKey:@"inputMessage"];
    [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];
    CIImage *qrImage = qrFilter.outputImage;
    //顏色濾鏡
    CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"];
    [colorFilter setDefaults];
    [colorFilter setValue:qrImage forKey:kCIInputImageKey];
    [colorFilter setValue:[CIColor colorWithRed:0 green:0 blue:0] forKey:@"inputColor0"];
    
![Uploading 1A4978EE-427F-4804-B536-1D5C330A0578_306160.png . . .][colorFilter setValue:[CIColor colorWithRed:1 green:1 blue:1] forKey:@"inputColor1"];
    CIImage *colorImage = colorFilter.outputImage;
    //返回二維碼
    CGFloat scale = width/31;
    UIImage *codeImage = [UIImage imageWithCIImage:[colorImage imageByApplyingTransform:CGAffineTransformMakeScale(scale, scale)]];
    return codeImage;
}
複製代碼

二維碼

CIFilter初體驗就先到這裏了,Have Fun!

相關文章
相關標籤/搜索