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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作為繪圖引擎。它提供了低...
    ShanJiJi閱讀 1,600評論 0 20
  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發出絢麗的界面效果,一方面得益于成功系統的設計,另一方面得益...
    韓七夏閱讀 2,796評論 2 10
  • 走過荒漠,都像草原;秋風吹過,不落葉。現在已經是冬天了,但暖暖的太陽和依舊蒼翠的樹木還是讓人覺得大地依然豐滿而濕潤...
    達吉雅拉閱讀 310評論 0 0
  • 具體的報錯內容如下 代碼中調用的地方大致如下: 經過分析,崩潰的線程和調用并非在同一個線程,此時try catch...
    RidingWind2023閱讀 1,022評論 0 0
  • 在這個少雪且日漸溫暖的季節里,春節不知不覺掩埋了平淡的日子,迎面撲來??粗鴫ι闲沦I的掛歷,數著本世紀最后一個春...
    傲然于心閱讀 251評論 0 0