【问题标题】:UIGraphicsGetImageFromCurrentContext and preserve aspect ratioUIGraphicsGetImageFromCurrentContext 并保持纵横比
【发布时间】:2017-08-31 16:46:05
【问题描述】:

我正在尝试实现一个UIImageView 子类,它允许用户用手指在图像视图中绘图。我的UIImageView 的 contentMode 设置为Aspect Fill。我注意到,当我的绘图代码执行并从图形上下文中提取生成的图像时,它正在以Scale to Fill 类型格式进行缩放,这不是我想要的。我想知道是否有人知道如何实现提取此图像并保持图像的纵横比。

class DrawImageView : UIImageView {

    var lastTouchPoint = CGPoint.zero
    var isSwiping = false

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        isSwiping = false 
        if let touchPoint = touches.first {
            lastTouchPoint = touchPoint.location(in: self)
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        isSwiping = true

        if let touchPoint = touches.first {
            let currentPoint = touchPoint.location(in: self)
            UIGraphicsBeginImageContext(frame.size)

            image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))

            if let context = UIGraphicsGetCurrentContext() {
                context.move(to: lastTouchPoint)
                context.addLine(to: currentPoint)
                context.setLineCap(CGLineCap.round)
                context.setLineWidth(9.0)
                context.setStrokeColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
                context.strokePath()
                image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                lastTouchPoint = currentPoint
            }
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if(!isSwiping) {

            UIGraphicsBeginImageContext(frame.size)
            image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))


            if let context = UIGraphicsGetCurrentContext() {
                context.setLineCap(CGLineCap.round)
                context.setLineWidth(9.0)
                context.setStrokeColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
                context.move(to: lastTouchPoint)
                context.addLine(to: lastTouchPoint)
                context.strokePath()
                image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
            }
        }
    }
}

【问题讨论】:

    标签: ios swift cocoa-touch uiimageview


    【解决方案1】:

    使用此代码:

    UIGraphicsBeginImageContext(frame.size)
    image?.draw(in: CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height))
    

    您是在说“将这张完整的图像 - 无论大小或纵横比 - 绘制成一个宽 x 高尺寸的矩形。”因此,如果 image 的“原始”大小为 300 x 200,而您的 frame 为 200 x 200,那么这就是要绘制图像的位置。

    为避免这种情况,您需要计算要绘制的正确矩形。使用这些尺寸,你会想要做(用于方面填充):

    image?.draw(in: CGRect(x:-50, y:0, width:frame.size.width + 50, height:frame.size.height))
    

    当然,您可以运行快速计算来确定实际数字,而不是硬编码值。

    【讨论】:

      【解决方案2】:

      我最终发现并用于提供方面填充矩形和方面适合矩形的函数如下:

       func getAspectFillFrame(sizeImageView : CGSize, sizeImage: CGSize) -> CGRect {
      
              let aspect = sizeImage.width / sizeImage.height
              let rect: CGRect
      
              if sizeImageView.width / aspect > sizeImageView.height {
      
                  let height = sizeImageView.width / aspect
      
                  rect = CGRect(x: 0, y: (sizeImageView.height - height) / 2,
                                width: sizeImageView.width, height: height)
      
              } else {
                  let width = sizeImageView.height * aspect
                  rect = CGRect(x: (sizeImageView.width - width) / 2, y: 0,
                                width: width, height: sizeImageView.height)
              }
      
              return rect
      
          }
      
          func getAspectFitFrame(sizeImgView:CGSize, sizeImage:CGSize) -> CGRect {
      
              let imageSize:CGSize  = sizeImage
              let viewSize:CGSize = sizeImgView
      
              let hfactor : CGFloat = imageSize.width/viewSize.width
              let vfactor : CGFloat = imageSize.height/viewSize.height
      
              let factor : CGFloat = max(hfactor, vfactor)
      
              // Divide the size by the greater of the vertical or horizontal shrinkage factor
              let newWidth : CGFloat = imageSize.width / factor
              let newHeight : CGFloat = imageSize.height / factor
      
              var x:CGFloat = 0.0
              var y:CGFloat = 0.0
              if newWidth > newHeight{
                  y = (sizeImgView.height - newHeight)/2
              }
              if newHeight > newWidth{
                  x = (sizeImgView.width - newWidth)/2
              }
              let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight)
      
              return newRect
      
          }
      

      【讨论】: