[Swift3] 對圖片進行裁剪
阿新 • • 發佈:2019-01-03
如果單獨的對已有圖片進行裁剪,可以使用系統自帶的函式,但是這個函式需要對圖片進行一些處理。我這裡自己實現了一個對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)
}
這樣一些準備工作就完成了,接下來從使用者開始畫矩形開始
然後是使用者手指在螢幕上移動時,這個矩形要隨時進行移動,但是要注意一點,矩形的範圍不可以超過View的範圍。即使手指已經超出那個範圍。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) // 記錄開始點 } }
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
}
這樣就可以得到對應的圖片了,之後就可以對這個圖片進行操作了。