上篇文章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
:它与CoreGraphics
和OpenGL context
类似,所有CoreImage
的处理流程都通过它来进行;
CIImage
:它用来存放图片数据,可以通过UIImage
,图片文件或像素数据创建;
CIFilter
:通过它来定义过滤器的详细属性。
CIContext
有两种初始化方法,分别对应GPU
和CPU
创建基于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.重绘+锐化