关于ios:仿扫描全能王的选择区域功能拍照旋转

35次阅读

共计 3630 个字符,预计需要花费 10 分钟才能阅读完成。

拍照,用零碎的,简略

本文次要是讲,抉择区域的旋转

  • 照片的旋转,用仿射变换
  • 抉择区域的旋转,就是旋转坐标系中的点,有一个坐标变换

手机 UIKit 框架下,view 的坐标系原点,是 view 的左上角

旋转坐标系中的点,个别坐标系用核心,不便


拍照,略。开始旋转抉择区域

1,摆放好

下面有两个视图,放照片的 UIImageView, 和照片上拖拽视图 sketch

布局没有采纳,束缚

因为旋转的时候,他们的 frame 变来变去,

间接手动计算 frame,更加的直观

         if let img = image{let s = img.size.size(in: measure.s)
        
            imgView.frame.size = s
            imgView.center = measure.center
            sketch.frame = imgView.frame
            // 照片
            view.addSubview(imgView)
            // 照片上的,拖拽区域
            view.addSubview(sketch)
            // ...
        }

零碎拍照,默认分辨率,4:3

为了简化计算,这里 imageView 的高 / 宽 = 其 image 的高 / 宽

拍照的图片,很大,适合的放在指定的小区域中

extension CGSize{func size(in std: CGSize) -> CGSize{
        
        let hRatio = height / std.height
        let wRatio = width / std.width
        
        let reSolution = height / width
        
        
        let s: CGSize
        
        if hRatio > wRatio{
            //  图片更窄
            s = CGSize(width: std.height / reSolution, height: std.height)
        }
        else{
            //  图片更宽
            s = CGSize(width: std.width, height: std.width * reSolution)
        }
        return s
        
    }
}

2,旋转

从图 a 到图 b , 是一个右旋

  • 旋转抉择区域视图,为了简化计算,旋转抉择区域的 frame 与看到的图片贴合

替换抉择区域的宽和高,就是批改尺寸 size,

复原其原来的中心点 center , 就是更新其原点

  • 旋转抉择区域视图,上的四个拖拽点,

先在原来的坐标系中,旋转角度,

抉择区域视图的原点变了,四个拖拽点旋转角度后,还需一个平移的弥补



    // 记录以后的角度
    var angle: CGFloat = 0

    @objc func rightTurn(){rotate(with: .rhs)
    }
    
    
    
    func rotate(with direction: RotateOpt) {
        
        let sizeOld = sketch.frame.size
        let originOld = sketch.frame.origin
        let center = sketch.center
  
        switch direction {
        case .lhs:
            
            // 逆时针
            
            angle -= 1
            
            
            sketch.defaultPoints.update(clockwize: false, by: sizeOld)
        case .rhs:
            
            // 顺时针
            
            angle += 1
            // 旋转四个点
            sketch.defaultPoints.update(clockwize: true, by: sizeOld)
            
        }
        
        
        // 图片视图,间接仿射变换
        imgView.transform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle)
        
        sketch.frame.size = CGSize(width: sizeOld.height, height: sizeOld.width)
       
       
        sketch.center = center
        let originNew = sketch.frame.origin
        // 再弥补四个点
        sketch.defaultPoints.patch(vector: originNew - originOld)
        
        
        // 更新绘制
        sketch.reloadData()}

旋转点的坐标,通过角度的变动,计算


    // 拿 size, 去算中心点
    mutating
    func update(clockwize beC: Bool, by area: CGSize){
        let lhsTop: CGPoint, rhsTop: CGPoint, rhsBottom: CGPoint, lhsBottom: CGPoint
        let center = CGPoint(x: area.width / 2, y: area.height / 2)
        if beC{lhsTop = clockwize(rightTurn: leftTop, forCoordinate: center)
            // ...
        }
        else{lhsTop = antiClockwize(leftTurn: leftTop, forCoordinate: center)
            // ...
        }
        leftTop = lhsTop
        // ...
        
       
    }
    
    // 顺时针旋转
    private
      func clockwize(rightTurn target: CGPoint, forCoordinate origin: CGPoint) -> CGPoint {
          let dx = target.x - origin.x
          let dy = target.y - origin.y
          let radius = sqrt(dx * dx + dy * dy)
          let azimuth = atan2(dy, dx) // in radians
          let x = origin.x - radius * sin(azimuth)
          let y = origin.y + radius * cos(azimuth)
          return CGPoint(x: x, y: y)
      }

3,旋转增强,为了更好的利用手机区域,图片竖着更大,横着稍小一些

图片视图,仿射变换,是旋转 rotate + 缩放 scale

抉择区域视图 sketch, 不能简略的替换宽和高,

稍麻烦了一些

抉择区域视图 sketch 的 frame, 中心点不变,他的 size 有两个抉择,切换就好了

在上一步的根底上,计算抉择区域视图 sketch 的四个坐标
  • 竖着的,转横着的,大变小,上一步的坐标,放大就行
  • 横着的,转竖着的,小变大,先放大,再用规范坐标(竖着的尺寸,替换后),投入计算
func rotate(with direction: RotateOpt) {
        guard let img = image else {return}
        
        let imgRatio = img.size.height / img.size.width
        let const = 4.0/3
        print(imgRatio, const)
        
        let sizeOld = sketch.frame.size
        let originOld = sketch.frame.origin
        let center = sketch.center
        let bigS = img.size.size(in: measure.s)
        let clockwize: Bool
        switch direction {
        case .lhs:
            
            // 逆时针
            
            angle -= 1
            clockwize = false
            
            
        case .rhs:
            
            // 顺时针
            
            angle += 1
            clockwize = true
            
            // 下一步,对 UI 的批改,影响上一步
            
        }
        
        
        
        var ratio: CGFloat = 1
        
        let smallS = img.size.size(by: measure.horizontal)
        
        var imgTransform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle)
        if Int(angle) % 2 == 1{
            ratio = smallS.width / bigS.height
            imgTransform = imgTransform.scaledBy(x: ratio, y: ratio)
            sketch.frame.size = smallS
           
        }
        else{
            ratio = bigS.height / smallS.width
            sketch.frame.size = bigS
            
        }
     
        // 旋转四个拖拽的点之前,先复位
        
        // 小的,变大的,的时候,须要操作
        if Int(angle) % 2 == 0{sketch.defaultPoints.scale(r: ratio, forS: sizeOld)
        }

        // 旋转,和平移弥补之前,先化为标注的,也就是竖着的尺寸

        sketch.defaultPoints.update(clockwize: clockwize, by: sizeOld)
        imgView.transform = imgTransform
        
       
        sketch.center = center
        let originNew = sketch.frame.origin
        // 弥补,跟上一步一样
        sketch.defaultPoints.patch(vector: originNew - originOld)
        
        
        //  四个拖拽的点,属于失常规范的图片
        
        // 横着摆放,大变小
        if Int(angle) % 2 == 1{sketch.defaultPoints.scale(r: ratio, forS: sizeOld)
        }
        
        // 绘制
        sketch.reloadData()}

前文,低仿扫描全能王的抉择区域性能

github repo

正文完
 0