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 当前使用的唯一东西)还是像 CGImage
或 CIImage
这样的其他东西?相信我,这很重要。如果您 正在 实际处理视图 - 为什么?操纵图像,而不是仅渲染图像的视图。即使这意味着进入 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 - 缩放、缩放和裁剪图像的主要内容,如果未能解决你的问题,请参考以下文章