123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- //
- // PQImageCropVC.swift
- // PQSpeed
- //
- // Created by ak on 2020/8/3.
- // Copyright © 2020 BytesFlow. All rights reserved.
- //
- // add by ak 主要功能 图片裁剪界面
- // e.g.
- // let image = UIImage(named:"img.jpg")!
- // let vc = PQImageCropVC(frame: (self.navigationController?.view.frame)!, image: image, aspectWidth:9, aspectHeight: 16)
- import BFUIKit
- import UIKit
- import BFCommonKit
- class PQImageCropVC: BFBaseViewController, UIScrollViewDelegate {
- var uploadData: PQUploadModel?
- var updataVideoData: PQVideoListModel? // 如果updataVideoData不为空则为修改视频
- var aspectW: CGFloat!
- var aspectH: CGFloat!
- var img: UIImage!
- var imageView: UIImageView!
- var scrollView: UIScrollView!
- var holeRect: CGRect!
- var gap: CGFloat = 100 // 距屏幕边缘距离
- required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") }
- init(image: UIImage, aspectWidth: CGFloat, aspectHeight: CGFloat) {
- super.init(nibName: nil, bundle: nil)
- aspectW = aspectWidth
- aspectH = aspectHeight
- img = image
- BFLog(message: "原图大小 \(img.size) aspectW:\(aspectW!) aspectH:\(aspectH!)")
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- setupView()
- }
- func setupView() {
- let holeWidth = view.frame.width - gap
- BFLog(message: "aspectH :\(String(describing: aspectH))")
- var holeHeight = holeWidth * aspectH / aspectW
- if holeHeight.isNaN {
- holeHeight = 0
- }
- if img.imageOrientation != .up {
- UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
- var rect = CGRect.zero
- rect.size = img.size
- img.draw(in: rect)
- img = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
- }
- holeRect = CGRect(x: 0, y: view.frame.height / 2 - holeHeight / 2, width: holeWidth, height: holeHeight)
- imageView = UIImageView(image: img)
- scrollView = UIScrollView(frame: CGRect(x: gap / 2.0, y: 0, width: holeWidth, height: holeHeight))
- scrollView.center = view.center
- scrollView.addSubview(imageView)
- scrollView.showsVerticalScrollIndicator = false
- scrollView.showsHorizontalScrollIndicator = false
- scrollView.alwaysBounceHorizontal = true
- scrollView.alwaysBounceVertical = true
- scrollView.delegate = self
- view.addSubview(scrollView)
- // 设置最小 zoom 是防止在裁剪区出现黑边导致裁剪后的图不对
- let minZoom = max(holeWidth / img.size.width, holeHeight / img.size.height)
- BFLog(message: "minZoom is: \(minZoom)")
- scrollView.minimumZoomScale = minZoom
- scrollView.maximumZoomScale = minZoom * 4
- // 后设置自动缩放
- scrollView.setZoomScale(minZoom, animated: false)
- scrollView.clipsToBounds = false
- scrollView.contentOffset = CGPoint(x: (img.size.width * minZoom - holeWidth) / 2, y: (img.size.height * minZoom - holeHeight) / 2)
- // 添加 mark layer
- let cropView = UIView(frame: view.frame)
- cropView.isUserInteractionEnabled = false
- view.addSubview(cropView)
- let layer = CAShapeLayer()
- let clipWidth = holeWidth
- let clipHeight = holeHeight
- let cropAreaX = (cScreenWidth - clipWidth) / 2
- let cropAreaY = (cScreenHeigth - clipHeight) / 2
- let cropAreaWidth = clipWidth
- let cropAreaHeight = clipHeight
- let cropframe = CGRect(x: cropAreaX, y: cropAreaY, width: cropAreaWidth, height: cropAreaHeight)
- let path = UIBezierPath(roundedRect: cropView.frame, cornerRadius: 0)
- let cropPath = UIBezierPath(rect: cropframe)
- path.append(cropPath)
- layer.path = path.cgPath
- layer.fillRule = CAShapeLayerFillRule.evenOdd
- layer.fillColor = UIColor.black.cgColor
- layer.opacity = 0.5
- layer.frame = cropView.bounds
- cropView.layer.addSublayer(layer)
- view.bringSubviewToFront(cropView)
- // 单独画线
- let drawLine = DrawLine()
- drawLine.setCropAreaLeft(cropAreaLeft: cropAreaX, cropAreaTop: cropAreaY, cropAreaRight: cropAreaX + cropAreaWidth, cropAreaBottom: cropAreaY + cropAreaHeight)
- drawLine.frame = cropView.bounds
- cropView.layer.addSublayer(drawLine)
- view.bringSubviewToFront(cropView)
- // 添加下边工具条
- view.addSubview(bottomView)
- // 显示引导
- let haveShowGuid = getUserDefaults(key: cIsShowImageCropGuid)
- if haveShowGuid == nil {
- // let guid = PQGuidClipView(frame: view.frame)
- // view.addSubview(guid)
- // saveUserDefaults(key: cIsShowImageCropGuid, value: cIsShowImageCropGuid)
- }
- }
- lazy var bottomView: UIView = {
- let bottomView = UIView(frame: CGRect(x: 0, y: cScreenHeigth - cDevice_iPhoneTabBarHei, width: cScreenWidth, height: cDevice_iPhoneTabBarHei))
- let deleteBtn = UIButton(frame: CGRect(x: cDefaultMargin, y: 0, width: cDevice_iPhoneTabBarHei, height: cDevice_iPhoneTabBarHei))
- bottomView.backgroundColor = BFConfig.shared.styleBackGroundColor
- deleteBtn.setImage(imageInUIKit(by: "icon_detail_back"), for: .normal)
- deleteBtn.addTarget(self, action: #selector(tappedClose), for: .touchUpInside)
- bottomView.addSubview(deleteBtn)
- let selecteBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: cDevice_iPhoneTabBarHei))
- selecteBtn.setTitle("裁剪封面", for: .normal)
- selecteBtn.setTitleColor(.black, for: .normal)
- selecteBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium)
- bottomView.addSubview(selecteBtn)
- selecteBtn.center.x = bottomView.center.x
- let nextBtn = UIButton(frame: CGRect(x: bottomView.frame.width - 100, y: (cDevice_iPhoneTabBarHei - 40) / 2, width: 80, height: 40))
- nextBtn.addCorner(corner: 20)
- nextBtn.setTitle("确定", for: .normal)
- nextBtn.addTarget(self, action: #selector(tappedCrop), for: .touchUpInside)
- nextBtn.setTitleColor(UIColor.white, for: .normal)
- nextBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium)
- nextBtn.backgroundColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
- bottomView.addSubview(nextBtn)
- return bottomView
- }()
- // MARK: scrollView delegate
- func viewForZooming(in _: UIScrollView) -> UIView? {
- BFLog(message: "viewForZooming")
- // 是imageView的容器,实现这个代理保证图片的放大拖动交互
- return imageView
- }
- func scrollViewDidZoom(_ scrollView: UIScrollView) {
- BFLog(message: "scrollViewDidZoom")
- let gapToTheHole = scrollView.frame.height / 2 - holeRect.height / 2
- scrollView.contentInset = UIEdgeInsets(top: gapToTheHole, left: 0, bottom: gapToTheHole, right: 0)
- }
- // 返回
- @objc func tappedClose() {
- BFLog(message: "返回")
- // add by ak bugfix 图片超出 返回异常
- navigationController?.popViewController(animated: true)
- }
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
- scrollView.isHidden = false
- }
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- scrollView.isHidden = true
- }
- // 裁剪
- @objc func tappedCrop() {
- BFLog(message: "开始裁剪图片")
- // 根据scrollView缩放系数和偏移量 对原图进行裁剪
- var imgX: CGFloat = 0
- if scrollView.contentOffset.x > 0 {
- imgX = scrollView.contentOffset.x / scrollView.zoomScale
- }
- let gapToTheHole: CGFloat = 0
- var imgY: CGFloat = 0
- if scrollView.contentOffset.y + 0 > 0 {
- imgY = (scrollView.contentOffset.y + gapToTheHole) / scrollView.zoomScale
- }
- let imgW = holeRect.width / scrollView.zoomScale
- let imgH = holeRect.height / scrollView.zoomScale
- print("IMG x: \(imgX) y: \(imgY) w: \(imgW) h: \(imgH)")
- let cropRect = CGRect(x: imgX, y: imgY, width: imgW, height: imgH)
- let imageRef = img.cgImage!.cropping(to: cropRect)
- let croppedImage = UIImage(cgImage: imageRef!)
- // 这个方法是使用view 截屏
- // let croppedImage : UIImage = scrollView.graphicsGetImage() ?? img
- BFLog(message: "croppedImage\(croppedImage.size)")
- postNotification(name: cSelectedImageSuccessKey, userInfo: ["image": croppedImage])
- let publicVideoVC = navigationController?.viewControllers.first(where: { (vc) -> Bool in
- vc is PQStuckPointPublicController
- })
- if publicVideoVC != nil {
- navigationController?.popToViewController(publicVideoVC!, animated: true)
- } else {
- navigationController?.popViewController(animated: true)
- }
- }
- }
- class DrawLine: CAShapeLayer {
- var mCropAreaLeft: CGFloat = 0
- var mCropAreaTop: CGFloat = 0
- var mCropAreaRight: CGFloat = cScreenWidth
- var mCropAreaBottom: CGFloat = 0
- let mLineWidth: CGFloat = 7
- func setCropAreaLeft(cropAreaLeft: CGFloat, cropAreaTop: CGFloat, cropAreaRight: CGFloat, cropAreaBottom: CGFloat) {
- mCropAreaLeft = cropAreaLeft
- mCropAreaTop = cropAreaTop
- mCropAreaRight = cropAreaRight
- mCropAreaBottom = cropAreaBottom
- setNeedsDisplay()
- }
- override func draw(in ctx: CGContext) {
- UIGraphicsPushContext(ctx)
- ctx.setStrokeColor(UIColor.white.cgColor)
- ctx.setLineWidth(mLineWidth)
- ctx.addRect(CGRect(x: mCropAreaLeft, y: mCropAreaTop, width: mCropAreaRight - mCropAreaLeft, height: mCropAreaBottom - mCropAreaTop))
- // 必和路径
- ctx.strokePath()
- UIGraphicsPopContext()
- }
- }
|