图形处理
2019-01-09 本文已影响0人
微笑_d797
图形绘制(第一天)
湖中倒影
画一个图片的倒影
extension UIImageView {
/// 创建一个倒影图像
/// height:裁剪比例
func refkectedImage(subimgV: UIImageView,height: CGFloat){
if let context = createBitmapContext(pixelsWidth: subimgV.bounds.size.width, pixelsHight: height),let gradientmaskimage = createGradientImage(pixelsWidth: 1, pixelsHight: height),let cgImage = subimgV.image?.cgImage {
/// 裁剪+翻转+缩放+添加渐变效果
context.clip(to: CGRect.init(x: 0, y: 0, width: subimgV.bounds.size.width, height: height), mask: gradientmaskimage)
context.translateBy(x: 0.0, y: height)
context.scaleBy(x: 1.0, y: -1.0)
///绘制
context.draw(cgImage, in: subimgV.bounds)
let reflectionimage = context.makeImage()
self.image = UIImage.init(cgImage: reflectionimage!)
}
}
private func createBitmapContext(pixelsWidth: CGFloat,pixelsHight: CGFloat) -> CGContext? {
/// 绘制颜色为灰色的图片 的色彩空间
let space = CGColorSpaceCreateDeviceGray()
///彩色换成
/// CGColorSpaceCreateDeviceRGB()
/*
Create a bitmap context. The context draws into a bitmap which is `width'
pixels wide and `height' pixels high. The number of components for each
pixel is specified by `space', which may also specify a destination color
profile. Note that the only legal case when `space' can be NULL is when
alpha is specified as kCGImageAlphaOnly.The number of bits for each component
of a pixel is specified by `bitsPerComponent'. The number of bytes per pixel
is equal to `(bitsPerComponent * number of components + 7)/8'. Each row of
the bitmap consists of `bytesPerRow' bytes, which must be at least
`width * bytes per pixel' bytes; in addition, `bytesPerRow' must be an
integer multiple of the number of bytes per pixel. `data', if non-NULL,
points to a block of memory at least `bytesPerRow * height' bytes.
If `data' is NULL, the data for context is allocated automatically and freed
when the context is deallocated. `bitmapInfo' specifies whether the bitmap
should contain an alpha channel and how it's to be generated, along with
whether the components are floating-point or integer.
*/
/*
创建位图上下文。上下文绘制为“宽度”位图。
像素宽,像素高。每个组件的数量
像素由“space”指定,也可以指定目标颜色。
轮廓。请注意,当“space”可以为空时,唯一的法律案例是
alpha指定为kcgimagealphaonly。每个组件的位数
“bitspercomponent”指定像素的。每个像素的字节数
等于`(bitspercomponent*组件数+7)/8'。每行
位图由“bytesperrow”字节组成,该字节必须至少为
`width*bytes per pixel'字节;此外,`bytesprerow'必须是
每像素字节数的整数倍。“data”,如果非空,
指向至少“bytesperrow*height”字节的内存块。
如果“data”为空,则自动分配和释放上下文的数据。
当上下文解除分配时。`bitmapinfo'指定位图
应该包含一个alpha通道以及如何生成它,以及
组件是浮点还是整数。
*/
let bitmapcontext = CGContext(data: nil, width: Int(pixelsWidth), height: Int(pixelsHight), bitsPerComponent: 8, bytesPerRow: 0, space: space, bitmapInfo: 1)
return bitmapcontext
}
/// 创建渐变图层
private func createGradientImage(pixelsWidth: CGFloat,pixelsHight: CGFloat) -> CGImage? {
var cgimage:CGImage?
let space = CGColorSpaceCreateDeviceGray()
let bitmapcontext = CGContext(data: nil, width: Int(pixelsWidth), height: Int(pixelsHight), bitsPerComponent: 8, bytesPerRow: 0, space: space, bitmapInfo: 0)!
var colors:[CGFloat] = [CGFloat(0.0),CGFloat(1.0),CGFloat(1.0),CGFloat(1.0)]
let grayscalecradient = CGGradient.init(colorSpace: space, colorComponents: &colors, locations: nil, count: 2)
let gradientstartpoint = CGPoint.zero
let gradientEndpoint = CGPoint.init(x: 0, y: pixelsHight)
bitmapcontext.drawLinearGradient(grayscalecradient!, start: gradientstartpoint, end: gradientEndpoint, options: CGGradientDrawingOptions.drawsAfterEndLocation)
cgimage = bitmapcontext.makeImage()
return cgimage
}
}
应用代码
let imgV = UIImageView()
imgV.frame = CGRect.init(x: 100, y: 100, width: 100, height: 100)
let path = Bundle.main.path(forResource: "WechatIMG47", ofType: "png")!
imgV.image = try UIImage.init(data: Data.init(contentsOf: URL.init(fileURLWithPath: path)))!
self.view.addSubview(imgV)
let fimgv = UIImageView()
fimgv.frame = CGRect.init(x: 100, y: 200, width: 100, height: 50)
fimgv.alpha = 0.5
self.view.addSubview(fimgv)
let height = imgV.bounds.size.height * 0.5
fimgv.refkectedImage(subimgV: imgV, height: height)
注意创建图层的方法CGBitmapinfo是一个结构体他的构造为 创建上下文的时候传的默认值1 创建渐变图层的时候 传的是0
public struct CGBitmapInfo : OptionSet {
public init(rawValue: UInt32)
///Aplha通道信息遮罩。用这个值来提取alpha信息。这个值明确了位图是否包含了alpha通道和alpha通道是如何生成的 0
public static var alphaInfoMask: CGBitmapInfo { get }
public static var floatInfoMask: CGBitmapInfo { get }
public static var floatComponents: CGBitmapInfo { get }
public static var byteOrderMask: CGBitmapInfo { get }
public static var byteOrder16Little: CGBitmapInfo { get }
public static var byteOrder32Little: CGBitmapInfo { get }
public static var byteOrder16Big: CGBitmapInfo { get }
public static var byteOrder32Big: CGBitmapInfo { get }
}
CoreGraphics 和 CAShaplayer(CoreAnimation) 的 优缺点
Core Graphics(占用CPU,性能消耗大,如果没有需求,苹果不建议实现空的drawRect方法;)画得越多,程序就会越慢。因为每次绘制会重绘整个贝塞尔路径(UIBezierPath),随着路径越来越复杂,每次重绘的工作就会增加,直接导致了帧数的下降。
它提供了低级别、轻量级的2d 渲染, 具有无与伦比的输出保真度。使用此框架可以处理基于路径的绘图、转换、颜色管理、屏幕外渲染、图案、渐变和着色、图像数据管理、图像创建和图像屏蔽, 以及 pdf 文档创建、显示和分析
Core Animation(通过GPU来渲染图形,不消耗内存,节省性能;)为这些图形类型的绘制提供了专门的类,并给他们提供硬件支持。CAShapeLayer可以绘制多边形,直线和曲线。CATextLayer可以绘制文本。CAGradientLayer用来绘制渐变。这些总体上都比Core Graphics更快,同时他们也避免了创造一个寄宿图。
用CAShapeLayer替代Core Graphics,性能就会得到提高(.虽然随着路径复杂性的增加,绘制性能依然会下降,但是只有当非常非常浮躁的绘制时才会感到明显的帧率差异。
WechatIMG48.png
添加滤镜
ps上的各种滤镜效果在iOS手机上也可以实现,通过CIFilter来实现
先初始化一个CIFilter初始化方法调用name属性来选择滤镜
设置inputimage要加滤镜的image
调用setDefaults方法
得到outputimage
/// 添加滤镜�
extension UIImage {
func filterimg() -> UIImage {
let ciimg = CIImage.init(cgImage: self.cgImage!)
let context = CIContext.init(options: nil)
let filter = CIFilter.init(name: "CIPhotoEffectInstant")!
filter.setValue(ciimg, forKey: "inputImage")
filter.setDefaults()
let outputimg = filter.outputImage!
return UIImage.init(cgImage: context.createCGImage(outputimg, from: outputimg.extent)!)
}
}