CIFilter_看了这个,你就可以打造自己的美图秀秀

上篇文章iOS_最全的二维码篇说要给大家简绍一下强大而好玩工具CIFilter,所以这今天晚上给大家分享一个demo。我保证你看了这篇文章之后,肯定能做出自己的美图工具,我发誓(虽然并没卵用)。

CIFilter,其实就是一个滤镜。喜欢摄影的小伙伴,可能接触过PS,而接触过PS的小伙伴,对滤镜肯定不陌生。而且有了解相关知识的小伙伴,对于颜色和图片处理的认知也一定信手捏来。什么RGB,什么CMYK,什么灰度图片,什么高斯模糊,什么锐化,什么对比度,什么饱和度,什么颜色通道,为什么值在255之间等等。我为什么知道这些,其实小Jorn我大一的时候,刚上大学,课不是很多,时间充足,那时候,都还不知道LOL(呵呵,现在,此处省略1W字),还带着高中的稚气和志气。想想要学点啥一技之长。记得高中时候,有次去拍一寸照,看那sb老板,不懂PS,硬是给我照片乱修。结果照片老丑,还硬坑我20块钱。所以大学就想到自己学学PS,在处理照片的时候可以自己修。而且,PS还可以做很多平面设计。说不定以后可以去做设计的工作。一个好的设计师,薪资还是很高的(_)。所以自己学了一年多的PS(堪称大神了,然并卵),后来学的差不多了。海报设计,网页设计,UI设计,还有其他各种设计,图文排版,图片处理,婚纱处理,P图等什么滴都自己做过(厉害吧)。大二的时候又学了一年的AI,后来还想学AE来着(因为大学嘛,越到后来,你懂得。游戏也开始玩起来了)。学了PS和AI,其实我还是觉得很不错的,不只在一个地方看到,PS和AI就像左右手,这也是做平面设计的工作者必备的两技能。一个负责位图,一个负责矢量图,功能都超强大。现在iOS上用的icon基本都是用这两工具设计的。虽然现在不慎混到了程序猿的大流。不过想想懂这也不是无可用武之地,至少在图片处理,颜色的认知上还有挺有帮助的(呵呵,安慰一下自己)。(扯远了。。。)

言归正传,你学会使用CIFilter,你就可以随意处理你想要的效果。系统给我们提供的滤镜种类是非常的多,不是十几个,是几十个。没错!

CoreImage是个非常强大框架,集图片的几乎所有操作编辑于一身,CIFilter只是其中的一个工具,主要作用是给图片渲染不同的效果
CIFilter的种类很多,所以苹果的官方文档也只能给出部分常用的种类的说明。
官方文档给出的部分说明:点击这里
虽然官方文档很简洁,但国外的大神们已经证明这是个相当强悍的框架,
不仅功能强大,而且可以直接使用GPU,效率奇高,甚至可以实时的对视频进行渲染。

下面让我们来看看,如何具体使用它:
首先你需要导入CoreImage.framework框架;进行Mac(不是iOS)开发的同学请导入QuartzCore.framework框架,包含在其中了。
然后我们先来看看3个主要的类:
CIContext:它与CoreGraphicsOpenGL context类似,所有CoreImage的处理流程都通过它来进行;
CIImage:它用来存放图片数据,可以通过UIImage,图片文件或像素数据创建;
CIFilter:通过它来定义过滤器的详细属性。
CIContext有两种初始化方法,分别对应GPUCPU

创建基于GPU的CIContext对象
context = [CIContext contextWithOptions: nil];
创建基于CPU的CIContext对象

context = [CIContext contextWithOptions: [NSDictionarydictionaryWithObject:[NSNumber numberWithBool:YES]
    forKey:kCIContextUseSoftwareRenderer]];

一般采用第一种基于GPU的,因为效率要比CPU高很多,但是要注意的是基于GPU的CIContext对象无法跨应用访问。 比如你打开UIImagePickerController要选张照片进行美化,如果你直接在UIImagePickerControllerDelegate的委托方法里调用CIContext对象进行处理,那么系统会自动将其降为基于CPU的,速度会变慢,所以正确的方法应该是在委托方法里先把照片保存下来,回到主类里再来处理。

CIFilter的强大之处在于,可以叠加来得到多种效果。看过iOS_最全的二维码篇这篇文章的小伙伴肯定知道了什么叫叠加,其实如果你按那篇文章我说的练习一下,你就会发现,得到的图片也还是不过清晰。因为,二维码生成的原图太小,放大就很模糊。其实我在用PS处理手机拍的图片时,一开始少不了这三步,补点光,太暗;增加的对比度,不够鲜明;锐化一下,细节不过清晰。对,就是锐化一下。等下会让你获得一副清晰的二维码图。

首先让你知道,怎么查看到底有哪些滤镜:

        /* Categories */
//        public let kCICategoryDistortionEffect: String ///失真效果
//        public let kCICategoryGeometryAdjustment: String ///几何调整
//        public let kCICategoryCompositeOperation: String ///复合操作
//        public let kCICategoryHalftoneEffect: String ///半色调效果
//        public let kCICategoryColorAdjustment: String ///颜色调整
//        public let kCICategoryColorEffect: String ///颜色效果
//        public let kCICategoryTransition: String ///翻转
//        public let kCICategoryTileEffect: String ///瓦片效果
//        public let kCICategoryGenerator: String ///生成器
//        @available(iOS 5.0, *)
//        public let kCICategoryReduction: String ///削减
//        public let kCICategoryGradient: String ///梯度
//        public let kCICategoryStylize: String ///风格
//        public let kCICategorySharpen: String ///锐化
//        public let kCICategoryBlur: String ///模糊
//        public let kCICategoryVideo: String ///视频
//        public let kCICategoryStillImage: String ///静态图片
//        public let kCICategoryInterlaced: String ///交叉
//        public let kCICategoryNonSquarePixels: String ///非方形像素
//        public let kCICategoryHighDynamicRange: String ///高动态范围
//        public let kCICategoryBuiltIn: String ///内建
//        @available(iOS 9.0, *)
//        public let kCICategoryFilterGenerator: String ///滤镜生成器

这是系统含有的所有大类。
想知道有哪些filter类型或想查找想要的filter类型,可以通过先查找大的分类(如上),然后在查找子项。

        let names = CIFilter.filterNames(inCategory: kCICategoryGenerator) ///kCICategoryGenerator大类
        print(names)

这样就会输出该大类包含的所有滤镜。如上会输出所有的生成器类型CIFilter种类:

 ///生成器大类所包含的所有生成器子类,如:"`CICode128BarcodeGenerator`"(条形码生成器),"CIQRCodeGenerator"(二维码生成器)
//        ["CIAztecCodeGenerator",
//         "CICheckerboardGenerator",
//         "CICode128BarcodeGenerator", ///条形码生成器
//         "CIConstantColorGenerator",
//         "CILenticularHaloGenerator",
//         "CIPDF417BarcodeGenerator",
//         "CIQRCodeGenerator", ///二维码生成器
//         "CIRandomGenerator",
//         "CIStarShineGenerator",
//         "CIStripesGenerator",
//         "CISunbeamsGenerator"]

然后就可以创建滤镜对象了,有两方法,含参数的仅iOS8之后可用,iOS上不设输入参数,系统会使用默认值,但是mac是会报错,输入参数不明确:

/** Creates a new filter of type 'name'.
         On OSX, all input values will be undefined.
         On iOS, all input values will be set to default values. */
        /// 要是是mac开发,创建filter对象必须提供输入参数,iOS可以忽略,系统会使用默认值。
        //init?(name: String)
        //@available(iOS 8.0, *) ///iOS 8.0 之后
        //init?(name: String, withInputParameters params: [String : Any]?)

看看该滤镜需要设置那些输入参数,如此:

        let filter = CIFilter(name: "CIQRCodeGenerator")
        let inpoutkeys = filter?.inputKeys ///查看这个filter的所有输入参数
        let outputKeys = filter?.outputKeys ///查看这个filter的所有输出参数
        
        print("inpoutkeys:",inpoutkeys)
        print("outputKeys:",outputKeys)

设置参数用KVC来设置,常用的key,系统已经作为常量给出,可以cmd加鼠标左键点击CIFilter类名进去查看。
如上,二维码生成器滤镜需要量输入参数:

///eg.1 ///示例代码KVO
        /// 1. 实例化二维码滤镜
        let filter = CIFilter(name: "CIQRCodeGenerator")///二维码
        
        /// 2. 恢复滤镜的默认属性 ///值得注意
        filter?.setDefaults()
        
        /// 3. 将字符串转换成二进制数据,(生成二维码所需的数据)
        let string = "hello word"
        let data = string.data(using: String.Encoding.utf8)///Swift 3.0
        
        /// 4. 通过KVO把二进制数据添加到滤镜inputMessage中
        filter?.setValue(data, forKey: "inputMessage")
        filter?.setValue("H", forKey: "inputCorrectionLevel")
        
        /// 5. 获得滤镜输出的图像
        let outputImage = filter?.outputImage ///CIImage
        
        /// 6. 将CIImage转换成UIImage,并放大显示
        //let originQRCodeImage = UIImage(ciImage: outputImage!, scale: 0.07, orientation: UIImageOrientation.up) ///原生二维码图片 ///这样将图片放大会变得模糊

这样得到的originQRCodeImage是模糊的,把scale设为一时得到实际大小,但太小。在上篇文章我提过,需要进行重绘(效果80分)。这里我们可以使用缩放滤镜来缩放。生产高质量的、按比例缩放的源图像的版本(这是文档说明,然我并没发现有啥牛掰,还是模糊)。
CIFilter为"CILanczosScaleTransform"(兰索斯缩放变化滤镜),但为了达到彩色的效果我们先把颜色滤镜加上,CIFliter为"CIFalseColor"(伪色滤镜):

let colorFilter = CIFilter(name: "CIFalseColor")///颜色滤镜
        colorFilter!.setDefaults()
        colorFilter!.setValue(outputImage
            , forKey:kCIInputImageKey)
        
        colorFilter!.setValue(CIColor(red: 33.0 / 225.0, green: 192.0 / 225.0, blue: 174.0 / 225.0, alpha: 1.0), forKey:"inputColor0")///二维码元素(像素)
        colorFilter!.setValue(CIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1), forKey:"inputColor1")///背景
        
        let colorImgae = colorFilter!.outputImage
 let scaleFilter = CIFilter(name: "CILanczosScaleTransform") ///兰索斯缩放变化滤镜
        scaleFilter?.setDefaults()
        scaleFilter?.setValue(colorImgae, forKey: kCIInputImageKey)
        scaleFilter?.setValue(1.0, forKey: kCIInputScaleKey)
        scaleFilter?.setValue(1.0, forKey: kCIInputAspectRatioKey)
        let scaleImage = scaleFilter?.outputImage

所以通过添加锐化滤镜来锐化一下,CIFilter为"CISharpenLuminance"(亮度锐化,对光度有作用,度色度没影响):

 let sharpenFilter = CIFilter(name: "CISharpenLuminance") ///细节锐化滤镜
        ///It operates on the luminance of the image; the chrominance of the pixels remains unaffected.
        sharpenFilter?.setDefaults()
        sharpenFilter?.setValue(scaleImage, forKey: kCIInputImageKey)
        sharpenFilter?.setValue(10.0, forKey: kCIInputSharpnessKey)
        let sharpenImage = sharpenFilter?.outputImage

最后得到图片:

let newQRCodeImage = UIImage(ciImage: sharpenImage!)
        let imgBtn = UIButton(type: .custom)
        imgBtn.frame = self.view.frame
        imgBtn.setImage(newQRCodeImage, for: .normal)
        self.view.addSubview(imgBtn)

通过参数的设置,得到的图片效果70分;

而在进行重绘后,再进行锐化处理的话,你就会发现效果是真的不错(95分)。

因为升为了Switft3.0代码,所以代码需要少量修改。主要就是Swift3.0把CoreGraphics的全局方法改为了实例方法,


func createUIimageWithCGImage(ciImage image: CIImage, widthAndHeightValue wh: CGFloat) -> CIImage {
        let ciRect = image.extent.integral///根据容器得到适合的尺寸
        let scale = min(wh / ciRect.width, wh / ciRect.height)
        
        ///获取bitmap
        let width  = size_t(ciRect.width * scale)

        let height  = size_t(ciRect.height * scale)
        let cs = CGColorSpaceCreateDeviceGray()///灰度颜色通道 ///CGColorSpaceRef
        
        let info_UInt32 = CGImageAlphaInfo.none.rawValue
        let bitmapRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: info_UInt32)
        
        let contex = CIContext(options: nil) ///  创建基于GPU的CIContext对象,性能和效果更好
        let bitmapImageRef = contex.createCGImage(image, from: CGRect(x: ciRect.origin.x, y: ciRect.origin.y, width: ciRect.size.width, height: ciRect.size.height)) ///CGImageRef
        
        ///swift 3.0, 把全局方法改为了实例方法
        bitmapRef!.interpolationQuality = CGInterpolationQuality.high///写入质量高,时间长
        bitmapRef!.scaleBy(x: scale, y: scale) ///调整“画布”的缩放
        bitmapRef?.draw(bitmapImageRef!, in: ciRect, byTiling: true)///绘制图片
        
        ///保存
        let scaledImage = bitmapRef!.makeImage() ///cgimage
        
        ///bitmapRef和bitmapImageRef不用主动释放,Core Foundation自动管理
        //let originImage = UIImage(CGImage: scaledImage!) ///原生灰度图片(灰色)
        
        let ciImage = CIImage(cgImage: scaledImage!) ///ciimage
        //let newQRCodeImage = UIImage(cgImage: scaledImage!) ///uiimage
        
        return ciImage
    }

附录:

///附:你要是细心,或者有点好奇心,你可能会问,为什么我们看到的二维码中间都有一个小图片,
///确实现在的大多二维码生成工具都喜欢中间贴上一个小图,但是上述生成的二维码并没有,
///其实这很简单,这也是我没有在这个小问题给出示例的原因。其实二维码在缺少小部分的情况下,并不影响存储信息的完整性
///所以小图片是另外加上去的,只是遮掉了一小块二维码内容,这并不影响什么。
///然而在一张图上添加另一张图,相信你也觉得这并不是什么问题。自己试试吧。
///如:用quartz2D 、drawImga的方法即可。

下图:1.锐化;2.重绘;3.重绘+锐化


1.锐化;2.重绘;3.重绘+锐化.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容