Core Graphics学习

Quartz 2D是Core Graphics框架的一部分,是一个强大的二维图像绘制引擎。Quartz 2D在UIKit中也有很好的封装和集成,我们日常开发时所用到的UIKit中的组件都是由Core Graphics进行绘制的。不仅如此,当我们引入UIKit框架时系统会自动引入Core Graphics框架,并且为了方便开发者使用在UIKit内部还对一些常用的绘图API进行了封装。

一般步骤

1、获取绘图上下文

2、创建并设置路径

3、将路径添加到上下文

4、设置上下文状态

5、绘制路径

图形上下文CGContextRef代表图形输出设备(也就是绘制的位置),包含了绘制图形的一些设备信息。Quartz 2D中所有对象都必须绘制在图形上下文。

class CGView: UIView {
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        
        // 1、 获取上下文对象
        let context = UIGraphicsGetCurrentContext()
        
        // 2、 创建路径对象
        let path = CGPathCreateMutable()
        CGPathMoveToPoint(path, nil, 10, 30)
        CGPathAddLineToPoint(path, nil, 10, 100)
        CGPathAddLineToPoint(path, nil, 150, 100)
        
        // 3、 添加路径到图形上下文
        CGContextAddPath(context, path)
        
        // 4、 设置图形上下文状态属性
        CGContextSetRGBStrokeColor(context, 253/255.0, 245/255.0, 220/255.0, 1) //设置笔触颜色
        CGContextSetRGBFillColor(context, 1, 61/255.0, 78/255.0, 1)   //设置填充色
        
        CGContextSetLineWidth(context, 5)   //设置线条宽度
        CGContextSetLineCap(context, CGLineCap.Round ) // 设置顶点样式
        CGContextSetLineJoin(context, CGLineJoin.Round) //设置连接点样式
        /*设置线段样式
         phase:虚线开始的位置  这里设置为0
         lengths:虚线长度间隔
         count:虚线数组元素个数
         */
        let lengths: [CGFloat] = [5,7] //长度间隔
        CGContextSetLineDash(context, 0 , lengths, 2)
        
        let color = UIColor.grayColor().CGColor //颜色转化,由于Quartz 2D跨平台,所以其中不能使用UIKit中的对象,但是UIkit提供了转化方法
        /*设置阴影
         context:图形上下文
         offset:偏移量
         blur:模糊度
         color:阴影颜色
         */
        CGContextSetShadowWithColor(context, CGSizeMake(2, 2), 0.8, color)
        
        // 5、 绘制图像到指定图形上下文
        /*
         CGPathDrawingMode是填充方式,枚举类型
         Fill:只有填充(非零缠绕数填充),不绘制边框
         EOFill:奇偶规则填充(多条路径交叉时,奇数交叉填充,偶交叉不填充)
         Stroke:只有边框
         FillStroke:既有边框又有填充
         EOFillStroke:奇偶填充并绘制边框
         */
        CGContextDrawPath(context, CGPathDrawingMode.EOFillStroke) //最后一个参数是填充类型
    }
}

UIKit已经为我们准备好了一个上下文,在drawRect:方法(这个方法在loadView、viewDidLoad方法后执行)中我们可以通过UIKit封装函数UIGraphicsGetCurrentContext()方法获得这个图形上下文。

然后我们按照上面说的步骤一步一步的执行下来得到结果:

然后在vc的viewDidLoad中加入代码:

let cgView = CGView()
cgView.frame = CGRectMake(100, 100, 200, 200)
self.view.addSubview(cgView)

得到结果如图:

70E6D849-A70D-4881-AECB-42103263A764.png

上面的步骤略显复杂,其实代码还可以简化

我们再创建一个继承自UIView的子类 CGViewTwo

class CGViewTwo: UIView {
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        // 1、 获取上下文对象
        let context = UIGraphicsGetCurrentContext()
        
        // 2、绘制路径(相当于前面创建路径并添加路径到图形上下文两步操作)
        CGContextMoveToPoint(context, 10, 30)
        CGContextAddLineToPoint(context, 10, 100)
        CGContextAddLineToPoint(context, 150, 100)
        
        // 封闭路径:直接调用路径封闭方法
        CGContextClosePath(context)
        
        // 3、 设置图形上下文属性
        /*
         set(): 设置笔触和填充颜色
         setFill(): 设置填充颜色
         setStroke(): 设置笔触颜色
         */
//        UIColor.redColor().set()
        UIColor.redColor().setFill()
        UIColor.redColor().setStroke()
        
        // 4、 绘制路径
        CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
    }
}

上面代码精简了许多,Core Graphics 内部对创建对象添加到上下文这两步操作进行了封装,可以一步完成

继续在刚的vc的viewDidLoad:中加入代码:

let cgView = CGView()
cgView.frame = CGRectMake(100, 100, 200, 200)
self.view.addSubview(cgView)
        
let cgViewTwo = CGViewTwo()
cgViewTwo.frame = CGRectMake(100, 350, 200, 150)
self.view.addSubview(cgViewTwo)
70E6D849-A70D-4881-AECB-42103263A764.png

80B6DF47-B2C8-488A-A42C-8405C83A3962.png

绘制矩形
我们再来创建一个继承自 UIView的子类CGViewThree

class CGViewThree: UIView {
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        // 1、 获取上下文对象
        guard let context = UIGraphicsGetCurrentContext() else { return }
        // 画矩形
        self.drawRectWithContext(context)
    }
    
    /**
     画 矩形
     
     - parameter context: 上下文对象
     */
    private func drawRectWithContext(context: CGContext) {
        let rect = CGRectMake(20, 0, 280, 50)
        CGContextAddRect(context, rect)
        UIColor.blueColor().set()
        CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
    }
}

在vc对应viewDidLoad中加入此View

let cgViewThree = CGViewThree()
cgViewThree.frame = CGRectMake(100, 400, 200, 150)
self.view.addSubview(cgViewThree)

运行后结果:

341EC0AB-0FFA-4E9F-BA67-ABAFFBCB276A.png

其实UIKit对绘图方法的封装,使用起来更加简单。我们可以直接使用
直接在CGViewThree中继续添加方法

/**
     画 矩形, 用UIKit封装的方法
     
     - parameter context: 上下文对象
     */
    private func drawRectByUIKitWithContext(context: CGContext) {
        let rect = CGRectMake(0, 0, self.bounds.size.width, 50)
        let rect2 = CGRectMake(0, 70, self.bounds.size.width, 50)
        
        UIColor.yellowColor().set()
        UIRectFill(rect)
        
        UIColor.redColor().set()
        UIRectFill(rect2)
    }

然后在drawRect中调用 运行结果

3BB8C3C5-ABE3-48DC-8650-49E1182A0DB6.png

绘制椭圆和圆
继续在CGViewThree中添加方法

/**
     画 椭圆, 宽高一样就是正圆
     
     - parameter context: 上下文对象
     */
    private func drawEllipse(context: CGContext) {
        let rect = self.bounds
        
        CGContextAddEllipseInRect(context, rect)
        UIColor.purpleColor().set()
        CGContextDrawPath(context, CGPathDrawingMode.Fill)
    }

这里宽高设置的不一样 只要把宽和高设置一样就是正圆

在drawRect中添加此方法

运行结果:

FA08B435-E9E8-473C-AE77-8832351AA279.png

绘制弧形

    /**
     画 弧形
     
     - parameter context: 上下文对象
     */
    private func drawArc(context: CGContext) {
        /*
         添加弧形对象
         x:中心点x坐标
         y:中心点y坐标
         radius:半径
         startAngle:起始弧度
         endAngle:终止弧度
         closewise:是否逆时针绘制,0则顺时针绘制
         */
        CGContextAddArc(context, self.bounds.size.width * 0.5, self.bounds.size.height * 0.5, 50, 0, CGFloat(M_PI), 0)
        UIColor.greenColor().set()
        CGContextDrawPath(context, CGPathDrawingMode.Fill)
    }

和上面一样 添加到drawRect

运行结果

6E882B8F-8FB4-4AA8-B231-3F7723DDF49B.png

绘制贝塞尔曲线
在Quartz 2D中曲线绘制分为两种:二次贝塞尔曲线和三次贝塞尔曲线。二次曲线只有一个控制点,而三次曲线有两个控制点,如下图所示:

954071-bca3f7cf65eb62ed.png

下面演示下绘制方法:

    /**
     绘制 贝塞尔曲线
     
     - parameter context: 上下文对象
     */
    private func drawCurve(context: CGContext) {
        // 绘制曲线
        CGContextMoveToPoint(context, 20, 50) //移动到起始位置
        
        /**
         绘制二次贝塞尔曲线
         c:图形上下文
         cpx:控制点x坐标
         cpy:控制点y坐标
         x:结束点x坐标
         y:结束点y坐标
         */
        CGContextAddQuadCurveToPoint(context, 120, 0, 120, 50)
        
        CGContextMoveToPoint(context, 20, 100)
        
        /*绘制三次贝塞尔曲线
         c:图形上下文
         cp1x:第一个控制点x坐标
         cp1y:第一个控制点y坐标
         cp2x:第二个控制点x坐标
         cp2y:第二个控制点y坐标
         x:结束点x坐标
         y:结束点y坐标
         */
        CGContextAddCurveToPoint(context, 70, 0, 120, 200, 170, 100)
        
        UIColor.yellowColor().setStroke()
        UIColor.redColor().setFill()
        
        CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
    }

上面所有方法加入到drawRect

23FBF543-1125-49A6-BFC2-C3BA8E0C3D85.png

文字绘制
Core Graphics不仅可以画图还能绘制文字
这个页面已经放不下了 开一个新的页面 继续,后面我会把所有代码上传github 供大家参考

创建一个新的继承自UIView的类CGViewFour

添加下面方法

    /**
     文字绘制
     
     - parameter context: 上下文对象
     */
    private func drawText(context: CGContext) {
        let str = "使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制使用CoreGraphics进行文字绘制"
        let rect  = CGRectMake(20, 20, 280, 200)
        let font = UIFont.systemFontOfSize(16)
        let color = UIColor.redColor()
        let style = NSMutableParagraphStyle()
        style.alignment = NSTextAlignment.Left
        (str as NSString).drawInRect(rect, withAttributes: [NSFontAttributeName:font,NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:style])
    }

声明了一个字符串,设置了绘制区间、字体颜色段落属性等

画好之后 还在在drawRect中调用

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        
        guard let context = UIGraphicsGetCurrentContext() else { return }
        self.drawText(context)
    }

结果:

F322FB4E-9836-4A28-B627-E5CC3B48CC4D.png

文字已经正确的绘制到视图上

图像绘制
当然Core Graphics也能绘制图像

很简单

    /**
     图像绘制
     
     - parameter context: 上下文对象
     */
    private func drawImage(context: CGContextRef) {
        let img = UIImage.init(named: "haha")
        img?.drawInRect(CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height))
        
        //从某一点开始绘制
        img?.drawAtPoint(CGPoint(x: 0, y: 0))
    }

可以从某点开始绘制也可以指定位置区域

绘制渐变
Quartz 2D的渐变方式分为两种:

线性渐变线:渐变色以直线方式从开始位置逐渐向结束位置渐变
径向渐变:以中心点为圆心从起始渐变色向四周辐射,直到终止渐变色

    /**
     绘制线性渐变
     
     - parameter context: 上下文
     */
    func drawLinearGradient(context:CGContextRef){
        
        //使用rgb颜色空间
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        /*
         指定渐变色
         space:颜色空间
         components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
         如果有三个颜色则这个数组有4*3个元素
         locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
         count:渐变个数,等于locations的个数
         */
        let compoents:[CGFloat] = [ 248.0/255.0,86.0/255.0,86.0/255.0,1,
                                    249.0/255.0,127.0/255.0,127.0/255.0,1,
                                    1.0,1.0,1.0,1.0]
        
        let locations:[CGFloat] = [0,0.4,1]
        let gradient = CGGradientCreateWithColorComponents(colorSpace, compoents, locations, locations.count)
        /*
         绘制线性渐变
         context:图形上下文
         gradient:渐变色
         startPoint:起始位置
         endPoint:终止位置
         options:绘制方式,DrawsBeforeStartLocation 开始位置之前就进行绘制,到结束位置之后不再绘制,
         DrawsAfterEndLocation开始位置之前不进行绘制,到结束点之后继续填充
         */
        CGContextDrawLinearGradient(context, gradient , CGPointZero, CGPointMake(self.frame.size.width,100), CGGradientDrawingOptions.DrawsAfterEndLocation)
    }

径向渐变
新建一个CGViewSix

  /**
     径向渐变绘制

     - parameter context: 上下文
     */
    func drawRadialGradient(context:CGContextRef){

        //使用rgb颜色空间
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        /*
        指定渐变色
        space:颜色空间
        components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
        如果有三个颜色则这个数组有4*3个元素
        locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
        count:渐变个数,等于locations的个数
        */
        let compoents:[CGFloat] = [ 248.0/255.0,86.0/255.0,86.0/255.0,1,
            249.0/255.0,127.0/255.0,127.0/255.0,1,
            1.0,1.0,1.0,1.0]

        let locations:[CGFloat] = [0,0.4,1]
        let gradient = CGGradientCreateWithColorComponents(colorSpace, compoents, locations, locations.count)
        /*
        绘制线性渐变
        context:图形上下文
        gradient:渐变色
        startPoint:起始位置
        startRadius:起始半径(通常为0,否则在此半径范围内容无任何填充)
        endCenter:终点位置(通常和起始点相同,否则会有偏移)
        endRadius:终点半径(也就是渐变的扩散长度)
        options:绘制方式,DrawsBeforeStartLocation 开始位置之前就进行绘制,到结束位置之后不再绘制,
        DrawsAfterEndLocation开始位置之前不进行绘制,到结束点之后继续填充
        */
        CGContextDrawRadialGradient(context, gradient, CGPointMake(100,100), 0, CGPointMake(105, 105), 80, CGGradientDrawingOptions.DrawsAfterEndLocation)
    }

渐变填充
有时候 我们需要在一个矩形中填充渐变,在此可以利用渐变裁切来完成。

继续在CGViewSix中添加以下方法

    /**
     绘制了一个矩形填充的渐变
     
     - parameter context: 上下文对象
     */
    func drawRectWithLinearGradientFill(context: CGContextRef) {
        // 使用rgb颜色空间
        /*
         CGColorSpaceCreateDeviceRGB()  使用RGB颜色空间
         CGColorSpaceCreateDeviceCMYK() 使用CMYK颜色空间
         CGColorSpaceCreateDeviceGray() 使用Gray颜色空间
         */
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        // 裁剪出一块矩形用于显示,注意必须先裁剪再调用渐变
        CGContextClipToRect(context, CGRectMake(10, 10, 200, 140))
        // 裁切还可以使用UIKit中封装的对应方法
//        UIRectClip(self.bounds)
        
        let components: [CGFloat] = [200.0/255.0,50.0/255.0,80.0/255.0,1,
                                     230.0/255.0,127.0/255.0,127.0/255.0,1,
                                     249.0/255.0,200.0/255.0,240.0/255.0,1,
                                     1.0,1.0,1.0,1.0]
        let locations = [0.0, 0.4, 0.8, 1.0]
        let gradient = CGGradientCreateWithColorComponents(colorSpace, components, components, locations.count)
        CGContextDrawLinearGradient(context, gradient, CGPointMake(10, 10), CGPointMake(self.bounds.size.width - 20, self.bounds.size.height - 20), CGGradientDrawingOptions.DrawsAfterEndLocation)
    }

叠加模式
使用Quartz 2D绘图时后面绘制的图像会覆盖前面的,默认情况下如果前面的被覆盖后将看不到后面的内容,但是有时候这个结果并不是我们想要的,因此在Quartz 2D中提供了填充模式供开发者配置调整。由于填充模式类别特别多。

因此下面以一个例子来说明:

新建一个CGViewSeven

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        let rect0 = CGRectMake(0, 130.0, 320.0, 50.0)
        let rect1 = CGRectMake(0, 390.0, 320.0, 50.0)
        
        let rect2=CGRectMake(20, 50.0, 10.0, 250.0)
        let rect3=CGRectMake(40.0, 50.0, 10.0, 250.0)
        let rect4=CGRectMake(60.0, 50.0, 10.0, 250.0)
        let rect5=CGRectMake(80.0, 50.0, 10.0, 250.0)
        let rect6=CGRectMake(100.0, 50.0, 10.0, 250.0)
        let rect7=CGRectMake(120.0, 50.0, 10.0, 250.0)
        let rect8=CGRectMake(140.0, 50.0, 10.0, 250.0)
        let rect9=CGRectMake(160.0, 50.0, 10.0, 250.0)
        let rect10=CGRectMake(180.0, 50.0, 10.0, 250.0)
        let rect11=CGRectMake(200.0, 50.0, 10.0, 250.0)
        let rect12=CGRectMake(220.0, 50.0, 10.0, 250.0)
        let rect13=CGRectMake(240.0, 50.0, 10.0, 250.0)
        let rect14=CGRectMake(260.0, 50.0, 10.0, 250.0)
        let rect15=CGRectMake(280.0, 50.0, 10.0, 250.0)
        
        let rect16=CGRectMake(30.0, 310.0, 10.0, 250.0)
        let rect17=CGRectMake(50.0, 310.0, 10.0, 250.0)
        let rect18=CGRectMake(70.0, 310.0, 10.0, 250.0)
        let rect19=CGRectMake(90.0, 310.0, 10.0, 250.0)
        let rect20=CGRectMake(110.0, 310.0, 10.0, 250.0)
        let rect21=CGRectMake(130.0, 310.0, 10.0, 250.0)
        let rect22=CGRectMake(150.0, 310.0, 10.0, 250.0)
        let rect23=CGRectMake(170.0, 310.0, 10.0, 250.0)
        let rect24=CGRectMake(190.0, 310.0, 10.0, 250.0)
        let rect25=CGRectMake(210.0, 310.0, 10.0, 250.0)
        let rect26=CGRectMake(230.0, 310.0, 10.0, 250.0)
        let rect27=CGRectMake(250.0, 310.0, 10.0, 250.0)
        let rect28=CGRectMake(270.0, 310.0, 10.0, 250.0)
        let rect29=CGRectMake(290.0, 310.0, 10.0, 250.0)
        
        UIColor.yellowColor().set()
        UIRectFill(rect0)
        UIColor.greenColor().set()
        UIRectFill(rect1)
        UIColor.redColor().set()
        UIRectFillUsingBlendMode(rect2, CGBlendMode.Clear )
        UIRectFillUsingBlendMode(rect3, CGBlendMode.Color )
        UIRectFillUsingBlendMode(rect4, CGBlendMode.ColorBurn)
        UIRectFillUsingBlendMode(rect5, CGBlendMode.ColorDodge)
        UIRectFillUsingBlendMode(rect6, CGBlendMode.Copy)
        UIRectFillUsingBlendMode(rect7, CGBlendMode.Darken)
        UIRectFillUsingBlendMode(rect8, CGBlendMode.DestinationAtop)
        UIRectFillUsingBlendMode(rect9, CGBlendMode.DestinationIn)
        UIRectFillUsingBlendMode(rect10, CGBlendMode.DestinationOut)
        UIRectFillUsingBlendMode(rect11, CGBlendMode.DestinationOver)
        UIRectFillUsingBlendMode(rect12, CGBlendMode.Difference)
        UIRectFillUsingBlendMode(rect13, CGBlendMode.Exclusion)
        UIRectFillUsingBlendMode(rect14, CGBlendMode.HardLight)
        UIRectFillUsingBlendMode(rect15, CGBlendMode.Hue)
        UIRectFillUsingBlendMode(rect16, CGBlendMode.Lighten)
        
        UIRectFillUsingBlendMode(rect17, CGBlendMode.Luminosity)
        UIRectFillUsingBlendMode(rect18, CGBlendMode.Multiply)
        UIRectFillUsingBlendMode(rect19, CGBlendMode.Normal)
        UIRectFillUsingBlendMode(rect20, CGBlendMode.Overlay)
        UIRectFillUsingBlendMode(rect21, CGBlendMode.PlusDarker)
        UIRectFillUsingBlendMode(rect22, CGBlendMode.PlusLighter)
        UIRectFillUsingBlendMode(rect23, CGBlendMode.Saturation)
        UIRectFillUsingBlendMode(rect24, CGBlendMode.Screen)
        UIRectFillUsingBlendMode(rect25, CGBlendMode.SoftLight)
        UIRectFillUsingBlendMode(rect26, CGBlendMode.SourceAtop)
        UIRectFillUsingBlendMode(rect27, CGBlendMode.SourceIn)
        UIRectFillUsingBlendMode(rect28, CGBlendMode.SourceOut)
        UIRectFillUsingBlendMode(rect29, CGBlendMode.XOR)
    }

添加到一个新的vc中 效果:

B6D31C40-1067-4743-81B9-8D89B3CEC95A.png

对比代码和显示效果查看每种叠加效果

上下文变换
在view中可以利用transform对试图进行平移旋转缩放,绘图中我们也经常用到图形形变,在CoreText中绘制文字的时候因为Core Graphics坐标原点在左下角、UIKit在右上角 。所有要通过变换转过来,下面通过一个图片的变换演示一下图形上下文的形变。

class CGViewEight: UIView {
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        
        let context = UIGraphicsGetCurrentContext()
        self.drawImage(context!)
    }
    
    /**
     平移旋转缩放
     
     - parameter context: 上下文对象
     */
    func drawImage(context:CGContextRef){
        //保存初始状态
        CGContextSaveGState(context)
        
        //形变第一步:图形上下文向右平移100
        CGContextTranslateCTM(context,100, 0)
//
//        //形变第二步:缩放0.8
        CGContextScaleCTM(context, 0.8, 0.8)
        
        //形变第三步:旋转
        CGContextRotateCTM(context, CGFloat(M_PI_4)/4)
        let img = UIImage(named: "haha")
        
        //从某一点开始绘制
//        img?.drawAtPoint(CGPoint(x: 0, y: 100))
        //在某个rect里面绘制
        img?.drawInRect(self.bounds)
    }
}
9A444553-B2CD-478D-91A2-DA348DE9B5CF.png

使用Core Graphics绘制图像

class CGViewNine: UIView {
    // 在前面基本绘图部分,绘制图像时使用了UIKit中封装的方法进行了图像绘制,我们不妨看一下使用Quartz 2D内置方法绘制是什么效果。
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        guard let context = UIGraphicsGetCurrentContext() else { return }
        self.drawImage(context)
    }
    
    func drawImage(context: CGContextRef) {
        let image = UIImage(named: "haha")
        let size = UIScreen.mainScreen().bounds.size
        CGContextSaveGState(context)
        let height: CGFloat = 450.0
        let y: CGFloat = 50.0
        // 图像绘制
        let rect = CGRectMake(10, y, 300, height)
        // 在Core Graphics中坐标系的y轴正方向是向上的,坐标原点在屏幕左下角,y轴方向刚好和UIKit中y轴方向相反
        CGContextScaleCTM(context, 1.0, -1.0) //在y轴缩放-1相当于沿着x张旋转180
        CGContextTranslateCTM(context, 0, -(size.height-(size.height-2*y-height))) //向上平移
        CGContextDrawImage(context, rect, image?.CGImage)
        
    }
}

由于坐标问题 我们做了翻转和平移

23F455C0-A852-4683-889C-BB2178847232.png

绘制到位图
利用位图图形上下文给一个图片添加水印,在下面的程序中我们首先创建上下文,然后在上下文中绘制图片、直线和文本,最后从当前位图上下文中取得最终形成的新图片显示到界面。

class ViewControllerFour: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let image = self.drawImageAtImageContext()
        let imageView = UIImageView(image: image)
        imageView.center=CGPointMake(self.view.bounds.width * 0.5, self.view.bounds.height * 0.5)
        
        self.view.addSubview(imageView)
    }
    
    private func drawImageAtImageContext() -> UIImage {
        // 获得一个位图图形上下文
        let size = self.view.bounds.size
        UIGraphicsBeginImageContext(size)
        
        let image = UIImage(named: "haha")
        image?.drawInRect(self.view.bounds)
        
        // 添加水印
        
        let str = "测试图片"
        let wordSize = (str as NSString).sizeWithAttributes([NSFontAttributeName:UIFont.boldSystemFontOfSize(16),NSForegroundColorAttributeName:UIColor.redColor()])
        (str as NSString).drawInRect(CGRectMake(self.view.bounds.size.width - wordSize.width - 10, self.view.bounds.size.height - wordSize.height - 10, wordSize.width, wordSize.height), withAttributes: [NSFontAttributeName:UIFont.boldSystemFontOfSize(16),NSForegroundColorAttributeName:UIColor.redColor()])
        //返回绘制的新图形
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        
        //保存图片
//        let data = UIImagePNGRepresentation(newImage)
//        data?.writeToFile("/Users/admin/Desktop/Gauge/haha.png", atomically: true)
        
        //不要忘记关闭对应上下文
        UIGraphicsEndImageContext()
        
        return newImage
    }
//    注意:上面这种方式绘制的图像除了可以显示在界面上还可以调用对应方法进行保存(代码注释中已经包含保存方法);除此之外这种方法相比在drawRect:方法中绘制图形效率更高,它不用每次展示时都调用所有图形绘制方法。
}

参考链接:http://www.cnblogs.com/kenshincui/p/3959951.html

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

推荐阅读更多精彩内容

  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,534评论 0 20
  • --绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益...
    韩七夏阅读 2,727评论 2 10
  • 走过荒漠,都像草原;秋风吹过,不落叶。现在已经是冬天了,但暖暖的太阳和依旧苍翠的树木还是让人觉得大地依然丰满而湿润...
    达吉雅拉阅读 306评论 0 0
  • 具体的报错内容如下 代码中调用的地方大致如下: 经过分析,崩溃的线程和调用并非在同一个线程,此时try catch...
    RidingWind2023阅读 994评论 0 0
  • 在这个少雪且日渐温暖的季节里,春节不知不觉掩埋了平淡的日子,迎面扑来。看着墙上新买的挂历,数着本世纪最后一个春...
    傲然于心阅读 247评论 0 0