SwiftUI - 缩放、缩放和裁剪图像

Posted

技术标签:

【中文标题】SwiftUI - 缩放、缩放和裁剪图像【英文标题】:SwiftUI - Scale, Zoom and Crop Image 【发布时间】:2020-01-23 17:37:25 【问题描述】:

使用link to repository编辑。

我正在使用 SwiftUI,因此无法访问“裁剪视图”。我使用手势而不是 ScrollView 来捕获图像的缩放级别和偏移量(x 和 y)。我无法返回根据这些因素正确裁剪的图像。

似乎 SwiftUI 本身可能是一个因素。也许在确定偏移量和缩放级别时需要考虑视图中图像的偏移量?

我有图像,并且我有来自视图上的手势的以下值来表示比例和 x/y 位置:

 @State var scale: CGFloat = 1.0
 @State var currentPosition: CGSize = CGSize.zero

当前尝试,与调用的函数最接近:

func prepareImage( ) 

        let imageToManipulate =  UIImage(named: "landscape")
        let currentPositionWidth = self.currentPosition.width
        let currentPositionHeight = self.currentPosition.height
        let zoomScale = self.scale
        let imsize = imageToManipulate!.size

        var scale : CGFloat = self.frameSize.width / imsize.width
        if imsize.height * scale < self.frameSize.height 
            scale = self.frameSize.height / imsize.height
        
        let croppedImsize = CGSize(width: (self.frameSize.width/scale) / zoomScale, height: (self.frameSize.height/scale) / zoomScale)
        let xOffset = (( imsize.width - croppedImsize.width ) / 2.0) - (currentPositionWidth / zoomScale)
        let yOffset = (( imsize.height - croppedImsize.height) / 2.0) - (currentPositionHeight / zoomScale)
        let croppedImrect: CGRect = CGRect(x: xOffset, y: yOffset, width: croppedImsize.width, height: croppedImsize.height)

        let r = UIGraphicsImageRenderer(size:croppedImsize)
        let croppedIm = r.image  _ in
            imageToManipulate!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
        
        self.croppedImage = croppedIm
        self.photoIsFinished = true
    

但是,正如您将在存储库中看到的那样,当结合缩放/缩放和 x/y 偏移时,它总是有点“关闭”。

同样,当您尝试裁剪为方形图像时,“关闭”的数量可能非常大。

【问题讨论】:

虽然我发现 SwiftUI 在图像方面非常 缺乏,但实际上发布的代码中似乎没有多少是由于 SwiftUI - 我没有看到 @987654324 @ 看法。因此,让我们更深入地研究一下 - 您是在处理 UIImage(关于 SwiftUI 当前使用的唯一东西)还是像 CGImageCIImage 这样的其他东西?相信我,这很重要。如果您 正在 实际处理视图 - 为什么?操纵图像,而不是仅渲染图像的视图。即使这意味着进入 UIKit。 嗯,是的 - 抱歉 - 我正在使用 UIImage。我已经编辑了我的问题。我只提到 SwiftUI 是因为我可以找到一些代码,其中包括使用 view.bounds 等,所以我无法弄清楚我在尝试像上面那样操作 UIImage 时做错了什么。 我很快需要对 CIImage 进行裁剪。我真的无法解决 CGImage,ubt UIImage/CIImage 有一个共同点 - 大小(对于 UIImage)和范围(对于 CIImage)。由于我需要 CIImage,我将使用 CICrop 过滤器 - 通过 UIView 的框架调整所有内容。基本上,(1)让裁剪的“目标”是一个带有边框的 UIView,(2)将其调整为实际图像大小,(3)裁剪 CIImage,(4)小夜曲,让scaleAspectFit 渲染它正确地显示在屏幕上。不确定这是否会对您有所帮助 - 但由于 SwiftUI 的局限性,谁知道呢。 @dfd 我用代码库更新了。当您达到这一点时,您可能会发现它很有用。我已经解决了我认为您打算做的事情,但仍然无法获得返回正确结果的函数。查看我编辑的问题和存储库。 存储库链接再次断开 【参考方案1】:

感谢Asperi's answer,我实现了一个轻量级的swiftUI库来裁剪图像。这里是库和演示。Here

魔法如下:

    public var body: some View 
        GeometryReader  proxy  in
           // ...
                        
                        Button(action: 
  // how to crop the image according to rectangle area
                            if self.tempResult == nil 
                                self.cropTheImageWithImageViewSize(proxy.size)
                            
                            self.resultImage = self.tempResult
                        )  
            Text("Crop Image")
                .padding(.all, 10)
                .background(Color.blue)
                .foregroundColor(.white)
                .shadow(color: .gray, radius: 1)
                .padding(.top, 50)
        
                    
  

func cropTheImageWithImageViewSize(_ size: CGSize) 

    let imsize =  inputImage.size
    let scale = max(inputImage.size.width / size.width,
                    inputImage.size.height / size.height)

    
    let zoomScale = self.scale

    let currentPositionWidth = self.dragAmount.width * scale
        let currentPositionHeight = self.dragAmount.height * scale
    
    let croppedImsize = CGSize(width: (self.cropSize.width * scale) / zoomScale, height: (self.cropSize.height * scale) / zoomScale)
     
    let xOffset = (( imsize.width - croppedImsize.width) / 2.0) - (currentPositionWidth  / zoomScale)
    let yOffset = (( imsize.height - croppedImsize.height) / 2.0) - (currentPositionHeight  / zoomScale)
    let croppedImrect: CGRect = CGRect(x: xOffset, y: yOffset, width: croppedImsize.width, height: croppedImsize.height)
          
    if let cropped = inputImage.cgImage?.cropping(to: croppedImrect) 
       //uiimage here can write to data in png or jpeg
        let croppedIm = UIImage(cgImage: cropped)
        tempResult = croppedIm
        result = Image(uiImage: croppedIm)
    

【讨论】:

【参考方案2】:

juanjjuanj通过 GitHub 存储库提供了答案

let imageToManipulate =  UIImage(named: "landscape")
let zoomScale = self.scale
let imsize = imageToManipulate!.size

var scale : CGFloat = self.frameSize.width / imsize.width
if imsize.height * scale < self.frameSize.height 
 scale = self.frameSize.height / imsize.height

let currentPositionWidth = self.currentPosition.width / scale
let currentPositionHeight = self.currentPosition.height / scale
let croppedImsize = CGSize(width: (self.frameSize.width/scale) / zoomScale, height: (self.frameSize.height/scale) / zoomScale)
let xOffset = (( imsize.width - croppedImsize.width ) / 2.0) - (currentPositionWidth / zoomScale)
let yOffset = (( imsize.height - croppedImsize.height) / 2.0) - (currentPositionHeight / zoomScale)
let croppedImrect: CGRect = CGRect(x: xOffset, y: yOffset, width: croppedImsize.width, height: croppedImsize.height)

let r = UIGraphicsImageRenderer(size:croppedImsize)
let croppedIm = r.image  _ in
            imageToManipulate!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
        
self.croppedImage = croppedIm
self.photoIsFinished = true

完整代码,演示如何允许用户在 SwiftUI 视图中缩放和平移帧内的图像,然后将结果裁剪为新图像,可以是viewed in the repository。

【讨论】:

嗨@dot3,github 存储库网址似乎不再存在。你能检查一下吗?我想看看它。谢谢 @atulkhatri 和其他人正在寻找 - juanj 仍然有他的版本:github.com/juanj/CropTestSwiftUI

以上是关于SwiftUI - 缩放、缩放和裁剪图像的主要内容,如果未能解决你的问题,请参考以下文章

JS:图像上传实时操作、缩放、尺寸和裁剪

在 UIScrollView 问题中裁剪缩放图像

缩放图像以在android中裁剪

在 iOS 中以圆形格式裁剪和缩放图像

如何缩放 + 裁剪图像并在 imageview 上显示裁剪的图像

裁剪缩放“Android”的图像