简体   繁体   English

如何根据背景颜色自动更改视图的透明颜色

[英]How to automatically change transparent color of a view based on the color of it’s background

I want to display a semi transparent text field over the uiimageview.我想在 uiimageview 上显示一个半透明的文本字段。 I can't choose static color for textfield because some images are bright while other images are dark.我不能为文本字段选择 static 颜色,因为有些图像很亮,而其他图像很暗。 I want to automatically adapt text field color based on the colors behind it.我想根据后面的 colors 自动调整文本字段颜色。 Is there an easy solution for that?有一个简单的解决方案吗?

UPD: The effect I want to achieve is: If UIImage is dark where my textfield should be placed, set textfield background color to white with 0.5 opacity. UPD:我想要实现的效果是:如果 UIImage 应该放置我的文本字段的位置是暗的,则将文本字段背景颜色设置为白色,不透明度为 0.5。 If UIImage is light where my textfield should be placed, set textfield background color to black with 0.5 opacity.如果 UIImage 在应该放置我的文本字段的位置很亮,请将文本字段背景颜色设置为黑色,不透明度为 0.5。

So I want to somehow calculate the average color of the uiimageview in place where I want to put my textfield and then check if it is light or dark.所以我想以某种方式计算 uiimageview 的平均颜色,放在我想放置文本字段的位置,然后检查它是浅色还是深色。 I don't know, how to get the screenshot of the particular part my uiimageview and get it's average color.我不知道,如何获取我的 uiimageview 的特定部分的屏幕截图并获得它的平均颜色。 I want it to be optimised.我希望它被优化。 I guess working with UIGraphicsImageRenderer isn't a good choice, that's why I ask this question.我想使用 UIGraphicsImageRenderer 不是一个好的选择,这就是我问这个问题的原因。 I know how to do it with UIGraphicsImageRenderer, but I don't think that my way is good enough.我知道如何使用 UIGraphicsImageRenderer 来做到这一点,但我认为我的方式还不够好。

"Brightness" of an image is not a straight-forward thing.图像的“亮度”并不是一件直截了当的事情。 You may or may not find this suitable.您可能会也可能不会觉得这合适。

If you search for determine brightness of an image you'll find plenty of documentation on it - likely way more than you want.如果您搜索determine brightness of an image您会发现大量关于它的文档 - 可能比您想要的要多。

One common way to calculate the "brightness" of a pixel is to use the sum of:计算像素“亮度”的一种常用方法是使用以下各项之和:

red component   * 0.299
green component * 0.587
blue component  * 0.114

This is because we perceive the different colors at different "brightness" levels.这是因为我们在不同的“亮度”级别上感知到不同的 colors。

So, you'll want to loop through each pixel in the area of the image where you want to place your label (or textField), get the average brightness, and then decide what's "dark" and what's "light".因此,您需要遍历图像区域中要放置 label(或 textField)的每个像素,获取平均亮度,然后确定什么是“暗”,什么是“亮”。

As an example, using this background image:例如,使用此背景图像:

在此处输入图像描述

I generated a 5 x 8 grid of labels, looped through getting the "brightness" of the image in the rect under each label's frame, and then set the background and text color based on the brightness calculation (values range from 0 to 255, so I used < 127 is dark, >= 127 is light):我生成了一个 5 x 8 的标签网格,循环获取每个标签框架下矩形中图像的“亮度”,然后根据亮度计算设置背景和文本颜色(值范围从 0 到 255,所以我用 < 127 是暗的,>= 127 是亮的):

在此处输入图像描述

This is the code I used:这是我使用的代码:

extension CGImage {
    var brightness: Double {
        get {
            // common formula to get "average brightness"
            let bytesPerPixel = self.bitsPerPixel / self.bitsPerComponent
            let imageData = self.dataProvider?.data
            let ptr = CFDataGetBytePtr(imageData)
            var x = 0
            var p = 0
            var result: Double = 0
            for _ in 0..<self.height {
                for _ in 0..<self.width {
                    let r = ptr![p+0]
                    let g = ptr![p+1]
                    let b = ptr![p+2]
                    result += (0.299 * Double(r) + 0.587 * Double(g) + 0.114 * Double(b))
                    p += bytesPerPixel
                    x += 1
                }
            }
            let bright = result / Double (x)
            return bright
        }
    }
}
extension UIImage {
    // get the "brightness" of self (entire image)
    var brightness: Double {
        get {
            return (self.cgImage?.brightness)!
        }
    }

    // get the "brightness" in a sub-rect of self
    func brightnessIn(_ rect: CGRect) -> Double {
        guard let cgImage = self.cgImage else { return 0.0 }
        guard let croppedCGImage = cgImage.cropping(to: rect) else { return 0.0 }
        return croppedCGImage.brightness
    }
}

class ImageBrightnessViewController: UIViewController {
    
    let imgView: UIImageView = {
        let v = UIImageView()
        v.contentMode = .center
        v.backgroundColor = .green
        v.clipsToBounds = true
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var labels: [UILabel] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // load an image
        guard let img = UIImage(named: "bkg640x360") else { return }

        imgView.image = img

        let w = img.size.width
        let h = img.size.height
        
        // set image view's width and height equal to img width and height
        view.addSubview(imgView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            imgView.widthAnchor.constraint(equalToConstant: w),
            imgView.heightAnchor.constraint(equalToConstant: h),
            imgView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            imgView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
        ])

        // use stack views to create a 5 x 8 grid of labels
        let outerStackView: UIStackView = {
            let v = UIStackView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.axis = .horizontal
            v.spacing = 32
            v.distribution = .fillEqually
            return v
        }()

        for _ in 1...5 {
            let vStack = UIStackView()
            vStack.axis = .vertical
            vStack.spacing = 12
            vStack.distribution = .fillEqually
            for _ in 1...8 {
                let label = UILabel()
                label.textAlignment = .center
                vStack.addArrangedSubview(label)
                labels.append(label)
            }
            outerStackView.addArrangedSubview(vStack)
        }
        
        let padding: CGFloat = 12.0

        imgView.addSubview(outerStackView)
        NSLayoutConstraint.activate([
            outerStackView.topAnchor.constraint(equalTo: imgView.topAnchor, constant: padding),
            outerStackView.leadingAnchor.constraint(equalTo: imgView.leadingAnchor, constant: padding),
            outerStackView.trailingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: -padding),
            outerStackView.bottomAnchor.constraint(equalTo: imgView.bottomAnchor, constant: -padding),
        ])
        
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        guard let img = imgView.image else {
            return
        }
        labels.forEach { v in
            if let sv = v.superview {
                // convert label frame to imgView coordinate space
                let rect = sv.convert(v.frame, to: imgView)
                // get the "brightness" of that rect from the image
                //  it will be in the range of 0 - 255
                let d = img.brightnessIn(rect)
                // set the text of the label to that value
                v.text = String(format: "%.2f", d)
                // just using 50% here... adjust as desired
                if d > 127.0 {
                    // if brightness is than 50%
                    //  black translucent background with white text
                    v.backgroundColor = UIColor.black.withAlphaComponent(0.5)
                    v.textColor = .white
                } else {
                    // if brightness is greater than or equal to 50%
                    //  white translucent background with black text
                    v.backgroundColor = UIColor.white.withAlphaComponent(0.5)
                    v.textColor = .black
                }
            }
        }
    }
}

As you can see, when getting the average of a region of a photo, you'll quite often not be completely happy with the result.如您所见,在获取照片区域的平均值时,您通常不会对结果完全满意。 That's why it's much more common to see one or the other, with a contrasting order and either a shadow or glow around the frame.这就是为什么看到一个或另一个更为常见的原因,具有对比顺序以及框架周围的阴影或发光。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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