简体   繁体   English

在 iOS Swift 中压缩/挤压图像

[英]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.如果您只处理它在运行时的外观,您可以使用UIImageViewContent 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM