gpt4 book ai didi

ios - 如何在 'aspect fill' 模式下将 UIImageView 裁剪为新的 UIImage?

转载 作者:行者123 更新时间:2023-11-30 11:40:22 24 4
gpt4 key购买 nike

我正在尝试使用可以放置在 UIImageView 中任何位置的覆盖 UIView 来裁剪 ImageView 的子图像。我借用了类似帖子中的解决方案,了解当 UIImageView 内容模式为“Aspect Fit”时如何解决此问题。建议的解决方案是:

  func computeCropRect(for sourceFrame : CGRect) -> CGRect {

let widthScale = bounds.size.width / image!.size.width
let heightScale = bounds.size.height / image!.size.height

var x : CGFloat = 0
var y : CGFloat = 0
var width : CGFloat = 0
var height : CGFloat = 0
var offSet : CGFloat = 0

if widthScale < heightScale {
offSet = (bounds.size.height - (image!.size.height * widthScale))/2
x = sourceFrame.origin.x / widthScale
y = (sourceFrame.origin.y - offSet) / widthScale
width = sourceFrame.size.width / widthScale
height = sourceFrame.size.height / widthScale
} else {
offSet = (bounds.size.width - (image!.size.width * heightScale))/2
x = (sourceFrame.origin.x - offSet) / heightScale
y = sourceFrame.origin.y / heightScale
width = sourceFrame.size.width / heightScale
height = sourceFrame.size.height / heightScale
}

return CGRect(x: x, y: y, width: width, height: height)
}

问题是,当 ImageView 进行宽高比填充时使用此解决方案会导致裁剪的片段与覆盖 UIView 的位置不完全对齐。我不太确定如何调整此代码以适应宽高比填充或重新定位我的覆盖层 UIView ,使其与我尝试裁剪的片段以 1:1 的比例对齐。

更新使用下面马特的答案解决了

class ViewController: UIViewController {

@IBOutlet weak var catImageView: UIImageView!
private var cropView : CropView!

override func viewDidLoad() {
super.viewDidLoad()

cropView = CropView(frame: CGRect(x: 0, y: 0, width: 45, height: 45))

catImageView.image = UIImage(named: "cat")
catImageView.clipsToBounds = true

catImageView.layer.borderColor = UIColor.purple.cgColor
catImageView.layer.borderWidth = 2.0
catImageView.backgroundColor = UIColor.yellow

catImageView.addSubview(cropView)

let imageSize = catImageView.image!.size
let imageViewSize = catImageView.bounds.size

var scale : CGFloat = imageViewSize.width / imageSize.width

if imageSize.height * scale < imageViewSize.height {
scale = imageViewSize.height / imageSize.height
}

let croppedImageSize = CGSize(width: imageViewSize.width/scale, height: imageViewSize.height/scale)

let croppedImrect =
CGRect(origin: CGPoint(x: (imageSize.width-croppedImageSize.width)/2.0,
y: (imageSize.height-croppedImageSize.height)/2.0),
size: croppedImageSize)

let renderer = UIGraphicsImageRenderer(size:croppedImageSize)

let _ = renderer.image { _ in
catImageView.image!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
}
}


@IBAction func performCrop(_ sender: Any) {
let cropFrame = catImageView.computeCropRect(for: cropView.frame)
if let imageRef = catImageView.image?.cgImage?.cropping(to: cropFrame) {
catImageView.image = UIImage(cgImage: imageRef)
}
}

@IBAction func resetCrop(_ sender: Any) {
catImageView.image = UIImage(named: "cat")
}
}

最终结果 enter image description here

最佳答案

让我们将问题分为两部分:

  1. 给定 UIImageView 的大小及其 UIImage 的大小,如果 UIImageView 的内容模式是 Aspect Fill,UIImage 的哪一部分适合 UIImageView?实际上,我们需要裁剪原始图像以匹配 UIImageView 实际显示的内容。

  2. 给定 UIImageView 中的任意矩形,它对应于裁剪图像的哪一部分(在第 1 部分中导出)?

第一部分是有趣的部分,所以让我们尝试一下。 (第二部分将变得微不足道。)

这是我将使用的原始图像:

https://static1.squarespace.com/static/54e8ba93e4b07c3f655b452e/t/56c2a04520c64707756f4267/1455596221531/

该图像的尺寸为 1000x611。这是缩小后的样子(但请记住,我将在整个过程中使用原始图像):

enter image description here

但是,我的 ImageView 将为 139x182,并且设置为宽高比填充。当它显示图像时,它看起来像这样:

enter image description here

我们要解决的问题是:如果我的 ImageView 设置为纵横比填充,原始图像的哪一部分将显示在我的 ImageView 中?

我们开始吧。假设 iv 是 ImageView :

let imsize = iv.image!.size
let ivsize = iv.bounds.size

var scale : CGFloat = ivsize.width / imsize.width
if imsize.height * scale < ivsize.height {
scale = ivsize.height / imsize.height
}

let croppedImsize = CGSize(width:ivsize.width/scale, height:ivsize.height/scale)
let croppedImrect =
CGRect(origin: CGPoint(x: (imsize.width-croppedImsize.width)/2.0,
y: (imsize.height-croppedImsize.height)/2.0),
size: croppedImsize)

现在我们已经解决了问题:croppedImrect 是 ImageView 中显示的原始图像的区域。让我们继续使用我们的知识,将图像实际裁剪为与 ImageView 中显示的内容相匹配的新图像:

let r = UIGraphicsImageRenderer(size:croppedImsize)
let croppedIm = r.image { _ in
iv.image!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
}

结果是这个图像(忽略灰色边框):

enter image description here

但是你瞧,这就是正确答案!我已经从原始图像中提取了 ImageView 内部描绘的区域。

现在您已拥有所需的所有信息。 croppedIm 是实际显示在 ImageView 的裁剪区域中的 UIImage。 scale 是 ImageView 和该图像之间的比例。因此,你可以轻松解决你原来提出的问题!给定施加在 ImageView 上的任何矩形,在 ImageView 的边界坐标中,您只需应用比例(即将其所有四个属性除以比例) - 现在您拥有与一部分相同的矩形croppedIm

(请注意,我们并不真的需要裁剪原始图像来获得croppedIm;实际上,知道如何就足够了em> 来执行该裁剪。重要的信息是 scale 以及 croppedImRectorigin;根据这些信息,您可以获取矩形施加在 ImageView 上,缩放它,并偏移它以获得原始图像所需的矩形。)

<小时/>

编辑我添加了一些截屏视频,只是为了表明我的方法可以作为概念证明:

enter image description here

编辑还在此处创建了一个可下载的示例项目:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/39cc800d18aa484d17c26ffcbab8bbe51c614573/bk2ch02p058cropImageView/Cropper/ViewController.swift

但请注意,我不能保证 URL 将永远持续,因此请阅读上面的讨论以了解所使用的方法。

关于ios - 如何在 'aspect fill' 模式下将 UIImageView 裁剪为新的 UIImage?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49352639/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com