简体   繁体   English

如何比较日志中kCGColorSpaceModelRGB和UIExtendedSRGBColorSpace实例的2个UIColor对象?

[英]How do I compare 2 UIColor objects which are kCGColorSpaceModelRGB and UIExtendedSRGBColorSpace instances in logs?

Now I'm really confused. 现在我真的很困惑。 Heres how the variable gets instantiated : 下面是变量如何实例化:

Utils.redColor = UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue)/255.0, alpha: alpha) 

And here I enumerate a Attribute text's attributes to skip the color if it's equals to Utils.redColor : 在这里,我枚举一个属性文本的属性,以跳过颜色,如果它等于Utils.redColor:

    text.enumerateAttributes(in: NSRange(0..<text.length), options: []) { (attributes, range, _) -> Void in
                            for (attribute, object) in attributes {
                                if let textColor = object as? UIColor{
                                     NSLog("textColor = \(textColor) red = \(Utils.redColor!)") 
             if (!textColor.isEqual(Utils.redColor!)){
//I need to repaint any textColor other than red
             text.setAttributes(textAttributes , range: range)
            }
          }

So, as you see in this code textColor is a UIColor object as well, but the log says: 所以,正如你在这段代码中看到的,textColor 也是一个UIColor对象,但是日志说:

textColor = kCGColorSpaceModelRGB 0.666667 0.172549 0.172549 1 red = UIExtendedSRGBColorSpace 0.666667 0.172549 0.172549 1

Which are two exact colors , but being instances of two different classes. 这是两种确切的颜色,但是是两个不同类的实例。 This is totally confusing for both of them are UIColor class's objects! 这两个都是UIColor类的对象,这完全令人困惑!

This comparison never triggers although it worked well in Swift2 虽然它在Swift2中运行良好,但这种比较从未触发

How do I fix it and why this problem ever occurs?? 我该如何解决它以及为什么会出现这个问题?

Welcome to the wild and wooly world of wide color and color management. 欢迎来到广泛的色彩和色彩管理的狂野和毛茸茸的世界。

Your two colors aren't equal, per isEqual (or Swift == , which runs through isEqual for ObjC classes that have it), because they have different color spaces. 你的两种颜色不相等,每个isEqual (或者Swift == ,对于拥有它的ObjC类,它通过isEqual运行),因为它们有不同的颜色空间。 (They aren't different classes; the first item in UIColor.description is an identifier for the color space, or where the color space doesn't have a name, the model for the color space — that is, whether it's RGB-based, CMYK-based, grayscale, etc.) (它们不是不同的类; UIColor.description的第一项是颜色空间的标识符,或者颜色空间没有名称的位置,颜色空间的模型 - 也就是说,它是否基于RGB ,基于CMYK,灰度等)

Without a color space to define them as a color, the four component values of a color have no reliable meaning, so isEqual uses both the component values and the color space to test for equality. 没有颜色空间将它们定义为颜色,颜色的四个组件值没有可靠的含义,因此isEqual使用组件值和颜色空间来测试相等性。

Aside on color spaces (skip down for solutions) 除了色彩空间(跳过解决方案)

Your color created with UIColor init(red:green:blue:alpha:) uses the "Extended sRGB" color space. 使用UIColor init(red:green:blue:alpha:)创建的颜色使用“扩展sRGB”颜色空间。 This color space is designed to support wide color displays (like the P3 color display in iPhone 7, iPad Pro 9.7", iMac late-2015, MacBook Pro late-2016, and probably whatever else comes next), but be component-value compatible with the sRGB color space used on other devices. 此色彩空间旨在支持广泛的彩色显示(如iPhone 7中的P3彩色显示屏,iPad Pro 9.7“,2015年末的iMac,2016年末的MacBook Pro,以及可能接下来的任何其他内容),但兼容组件价值使用其他设备上使用的sRGB色彩空间。

For example, sRGB 1.0, 0.0, 0.0 is the "red" you're probably most used to... but if you create a color in the P3 color space with RGB values 1.0, 0.0, 0.0 you get much much redder. 例如,sRGB 1.0, 0.0, 0.0是您可能最习惯的“红色”......但如果您在P3颜色空间中创建一个RGB值为1.0,0.0,0.0的颜色1.0, 0.0, 0.0则会得到更多的红色。 If you have an app where you need to support both sRGB and P3 displays and work directly with color components, this can get confusing. 如果您有一个应用程序,您需要同时支持sRGB和P3显示并直接使用颜色组件,这可能会让人感到困惑。 So the Extended sRGB space lets the same component values mean the same thing, but also allows colors outside the sRGB gamut to be specified using values outside the 0.0 - 1.0 range . 因此,扩展sRGB空间允许相同的组件值表示相同的内容,但也允许使用0.0 - 1.0范围之外的值指定sRGB色域之外的颜色。 For example, the reddest that Display P3 can get is expressed in Extended sRGB as (roughly) 1.093, -0.227, -0.15 . 例如,显示P3可以获得的最1.093, -0.227, -0.15在扩展sRGB中表示为(大致) 1.093, -0.227, -0.15

As [the docs for that initializer note, for apps linked against the iOS 10 or later SDK, init(red:green:blue:alpha:) creates a color in the Extended sRGB color space, but for older apps (even if they're running on iOS 10) it creates a color in a device-specific RGB space (which you can generally treat as equivalent to sRGB). 作为[初始化程序注释的文档,对于针对iOS 10或更高版本SDK链接的应用程序, init(red:green:blue:alpha:)在扩展sRGB颜色空间中创建颜色,但对于较旧的应用程序(即使它们'重新在iOS 10上运行)它在特定于设备的RGB空间中创建一种颜色(通常可以将其视为等同于sRGB)。

Dealing with different color spaces 处理不同的色彩空间

So, either your color-replacing code or whatever code is creating the colors in your attributed string need to be aware of color spaces. 因此,要么您的颜色替换代码或任何代码在您的属性字符串中创建颜色需要知道颜色空间。 There are a few possible ways to deal with this; 有几种可能的方法可以解决这个问题; pick the one that works best for you: 选择最适合你的那个:

  1. Make sure both your string-creation code and your color-replacement code are using the same device-independent color space. 确保您的字符串创建代码和颜色替换代码都使用相同的设备无关颜色空间。 UIColor doesn't provide a lot of utilities for working with color spaces, so you can either use Display P3 (on iOS 10 and up), or drop down to CGColor : UIColor没有提供很多用于处理颜色空间的实用程序,因此您可以使用Display P3 (在iOS 10及更高版本上),或者下拉到CGColor

     let sRGB = CGColorSpace(name: CGColorSpace.sRGB)! let cgDarkRed = CGColor(colorSpace: sRGB, components: [0.666667, 0.172549, 0.172549, 1])! let darkRed = UIColor(cgColor: cgDarkRed) // example creating attributed string... let attrString = NSAttributedString(string: "red", attributes: [NSForegroundColorAttributeName : darkRed]) // example processing text... let redAttributes = [NSForegroundColorAttributeName: darkRed] text.enumerateAttributes(in: NSRange(0..<attrString.length)) { (attributes, range, stop) in for (_, textColor) in attributes where (textColor as? UIColor) != darkRed { text.setAttributes(redAttributes , range: range) } } 
  2. If you can't control the input colors, convert them to the same color space before comparing. 如果无法控制输入颜色,请在比较前将它们转换为相同的颜色空间。 Here's a UIColor extension to do that: 这是一个UIColor扩展来做到这一点:

     extension UIColor { func isEqualWithConversion(_ color: UIColor) -> Bool { guard let space = self.cgColor.colorSpace else { return false } guard let converted = color.cgColor.converted(to: space, intent: .absoluteColorimetric, options: nil) else { return false } return self.cgColor == converted } } 

    (Then you can just use this function in place of == or isEqual in your text processing.) (然后你可以在文本处理中使用这个函数代替==isEqual 。)

  3. Just get at the raw component values of the colors and compare them directly, based on the assumption that you know the color spaces for both are compatible. 只需获取颜色的原始组件值并直接比较它们,基于您知道两者的颜色空间兼容的假设。 Sort of fragile, so I recommend against this option. 有点脆弱,所以我建议不要这个选项。

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

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