Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UIImageView:如何在平移和平移之后捕获可见内容;快速移动_Ios_Swift_Uiimageview_Cgaffinetransform - Fatal编程技术网

Ios UIImageView:如何在平移和平移之后捕获可见内容;快速移动

Ios UIImageView:如何在平移和平移之后捕获可见内容;快速移动,ios,swift,uiimageview,cgaffinetransform,Ios,Swift,Uiimageview,Cgaffinetransform,我有一个UIImageView,它由ImagePicker加载,带有一张照片(3k x 4k大小),使用AspectFit模式填充到视图中。然后,我用手势识别器平移和缩放图像,该识别器可以调整视图的变换比例和平移。这很有效,下面是代码: @objc private func startZooming(_ sender: UIPinchGestureRecognizer) { let scaleResult = sender.view?.transform.scaledBy(x: sender

我有一个UIImageView,它由ImagePicker加载,带有一张照片(3k x 4k大小),使用AspectFit模式填充到视图中。然后,我用手势识别器平移和缩放图像,该识别器可以调整视图的变换比例和平移。这很有效,下面是代码:

@objc private func startZooming(_ sender: UIPinchGestureRecognizer) {
  let scaleResult = sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)
  guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
  sender.view?.transform = scale
  sender.scale = 1
}
  
@objc private func startPanning(_ sender: UIPanGestureRecognizer) {
    let translate = sender.translation(in: mainImageView)
    let center = mainImageView.center
    mainImageView.center = CGPoint(x: center.x + translate.x, y: center.y + translate.y)
    self.currImageTranslation.x += translate.x
    self.currImageTranslation.y += translate.y
    sender.setTranslation(CGPoint(x: 0, y: 0), in: mainImageView)
}
我的问题是,我需要转换产生的视觉结果作为CGImage输入视觉推理引擎。当我从UIImageView获取图像时:

let image = myUIImageView.image // I get the original untransformed image
当我尝试时:

UIGraphicsBeginImageContextWithOptions(image!.size, false, 0.0)
  myImageView.layer.render(in: UIGraphicsGetCurrentContext()!)
  let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let rect = mainImageView.bounds
let scale = UIScreen.main.scale
var t = self.currImageTranslation
let tScale = mainImageView.transform.a
let zoomOffsetFactorX = ((t.x /  rect.size.width) * tScale)
let zoomOffsetFactorY = ((t.y / rect.size.height) * tScale)
t.x = t.x - zoomOffsetFactorX
t.y = (t.y + 20.0) + zoomOffsetFactorY

// create a context
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()!
let transform = mainImageView.transform
let imrect = CGRect(origin: t, size: rect.size)
context.concatenate(transform)
let tempImage = mainImageView.image
tempImage!.draw(in: imrect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
新图像也是原始图像(未转换)

当我尝试时:

UIGraphicsBeginImageContextWithOptions(image!.size, false, 0.0)
  myImageView.layer.render(in: UIGraphicsGetCurrentContext()!)
  let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let rect = mainImageView.bounds
let scale = UIScreen.main.scale
var t = self.currImageTranslation
let tScale = mainImageView.transform.a
let zoomOffsetFactorX = ((t.x /  rect.size.width) * tScale)
let zoomOffsetFactorY = ((t.y / rect.size.height) * tScale)
t.x = t.x - zoomOffsetFactorX
t.y = (t.y + 20.0) + zoomOffsetFactorY

// create a context
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()!
let transform = mainImageView.transform
let imrect = CGRect(origin: t, size: rect.size)
context.concatenate(transform)
let tempImage = mainImageView.image
tempImage!.draw(in: imrect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
新图像将正确转换,但仅在比例=1.0时,缩放或不缩放将创建分数图像,即剪裁到零原点

我想生成一个用户在该ImageView屏幕上看到的UIImage。有人能帮忙吗

在@DonMag慷慨的建议下,我尝试了以下方法:

func enableZoom() {
  let pinchGesture = UIPinchGestureRecognizer(target: self, 
                action: #selector(startZooming(_:)))
  let panGesture = UIPanGestureRecognizer(target: self, 
                action: #selector(startPanning(_:)))
    containerView.isUserInteractionEnabled = true
    containerView.addGestureRecognizer(pinchGesture)
    containerView.addGestureRecognizer(panGesture)
}


@objc private func startZooming(_ sender: UIPinchGestureRecognizer) {
  let scaleResult = sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)
  guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
  sender.view?.transform = scale
  newImage()
  sender.scale = 1
}
  
@objc private func startPanning(_ sender: UIPanGestureRecognizer) {
    let translate = sender.translation(in: mainImageView)
    let center = mainImageView.center
    mainImageView.center = CGPoint(x: center.x + translate.x, y: center.y + translate.y)
    self.currImageTranslation.x += translate.x
    self.currImageTranslation.y += translate.y
    sender.setTranslation(CGPoint(x: 0, y: 0), in: mainImageView)
    newImage()
}

//MARK:- create cropped/panned image and infer
func newImage() -> Void {
    
    let format = UIGraphicsImageRendererFormat()
    // we want a 1:1 points-to-pixels output
    format.scale = 1
    let renderer = UIGraphicsImageRenderer(size: containerView.bounds.size, format: format)
    let image = renderer.image { ctx in
        containerView.drawHierarchy(in: containerView.bounds, afterScreenUpdates: true)
    }
    self.currCGImage = image.cgImage
    //repeatInference()   // runs only once every 0.3 s
    return
}
  

现在,“新形象”正确地反映了泛感觉创造的翻译,但似乎忽略了尺度上的细微变化。drawHierarchy似乎忽略了UIView中强加的转换。我哪里出错了?

我不完全确定您在用转换代码做什么,但这可能对您有用——而且更简单

如果我理解正确,您有一个带有
.aspectFit
UIImageView
,它位于
UIView
的“容器”中,您可以对图像视图应用缩放和平移变换:

    let format = UIGraphicsImageRendererFormat()
    // we want a 1:1 points-to-pixels output
    format.scale = 1
    let renderer = UIGraphicsImageRenderer(size: containerView.bounds.size, format: format)
    let image = renderer.image { ctx in
        containerView.drawHierarchy(in: containerView.bounds, afterScreenUpdates: true)
    }
下面是一个完整的示例实现:

class TransImageViewController: UIViewController {

    let containerView = UIView()
    let imageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let img = UIImage(named: "bkg_2400x1600") else {
            fatalError("Could not load the image!!!")
        }
        
        let stack = UIStackView()
        stack.spacing = 20
        stack.distribution = .fillEqually
        
        let b1 = UIButton()
        let b2 = UIButton()
        
        [b1, b2].forEach { b in
            b.backgroundColor = .red
            b.setTitleColor(.white, for: .normal)
            b.setTitleColor(.gray, for: .highlighted)
        }
        
        b1.setTitle("Transform", for: [])
        b2.setTitle("Capture", for: [])
        
        stack.addArrangedSubview(b1)
        stack.addArrangedSubview(b2)

        [stack, containerView, imageView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
        }
        
        view.addSubview(stack)
        view.addSubview(containerView)
        containerView.addSubview(imageView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            // buttons stack at top
            stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
            
            // container 400x500 centered
            containerView.widthAnchor.constraint(equalToConstant: 400),
            containerView.heightAnchor.constraint(equalToConstant: 500),
            containerView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            containerView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
            // imageView constrained all 4 sides to container
            imageView.topAnchor.constraint(equalTo: containerView.topAnchor),
            imageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
            imageView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),

        ])
        
        containerView.clipsToBounds = true
        imageView.contentMode = .scaleAspectFit
        imageView.image = img
        
        view.backgroundColor = .blue
        containerView.backgroundColor = .yellow
        imageView.backgroundColor = .orange

        b1.addTarget(self, action: #selector(self.doTransform), for: .touchUpInside)
        b2.addTarget(self, action: #selector(self.grabImage), for: .touchUpInside)
    }

    @objc func doTransform() -> Void {
        var t = CGAffineTransform.identity
        t = t.scaledBy(x: 4.0, y: 4.0)
        t = t.translatedBy(x: -120, y: 40)
        imageView.transform = t
    }
    
    @objc func grabImage() -> Void {

        let format = UIGraphicsImageRendererFormat()
        // we want a 1:1 points-to-pixels output
        format.scale = 1
        let renderer = UIGraphicsImageRenderer(size: containerView.bounds.size, format: format)
        let image = renderer.image { ctx in
            containerView.drawHierarchy(in: containerView.bounds, afterScreenUpdates: true)
        }
        
        // do what you want with the resulting image
        print("Resulting image size:", image.size)

    }

}
将此图像用作我的“bkg_2400x1600”图像资源:

上面的代码是这样开始的(我的“容器”视图是400x500分):

点击“转换”按钮适用于
。缩放比(x:4.0,y:4.0)
。平移比(x:-120,y:40)

然后点击“捕获”按钮,我可以看到这个400x500像素的图像:


@DonMag让我走上了正确的道路。然而,为了在抓取的图像中获得正确的缩放,我需要将scaleBy变换应用于UIImageView,而不是containerview。此外,我还需要将格式比例设置为pinchGesture中的当前比例因子。以下是工作版本:

    func enableZoom() {
      let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(startZooming(_:)))
      let panGesture = UIPanGestureRecognizer(target: self, action: #selector(startPanning(_:)))
        containerView.isUserInteractionEnabled = true
        containerView.addGestureRecognizer(pinchGesture)
        containerView.addGestureRecognizer(panGesture)
    }

    @objc private func startZooming(_ sender: UIPinchGestureRecognizer) {
//        let scaleResult = sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)
//        guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
//        sender.view?.transform = scale
      let scaleResult = mainImageView?.transform.scaledBy(x: sender.scale, y: sender.scale)
      guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
      mainImageView.transform = scale
      currImageScale = sender.scale
      newImage()
      sender.scale = 1
    }
      
    @objc private func startPanning(_ sender: UIPanGestureRecognizer) {
        let translate = sender.translation(in: mainImageView)
        let center = mainImageView.center
        mainImageView.center = CGPoint(x: center.x + translate.x, y: center.y + translate.y)
        self.currImageTranslation.x += translate.x
        self.currImageTranslation.y += translate.y
        sender.setTranslation(CGPoint(x: 0, y: 0), in: mainImageView)
        newImage()
    }
    
    //MARK:- create cropped/panned image and infer
    func newImage() -> Void {
        
        let format = UIGraphicsImageRendererFormat()
        // we want a 1:1 points-to-pixels output
        format.scale = currImageScale
        let renderer = UIGraphicsImageRenderer(size: containerView.bounds.size, format: format)
        let image = renderer.image { ctx in
            containerView.drawHierarchy(in: containerView.bounds, afterScreenUpdates: true)
        }
        self.currCGImage = image.cgImage
        repeatInference()   // runs only once every 0.3 s
        return
    }
    
    

为了澄清。。。您想要原始图像的大小吗?还是屏幕尺寸?例如,如果您的scrollview在@2x设备上是200x200分,并且您的zoom显示的是3k x 4k图像的1600x1600部分。。。是否希望结果是1600x1600矩形缩小为400x400像素图像?还是要从原始图像中剪裁1600x1600像素的矩形?感谢您的回复!为了尝试澄清,我没有使用卷轴和播放内容大小。只需在图像视图中对UIImage进行变换/转换。uiimageview在plus手机上约为440x500,这是我想要退回的尺寸。本质上类似于视图的位图。推理机将根据需要进行缩放/裁剪。这个答案有部分答案。肯定没有一个简短的答案。看起来很完美!将在几个小时内进行测试,并将很快标记为正确。非常感谢!我修改了ViewController,将目标图像视图放置在容器UIView中,并将userInteractions/GestureRecognitors设置为容器UIView。抓取的图像现在在帧中按预期移动,但是,收缩手势(即缩放或放大容器)在屏幕上确实会改变,但不会改变抓取的图像。抓取的图像不会放大。我正在修改OP以包含当前的相关代码。