我需要点击uiimageview(srgb)
并将返回的颜色与资产目录颜色(或自定义代码颜色)进行比较。我在色彩空间上遇到很多麻烦,而我的比赛总是不行。我已经阅读了一些关于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!");
}
}
如果您不熟悉以下主题,请不要这样做。我将向您展示一种方法,一种非常简化的方法,但是会有一些麻烦。
需要预先阅读或至少了解/熟悉的东西。
您的UIImageView
可以是完全不透明的,透明的,部分不透明的,透明的......假设UIImageView
下方有黄色的视图,并且UIImageView
并非不透明,并且alpha设置为50 %。你要什么颜色原始图像颜色?渲染的颜色(与黄色混合)?
我假设那个与黄色混合在一起。这是获得正确颜色的代码:
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
->没有任何用处,那是什么下面?白色?黑色?橙色?
每个设备都不同,可以显示不同范围的颜色-iPad,iPhone等。...还包括其他设备类型,例如计算机显示器,打印机等,因为我不知道您要在您的产品中实现什么应用程序,以提醒您-每个设备上的颜色相同但外观不同。
这里是Display P3配置文件和通用sRGB的比较。您只需在macOS上启动ColorSync Utility就可以比较更多配置文件。它表明,当您将一种颜色从一种空间转换为另一种空间时,颜色会有所不同。
Color transformation章中的语录:
颜色转换或颜色空间转换是一种颜色表示形式从一种颜色空间到另一种颜色空间的转换。
&
几乎在每个翻译过程中,我们都必须处理不同设备的色域在范围内变化的事实,从而无法准确再现。
这是一个复杂的过程,但是它取决于许多事情(色彩空间,...)。它可能涉及后代化(例如16位-> 8位),取决于您的渲染意图(相对比色,感知,...),等等。
非常简单的示例-您有一张红色(#FF0000
)的图像,并为其分配了通用sRGB配置文件。 iPhone将显示它(P3),您将看到different颜色。更准确地说,如果获得RGB分量值,它们将有所不同。
CoreGraphics.framework提供颜色转换功能-converted(to:intent:options:)
。您必须通过:
converted(to:intent:options:)
)。nil
示例:
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您可以通过两种方式创建要比较的颜色:
#CC3333
初始值设定项Xcode资产目录允许您为不同的设备,色域指定颜色,也可以选择自定义内容(显示P3,sRGB,扩展范围sRGB等)。
UIColor
初始值设定项可让您指定颜色(不只是):
请注意您如何创建要比较的颜色。 RGB分量值在各种颜色空间中都不同。
您已经知道它现在是如何工作的,您可以看到其中涉及一些数学运算,使得转换后的颜色无法精确匹配。我的意思是-将两种颜色转换为相同的颜色空间-您仍然无法使用简单的等式运算符比较组件(RGB)。精度会因转换而丢失,即使不是,也会丢失-还记得UIColor
吗?
[有一种方法可以实现您想要的,它称为What every computer scientist should know about floating-point arithmetic。换句话说-您想计算两种颜色的距离。
Color difference
我们能够计算两种颜色的欧几里得距离,让我们编写一个简单的函数来检查两种颜色是否具有一定的容差匹配:
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)
}
}
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
添加到资产目录中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
}
}
获得正确的颜色(定义,获取,比较,转换...)不是那么容易。试图指出重要事项,同时保持其简单性,但是您现在应该可以这样做。不要忘记正确创建颜色,转换为适当的颜色空间,选择适合您的应用程序需求的容差,等等。