比较通过水龙头返回的uicolor和资产目录颜色

问题描述 投票:0回答:1

我需要点击uiimageview(srgb)

hotspots

并将返回的颜色与资产目录颜色(或自定义代码颜色)进行比较。我在色彩空间上遇到很多麻烦,而我的比赛总是不行。我已经阅读了一些关于stackoverflow的出色示例,并尝试了它们,但我仍然必须做错什么。

我使用此颜色选择器代码(第一个答案):How to get the pixel color on touch?

以及这两个用于匹配的Objective-C答案的变化:How to compare UIColors?

我也尝试过使用这样的自定义颜色(而不是资产颜色):

+ (UIColor *)themeRed {
    return [UIColor colorWithRed:192.0f/255.0f green:92.0f/255.0f blue:42.0f/255.0f alpha:1];
}

仍然没有比赛。我的测试比赛代码如下。

-(void)tappedColorView:(UITapGestureRecognizer *)tapRecognizer {
    CGPoint touchPoint = [tapRecognizer locationInView: uiiv_hs];
    //NSLog(@"my color %@", [uiiv_hs colorOfPoint:touchPoint]);

    UIColor *color = [uiiv_hs colorOfPoint:touchPoint];
    NSLog(@"color %@",[uiiv_hs colorOfPoint:touchPoint]);
    UIColor *matchcolor = [UIColor themeRed];
    NSLog(@"mcolor %@",[UIColor themeRed]);

    NSArray *colors = [NSArray arrayWithObjects:[UIColor colorNamed:@"Color01"],[UIColor colorNamed:@"Color02"], nil];

    if ([color matchesColor:matchcolor error:nil]) {
        NSLog(@"1Match!");
    } else {
        NSLog(@"1No Match!");
    }

    if ([color isEqualToColor:[UIColor themeRed]]) {
        NSLog(@"2Match!");
    } else {
        NSLog(@"2No Match!");
    }
}
objective-c xcode uicolor cgcolorspace
1个回答
0
投票

如果您不熟悉以下主题,请不要这样做。我将向您展示一种方法,一种非常简化的方法,但是会有一些麻烦。

资源

需要预先阅读或至少了解/熟悉的东西。

问题1-您想要哪种颜色?

您的UIImageView可以是完全不透明的,透明的,部分不透明的,透明的......假设UIImageView下方有黄色的视图,并且UIImageView并非不透明,并且alpha设置为50 %。你要什么颜色原始图像颜色?渲染的颜色(与黄色混合)?

Comparison of colors from UIView with different alpha channel

我假设那个与黄色混合在一起。这是获得正确颜色的代码:

extension UIView {
    func color(at point: CGPoint) -> UIColor? {
        var targetOpaqueView: UIView = self

        // Traverse the view hierarchy to find a parent which is opaque
        while !targetOpaqueView.isOpaque && targetOpaqueView.superview != nil {
            targetOpaqueView = targetOpaqueView.superview!
        }

        // Convert the point from our view to the target one
        let targetPoint: CGPoint = convert(point, to: targetOpaqueView)

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        var pixel: [UInt8] = [0, 0, 0, 0]

        guard let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
            return nil
        }

        context.translateBy(x: -targetPoint.x, y: -targetPoint.y)

        // Render the target opaque view to get all the possible transparency right
        targetOpaqueView.layer.render(in: context)
        return UIColor(red: CGFloat(pixel[0])/255.0, green: CGFloat(pixel[1])/255.0, blue: CGFloat(pixel[2])/255.0, alpha: CGFloat(pixel[3])/255.0)
    }
}

此函数应返回alpha分量设置为1.0的颜色。必须为1.0,否则我们无法继续。为什么?想象一下UIImageView alpha设置为50%->我们将不遍历视图层次结构(此targetOpaqueView舞动)->我们将获得一种颜色,其alpha分量接近0.5->没有任何用处,那是什么下面?白色?黑色?橙色?

问题2-设备

每个设备都不同,可以显示不同范围的颜色-iPad,iPhone等。...还包括其他设备类型,例如计算机显示器,打印机等,因为我不知道您要在您的产品中实现什么应用程序,以提醒您-每个设备上的颜色相同但外观不同。

问题3-颜色配置文件

这里是Display P3配置文件和通用sRGB的比较。您只需在macOS上启动ColorSync Utility就可以比较更多配置文件。它表明,当您将一种颜色从一种空间转换为另一种空间时,颜色会有所不同。

Display P3 and Generic sRGBP comparison

问题4-颜色转换

Color transformation章中的语录:

颜色转换或颜色空间转换是一种颜色表示形式从一种颜色空间到另一种颜色空间的转换。

几乎在每个翻译过程中,我们都必须处理不同设备的色域在范围内变化的事实,从而无法准确再现。

这是一个复杂的过程,但是它取决于许多事情(色彩空间,...)。它可能涉及后代化(例如16位-> 8位),取决于您的渲染意图(相对比色,感知,...),等等。

非常简单的示例-您有一张红色(#FF0000)的图像,并为其分配了通用sRGB配置文件。 iPhone将显示它(P3),您将看到different颜色。更准确地说,如果获得RGB分量值,它们将有所不同。

CoreGraphics.framework提供颜色转换功能-converted(to:intent:options:)。您必须通过:

  • 目标色彩空间,
  • intent =当颜色在新颜色空间的色域之外时用于匹配颜色的机制,
  • 选项(只需通过converted(to:intent:options:))。
nil

示例:

  • 扩展sRGB颜色(extension UIColor { func converted(toColorSpace colorSpace: CGColorSpace, intent: CGColorRenderingIntent = .defaultIntent) -> UIColor? { guard let converted = cgColor.converted(to: colorSpace, intent: intent, options: nil) else { return nil } return UIColor(cgColor: converted) } } )的分量值(RGBA):0.8 0.2 0.2 1
  • 将相同颜色转换为扩展线性sRGB:0.603827 0.0331048 0.0331048 1
  • 将相同颜色转换为显示P3:0.737027 0.252869 0.228974 1

问题5-自定义颜色

您可以通过两种方式创建要比较的颜色:

  • Xcode资产目录
  • #CC3333初始值设定项

Xcode资产目录允许您为不同的设备,色域指定颜色,也可以选择自定义内容(显示P3,sRGB,扩展范围sRGB等)。

UIColor初始值设定项可让您指定颜色(不只是):

  • 显示P3
  • 扩展范围sRGB(iOS> = 10)

请注意您如何创建要比较的颜色。 RGB分量值在各种颜色空间中都不同。

问题6-颜色比较

您已经知道它现在是如何工作的,您可以看到其中涉及一些数学运算,使得转换后的颜色无法精确匹配。我的意思是-将两种颜色转换为相同的颜色空间-您仍然无法使用简单的等式运算符比较组件(RGB)。精度会因转换而丢失,即使不是,也会丢失-还记得UIColor吗?

[有一种方法可以实现您想要的,它称为What every computer scientist should know about floating-point arithmetic。换句话说-您想计算两种颜色的距离。

Color difference
  • 显示P3:(0.692708 0.220536 0.201643 1)
  • 显示P3:(0.692708 0.220536 0.198637 1)
  • 欧式距离:0.0030061900627510133

我们能够计算两种颜色的欧几里得距离,让我们编写一个简单的函数来检查两种颜色是否具有一定的容差匹配:

extension UIColor {
    func euclideanDistance(to other: UIColor) -> CGFloat? {
        let ciColor = CIColor(color: self)
        let ciColorOther = CIColor(color: other)

        guard ciColor.numberOfComponents == ciColorOther.numberOfComponents,
            ciColor.alpha == 1.0, ciColorOther.alpha == 1.0 else {
                return nil;
        }

        let dr = ciColorOther.red - ciColor.red
        let dg = ciColorOther.green - ciColor.green
        let db = ciColorOther.blue - ciColor.blue

        return sqrt(dr * dr + dg * dg + db * db)
    }
}

所有碎片在一起

  • 我拍摄了您的图像的屏幕截图
  • 已在Pixelmator中打开它并导出到Web(sRGB,未关联任何配置文件)
  • 已拖放并放入资产目录
  • 从图像中选择红色(extension UIColor { func matches(to other: UIColor, euclideanDistanceTolerance tolerance: CGFloat = 0.01) -> Bool? { guard let distance = euclideanDistance(to: other) else { return nil } return distance <= tolerance } }
  • 已将#C02A2B添加到资产目录中
    • 全部色域,内容sRGB,8位十六进制CustomRedColor
  • 使用我们已经讨论过的所有功能,用轻敲手势处理程序制作了一个简单的视图控制器
#C02A2B

class ViewController: UIViewController { @IBOutlet var imageView: UIImageView! @IBOutlet var leftView: UIView! @IBOutlet var rightView: UIView! private let assetsCatalogRedColor: UIColor = UIColor(named: "CustomRedColor")! @IBAction func handleTap(sender: UITapGestureRecognizer) { let location = sender.location(in: imageView) guard let colorSpace = CGColorSpace(name: CGColorSpace.displayP3), let redColor = assetsCatalogRedColor.converted(toColorSpace: colorSpace, intent: .defaultIntent), let tappedColor = imageView.color(at: location)?.converted(toColorSpace: colorSpace, intent: .defaultIntent) else { return } let matches = tappedColor.matches(to: redColor) ?? false print("Tapped color matches CustomRedColor: \(matches)") leftView.backgroundColor = tappedColor rightView.backgroundColor = redColor } }

  • 点击底部的红色圆圈
  • 而且我有enter image description here

结论

获得正确的颜色(定义,获取,比较,转换...)不是那么容易。试图指出重要事项,同时保持其简单性,但是您现在应该可以这样做。不要忘记正确创建颜色,转换为适当的颜色空间,选择适合您的应用程序需求的容差,等等。

© www.soinside.com 2019 - 2024. All rights reserved.