[英]Squeezing/Squashing of Images in iOS Swift
I am working on a photo editing application where I need to squeeze/squash car images to create cute caricatures just like the image attached.我正在开发一个照片编辑应用程序,我需要挤压/挤压汽车图像以创建可爱的漫画,就像附加的图像一样。 This is my very first photo editing application so I don't exactly know what term to put on Google search and even how I can achieve this thing.这是我的第一个照片编辑应用程序,所以我不知道在谷歌搜索上放什么词,甚至不知道如何实现这个目标。 Any help, guidance, or direction would be a great favor.任何帮助、指导或方向都将是一个很大的帮助。
Please note this is not related to image resizing.请注意,这与图像大小调整无关。
Following are two more examples.以下是另外两个例子。
There are a couple ways to do this...有几种方法可以做到这一点......
If we use this as the original image:如果我们将其用作原始图像:
it has a transparent bounding box... so it looks like this in an image editing program:它有一个透明的边界框......所以它在图像编辑程序中看起来像这样:
If you are only dealing with how it looks at run-time, you can use a UIImageView
with Content Mode: Scale to Fill
and then adjust the width of the image view.如果您只处理它在运行时的外观,您可以使用UIImageView
和Content Mode: Scale to Fill
然后调整图像视图的宽度。
If you want to actually scale the UIImage
, this simple extension will do the job:如果您想实际扩展UIImage
,这个简单的扩展将完成这项工作:
extension UIImage {
func squeeze(w: CGFloat, h: CGFloat) -> UIImage {
let newWidth: CGFloat = self.width * w
let newHeight: CGFloat = self.height * h
let sz: CGSize = CGSize(width: newWidth, height: newHeight)
let renderer: UIGraphicsImageRenderer = UIGraphicsImageRenderer(size: sz)
let img = renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: sz))
}
return img
}
}
(the image views have a green border, so we can see the frames). (图像视图有一个绿色边框,所以我们可以看到框架)。
Here is some example code you can play with:这是您可以使用的一些示例代码:
class ViewController: UIViewController, UITextFieldDelegate {
var origIMG: UIImage!
let imgViewA = UIImageView()
let imgViewB = UIImageView()
let imgViewC = UIImageView()
let st = UIStackView()
let statusLabel = UILabel()
let slider = UISlider()
var bWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
guard let img = UIImage(named: "car1"),
let bkgImg = UIImage(named: "carsBKG")
else { return }
print(img.size)
origIMG = img
// add a background image view
let vBKG = UIImageView(image: bkgImg)
st.axis = .vertical
st.alignment = .center
st.spacing = 2
[imgViewA, imgViewB, imgViewC].forEach { v in
v.layer.borderWidth = 2
v.layer.borderColor = UIColor.green.cgColor
v.backgroundColor = .clear
v.image = origIMG
}
// for A and B, we let the image view frame scale the image
imgViewA.contentMode = .scaleToFill
imgViewB.contentMode = .scaleToFill
// for C we keep the image aspect ratio, because
// we're going to modify the UIImage size
imgViewC.contentMode = .scaleAspectFit
var label: UILabel!
label = UILabel()
label.text = "Original"
st.addArrangedSubview(label)
st.addArrangedSubview(imgViewA)
st.setCustomSpacing(20.0, after: imgViewA)
label = UILabel()
label.text = "Modify Image View Frame"
st.addArrangedSubview(label)
st.addArrangedSubview(imgViewB)
st.setCustomSpacing(20.0, after: imgViewB)
label = UILabel()
label.text = "Modify UIImage"
st.addArrangedSubview(label)
st.addArrangedSubview(imgViewC)
st.setCustomSpacing(20.0, after: imgViewC)
statusLabel.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
statusLabel.textAlignment = .center
st.addArrangedSubview(statusLabel)
slider.backgroundColor = .white.withAlphaComponent(0.6)
slider.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged)
st.addArrangedSubview(slider)
st.setCustomSpacing(20.0, after: slider)
vBKG.translatesAutoresizingMaskIntoConstraints = false
st.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vBKG)
view.addSubview(st)
// we're going to modify the 2nd image view width
bWidth = imgViewB.widthAnchor.constraint(equalTo: st.widthAnchor)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
st.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
st.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
st.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
// background image view same size/position as stack view
// plus 20-points on each side
vBKG.topAnchor.constraint(equalTo: st.topAnchor, constant: -20.0),
vBKG.leadingAnchor.constraint(equalTo: st.leadingAnchor, constant: -20.0),
vBKG.trailingAnchor.constraint(equalTo: st.trailingAnchor, constant: 20.0),
vBKG.bottomAnchor.constraint(equalTo: st.bottomAnchor, constant: 20.0),
// top image (original) full width, proportional height
imgViewA.widthAnchor.constraint(equalTo: st.widthAnchor),
imgViewA.heightAnchor.constraint(equalTo: imgViewA.widthAnchor, multiplier: origIMG.height / origIMG.width),
// 2nd image starts at full width, proportional height
// we'll change the image VIEW width
bWidth,
imgViewB.heightAnchor.constraint(equalTo: imgViewA.widthAnchor, multiplier: origIMG.height / origIMG.width),
// 3rd image full width, proportional height
// we'll change the actual IMAGE
imgViewC.widthAnchor.constraint(equalTo: st.widthAnchor),
imgViewC.heightAnchor.constraint(equalTo: imgViewA.widthAnchor, multiplier: origIMG.height / origIMG.width),
slider.widthAnchor.constraint(equalTo: st.widthAnchor),
])
// start slider at 100%
slider.value = 1.0
statusLabel.text = "100%"
// let's make the labels readable
st.arrangedSubviews.forEach { vSub in
if let v = vSub as? UILabel {
v.textColor = .white
v.backgroundColor = .black.withAlphaComponent(0.4)
v.textAlignment = .center
v.widthAnchor.constraint(equalTo: st.widthAnchor).isActive = true
}
}
}
@objc func sliderChanged(_ sender: UISlider) {
let pct = CGFloat(sender.value)
// let's use a minimum scale of 0.5%
if pct < 0.05 { return }
// update imgViewB's width anchor as a percentage
bWidth.isActive = false
bWidth = imgViewB.widthAnchor.constraint(equalTo: st.widthAnchor, multiplier: pct)
bWidth.isActive = true
// set imgViewC's image to a NEW rendered UIImage
// we're scaling the width, keeping the original height
imgViewC.image = origIMG.squeeze(w: pct, h: 1.0)
statusLabel.text = "\(Int(pct * 100))%"
}
}
extension UIImage {
func squeeze(w: CGFloat, h: CGFloat) -> UIImage {
let newWidth: CGFloat = self.width * w
let newHeight: CGFloat = self.height * h
let sz: CGSize = CGSize(width: newWidth, height: newHeight)
let renderer: UIGraphicsImageRenderer = UIGraphicsImageRenderer(size: sz)
let img = renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: sz))
}
return img
}
}
When running, it looks like this - dragging the slider sets the Widths to a percentage of the original:运行时,它看起来像这样 - 拖动 slider 将宽度设置为原始的百分比:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.