#10.2照片編輯
Published in
18 min readDec 6, 2022
程式重點:
- UIImagePickerController使用
- UICollectionViewFlowLayout設定
- FileManager使用
- 程式生成UIView(Init)
- View的touchesBegan,touchesMoved,touchesEnded函式使用
- instantiateViewController(傳值,建構子)
- CGAffineTransform動畫使用
- UIColorPickerViewController使用
- UIGraphicsImageRenderer存圖
分析和解構流程:
1.生成Photo資料型別,定義儲存位置
2.撰寫TableView的Cell生成和BarButtonItem生成
3.撰寫UIImagePickerController(相簿選圖),包含使用instantiateViewController進行換頁和傳值
4,撰寫用程式生成View,包含使用touchesBegan等函式
5.撰寫編輯圖片功能的邏輯
6.撰寫呈現TableView畫面的程式邏輯
//secondButton
@IBOutlet var secondBtns: [UIButton]!
//FirstButton
@IBOutlet weak var Crop: UIButton!
@IBOutlet weak var Rotate: UIButton!
@IBOutlet weak var BackgroundColor: UIButton!
@IBOutlet weak var Btn4: UIButton!
@IBOutlet weak var imageBackGroundView: UIView!
//傳值
//建構子
init?(coder: NSCoder, editImage: UIImage,photos:[Photo]) {
self.editImageRetouch = editImage
self.photos = photos
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//接取 建構子的參數
var editImageRetouch: UIImage
var editImageView : EditImageUIView?
var width: CGFloat = 0.0
var height: CGFloat = 0.0
//旋轉
var rotatex: CGFloat = 1
var rotatey: CGFloat = 1
//旋轉的Constant
var rotateConstant: CGFloat = 0
var imageBackgroundOriginalWidth: CGFloat = 0
var imageBackgroundOriginalHeight: CGFloat = 0
//修飾圖片Width
var retouchingImageOriginalWidth: CGFloat = 0
var retouchingImageOriginalHeight: CGFloat = 0
//圖片背景最大寬
var imageBackgroundmaxY: CGFloat = 0
var imageBackgroundminY: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
//螢幕寬
let screenW = UIScreen.main.bounds.width
//螢幕高
let screenH = UIScreen.main.bounds.height
//建構 UIView
editImageView = EditImageUIView(frame: CGRect(x: 0, y: (screenH-screenW)/2, width: screenW, height: screenW), editImage: editImageRetouch)!
print("editImageView",editImageView)
view.addSubview(editImageView!)
print("imageBackGroundView",imageBackGroundView)
currentMode = .typeCrop
//imageBackgroundOriginalWidth的寬
//view
imageBackgroundOriginalWidth = editImageView!.bounds.width
imageBackgroundOriginalHeight = editImageView!.bounds.height
print("imageBackgroundOriginalWidth",imageBackgroundOriginalWidth)
print("retouchingImageOriginalHeight",imageBackgroundOriginalHeight)
//imageBackgroundOriginalWidth等於傳過來的寬 imageview
retouchingImageOriginalWidth = editImageView!.imageView.frame.width //imageBackgroundOriginalWidth等於傳過來的高
retouchingImageOriginalHeight = editImageView!.imageView.frame.height
print("retouchingImageOriginalWidth",retouchingImageOriginalWidth)
print("retouchingImageOriginalHeight",retouchingImageOriginalHeight)
imageBackgroundmaxY = editImageView!.frame.maxY
imageBackgroundminY = editImageView!.frame.minY
print("imageBackgroundmaxY",imageBackgroundmaxY)
print("imageBackgroundminY",imageBackgroundminY)
}
編輯Button的UI介面
//重置上排按鈕的狀態
func secondBtnReset() {
//濾鏡有的話
for i in secondBtns.indices{
secondBtns[i].setTitle(nil, for: .normal)
secondBtns[i].setImage(nil, for: .normal)
secondBtns[i].isHidden = false
}
}
@IBAction func typeRatioChange(_ sender: UIButton) {
secondBtnReset()
currentMode = .typeRatio
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
secondBtns[0].setTitle("original", for: .normal)
secondBtns[0].setImage(nil, for: .normal)
secondBtns[1].setTitle("1:1", for: .normal)
secondBtns[1].setImage(nil, for: .normal)
secondBtns[2].setTitle("16:9", for: .normal)
secondBtns[2].setImage(nil, for: .normal)
secondBtns[3].isHidden = true
case .typeRotate:
fallthrough
case .colorControl:
break
}
}
@IBAction func typeRotateChange(_ sender: UIButton) {
secondBtnReset()
currentMode = .typeRotate
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
fallthrough
case .typeRotate:
secondBtns[0].setTitle("", for: .normal)
secondBtns[0].setImage(UIImage(systemName: "arrow.left.and.right.righttriangle.left.righttriangle.right"), for: .normal)
secondBtns[1].setTitle("", for: .normal)
secondBtns[1].setImage(UIImage(systemName: "arrow.up.and.down.righttriangle.up.righttriangle.down"), for: .normal)
secondBtns[2].setTitle("", for: .normal)
secondBtns[2].setImage(UIImage(systemName: "rotate.right"), for: .normal)
secondBtns[3].setTitle("", for: .normal)
secondBtns[3].setImage(UIImage(systemName: "rotate.left"), for: .normal)
case .colorControl:
break
}
}
編輯圖片功能的邏輯撰寫
//編輯完後 置中
func centerAnchor(){
editImageView?.translatesAutoresizingMaskIntoConstraints = false
editImageView!.imageView.centerXAnchor.constraint(equalTo: editImageView!.centerXAnchor).isActive = true
editImageView!.imageView.centerYAnchor.constraint(equalTo: editImageView!.centerYAnchor).isActive = true
editImageView!.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
//裁切成原圖
func originalCrop() {
//背景圖片
editImageView!.bounds.size = CGSize(width: imageBackgroundOriginalWidth, height: imageBackgroundOriginalHeight)
editImageView!.imageView.frame.size = CGSize(width: retouchingImageOriginalWidth, height: retouchingImageOriginalHeight)
centerAnchor()
}
//水平翻轉
func horizontalRotate() {
//x軸交換
rotatex *= -1
editImageView!.imageView.transform = CGAffineTransform(scaleX: rotatex, y: rotatey)
}
//裁切成1:1
func squareCrop() {
//圖片跟背景圖片等寬高
width = editImageView!.bounds.width
height = width
editImageView!.bounds.size = CGSize(width: width, height: height)
centerAnchor()
}
//垂直翻轉
func verticalRotate() {
rotatey *= -1
editImageView!.imageView.transform = CGAffineTransform(scaleX: rotatex, y: rotatey)
}
//裁切成16:9
func ratio16to9Crop() {
width = editImageView!.bounds.width
height = width / 16 * 9
editImageView!.bounds.size = CGSize(width: width, height: height)
editImageView!.imageView.frame.size = editImageView!.bounds.size
centerAnchor()
}
//順時針翻轉
func clockwiseRotate() {
//90
rotateConstant += ((CGFloat.pi) / 2)
editImageView!.imageView.transform = CGAffineTransform(rotationAngle: rotateConstant )
}
//逆時針翻轉
func anticlockwiseRotate() {
rotateConstant -= ((CGFloat.pi) / 2)
editImageView!.imageView.transform = CGAffineTransform(rotationAngle: rotateConstant )
}
Button按鈕功能的點選配置
@IBAction func showSecondBtn(_ sender: UIButton) {
switch sender{
case secondBtns[0]:
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
//原圖片預設
originalCrop()
imageBackgroundmaxY = editImageView!.frame.maxY
print(imageBackgroundmaxY)
case .typeRotate:
//水平翻轉
horizontalRotate()
case .colorControl:
break
}
case secondBtns[1]:
print("secondBtns")
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
//裁切1:1
squareCrop()
imageBackgroundmaxY = editImageView!.frame.maxY
print(imageBackgroundmaxY)
case .typeRotate:
//垂直翻轉
verticalRotate()
case .colorControl:
break
}
case secondBtns[2]:
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
ratio16to9Crop()
imageBackgroundmaxY = editImageView!.frame.maxY
print(imageBackgroundmaxY)
case .typeRotate:
clockwiseRotate()
case .colorControl:
break
}
case secondBtns[3]:
switch currentMode {
case .typeCrop:
fallthrough
case .typeRatio:
fallthrough
case .typeRotate:
//逆時鐘
anticlockwiseRotate()
case .colorControl:
break
}
default:
break
}
}
//背景色調整
func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
editImageView!.backgroundColor = viewController.selectedColor
}
@IBAction func backgroundColorChange(_ sender: UIButton) {
let controller = UIColorPickerViewController()
controller.delegate = self
present(controller, animated: true, completion: nil)
}
//裁切
@IBAction func typeCropChange(_ sender: UIButton) {
currentMode = .typeCrop
print("typeCrop")
}
存取照片並回傳
func savePhoto(photoImage: UIImage) {
//圖片名字
let photoName = "\(UUID().uuidString).jpg"
//生成圖片資料
let photo = Photo(imageName: photoName)
print("photoName",photoName)
//轉jpeg
let imageData = photoImage.jpegData(compressionQuality: 0.8)
// jpegData存取的位置
let photoUrl = Photo.documentsDirectory.appendingPathComponent(photoName)
print(photoUrl)
//寫入
try? imageData?.write(to: photoUrl)
//加到陣列
photos.append(photo)
//存取進入plist位置
Photo.savePhotoList(photoList: photos)
print("savePhoto")
print(photos)
}
@IBAction func savePhoto(_ sender: UIButton) {
//利用UIGraphicsImageRenderer裝取view圖片
let renderer = UIGraphicsImageRenderer(size: editImageView!.bounds.size)
//呼叫 UIGraphicsImageRenderer 的 function image(actions:) 產生圖片,在傳入的 closure 裡從容器 editImageView 呼叫 function drawHierarchy(in:afterScreenUpdates:),將 editImageView 的內容繪製成圖片,讓 editImageView 和它的 subview 出現在圖片裡。
let image = renderer.image(actions: { (context) in
editImageView!.drawHierarchy(in: editImageView!.bounds, afterScreenUpdates: true)
})
//存圖
savePhoto(photoImage: image)
print("savePhotoIsClick")
//傳值
guard let navigationCotroller = self.navigationController else { return }
let count = navigationCotroller.viewControllers.count
let gobackList = self.navigationController?.viewControllers[ count - 2] as! PictureCollectionViewController
gobackList.photos = photos
//換頁
navigationCotroller.popToViewController(gobackList, animated: true)
}
程式碼: