1. 程式人生 > >[Swift3] 對圖片進行裁剪

[Swift3] 對圖片進行裁剪

如果單獨的對已有圖片進行裁剪,可以使用系統自帶的函式,但是這個函式需要對圖片進行一些處理。我這裡自己實現了一個對UIImage的extension。

extension UIImage {
	func subImage(rect: CGRect) -> UIImage? {
		let cgImage = self.cgImage!  // 需要先轉換成CGImage
		let image= cgImage.cropping(to: rect)  // 要注意rect的大小和位置不要超出image的範圍
		return image
	}
}
這種情況需要注意rect的大小和位置,我這裡要實現的是使用者在自己建立的UIImageView上對圖片自行裁剪。

使用者畫圖部分我選擇用CAShapeLayer實現,首先對其寫一個擴充套件,對一些資料進行預設,這樣以後定義的時候就不需要每次都進行設定了

extension CAShapeLayer {
    
    class func defaultShapeLayer() -> CAShapeLayer {
        let shapeLayer = CAShapeLayer()
        let frame = CGRect(x: 0, y: 0, width: screenW, height: bottomImageH)  // 這裡的frame是定義的使用者繪圖的frame
        shapeLayer.frame = frame
        shapeLayer.strokeColor = UIColor.red.cgColor  // 線的顏色
        shapeLayer.fillColor = UIColor.clear.cgColor // 填充色為透明
        shapeLayer.lineWidth = 2  // 線寬
        
        return shapeLayer
    }
    
}

由於使用者是通過按下手指,滑動螢幕來描繪矩形,所以這個矩形的建立使用開始點和結束點這兩個點建立比較方便,但是系統沒有這個函式,所以接下來對CGRect進行擴充套件
init(startPoint: CGPoint, endPoint: CGPoint) {
        self.init(x: startPoint.x, y: startPoint.y, width: endPoint.x - startPoint.x, height: endPoint.y - startPoint.y)
    }
這樣一些準備工作就完成了,接下來從使用者開始畫矩形開始
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {  // 這個函式是當用戶開始觸控這個View時呼叫
        if let touch = touches.first {
            shapeLayer?.removeFromSuperlayer()  // 由於設定只能有一個矩形,所以這個shapeLayer作為了我的View的屬性,當觸屏開始時先將原有的矩形移除
            shapeLayer = CAShapeLayer.defaultShapeLayer()
            startPoint = touch.location(in: self)  // 記錄開始點
        }
    }
然後是使用者手指在螢幕上移動時,這個矩形要隨時進行移動,但是要注意一點,矩形的範圍不可以超過View的範圍。即使手指已經超出那個範圍。
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {  // 當用戶手指移動時
        if let touch = touches.first {
            endPoint = touch.location(in: self)
            endPoint.y = endPoint.y < 0 ? 0 : endPoint.y
            endPoint.y = endPoint.y > bottomImageH ? bottomImageH : endPoint.y
            shapeLayer.path = UIBezierPath(rect: CGRect(startPoint: startPoint, endPoint: endPoint)).cgPath  // 設定shapeLayer的path
            self.layer.addSublayer(shapeLayer)  // 實時顯示矩形
        }
    }

結束之後就可以通過這兩個點生成的矩形進行裁剪啦。

但是,裁剪的時候,重點,也是坑點,來了

由於imageView的大小和圖片的大小不一致,所以圖片會有一些拉伸。也就是說使用者在imageView上畫的矩形和image上對應的矩形很有可能是不一致的。

打個比方,我們的圖片是一個50x50的正方形,但是你的imageView卻是一個100x150的矩形,如果使用者將整個矩形都選中,我們直接使用這個100x150的矩形在原正方形上截圖,就會出現問題。所以我們需要通過一定的演算法將這個100x150的矩形轉換成50x50的正方形。這樣最開始的那個擴充套件就需要進行一定的調整

//  這是對imageView寫的擴充套件,所以有些地方會與一開始那個不一樣

func subImage(rect: CGRect) -> UIImage? {
        let sourceImage: CGImage = (self.image?.cgImage!)!
        let widthScale = CGFloat(sourceImage.width) / self.frame.width  // 計算寬度比
        let heightScale = CGFloat(sourceImage.height) / self.frame.height  // 計算高度比
        let originPoint = CGPoint(x: rect.origin.x * widthScale, y: rect.origin.y * heightScale)  // 計算原點(startPoint)的偏移量
        let size = CGSize(width: rect.width * widthScale, height: rect.height * heightScale)  // 計算size
        let rect = CGRect(origin: originPoint, size: size)  // 在image上對應的矩形
        let image = sourceImage.cropping(to: rect)
        
        return image == nil
    }


這樣就可以得到對應的圖片了,之後就可以對這個圖片進行操作了。