Home > Blockchain >  Convert Display P3 to eSRGB by hex color in iOS swift?
Convert Display P3 to eSRGB by hex color in iOS swift?

Time:11-29

I'm using UIColorPickerViewController. When I use Sliders section, default value is display p3 like below an image.

enter image description here

My app is using UIExtendedSRGBColorSpace. So I need to convert to UIExtendedSRGBColorSpace. When I convert from Display P3 to eSRGB, it returns UIExtendedSRGBColorSpace -0.511642 1.01827 -0.310624 1.

convert code is here.

extension CGColorSpace {
static let extendedSRGB = CGColorSpace(name: CGColorSpace.extendedSRGB)! }

func updateFromP3ToExtendedsRGB() -> UIColor?
    {
        guard self.cgColor.colorSpace?.name == CGColorSpace.displayP3 else { return nil }
        let convertColor = self.cgColor.converted(to: .extendedSRGB, intent: .relativeColorimetric, options: nil)
        if let convertCGColor = convertColor
        {
            return UIColor(cgColor: convertCGColor)
        }
        
        return nil
    }

I got negative value. Here is the problem.

I need to save color with hex code. When I changed to hex code of converted color, it turns different color like yellow color ffffffb1.

enter image description here

here is code to converting hex code.

func toHexString() -> String {
        var r:CGFloat = 0
        var g:CGFloat = 0
        var b:CGFloat = 0
        var a:CGFloat = 0

        getRed(&r, green: &g, blue: &b, alpha: &a)
        let argb:Int = (Int)(a*255)<<24 | (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
        return NSString(format:"x", argb) as String
    }

So, my question is how to convert from display p3 to eSRGB by hex string?

enter image description here

CodePudding user response:

If you convert from UIColor, hex value always is sRGB colorspace. You should convert from CGColor. Apple UIColor


extension CGColor {
    func toHex() -> String? {
        guard let components = components else { return nil }
        
        if components.count == 2 {
            let value = components[0]
            let alpha = components[1]
            return String(format: "#lXlXlXlX", lroundf(Float(alpha*255)), lroundf(Float(value*255)), lroundf(Float(value*255)), lroundf(Float(value*255)))
        }
        
        guard components.count == 4 else { return nil }
        
        let red   = components[0]
        let green = components[1]
        let blue  = components[2]
        let alpa  = components[3]
        
        let hexString = String(format: "#lXlXlXlX",lroundf(Float(alpa*255)), lroundf(Float(red*255)), lroundf(Float(green*255)), lroundf(Float(blue*255)))
        
        return hexString
    }
}


extension UIColor {
    func toHexString() -> String {
        cgColor.toHex() ?? ""
    }
    
    func toDisplayP3HexString() -> String {
        guard let displayP3Color = self.cgColor.converted(to: CGColorSpace(name: CGColorSpace.displayP3)!, intent: .defaultIntent, options: nil) else {
            return ""
        }
        return displayP3Color.toHex() ?? ""
    }
}

CodePudding user response:

The code you posted shouldn't compile. The first parameter to CGColor converted needs to be a CGColorSpace. But you are passing in .extendedSRGB which would appear to be CGColorSpace.extendedSRGB which is a CFString, not a CGColorSpace.

When your code is updated as follows it gives what seems to be the correct result:

extension UIColor {
    func updateFromP3ToExtendedsRGB() -> UIColor? {
        guard self.cgColor.colorSpace?.name == CGColorSpace.displayP3 else { return nil }
        guard let eSRGBSpace = CGColorSpace(name: CGColorSpace.extendedSRGB) else { return nil }
        let convertColor = self.cgColor.converted(to: eSRGBSpace, intent: .relativeColorimetric, options: nil)
        if let convertCGColor = convertColor {
            return UIColor(cgColor: convertCGColor)
        }

        return nil
    }
}

With a P3 color of 75FB4C (117, 251, 76) this gives an eSRGB color of 03FF00.

What's really strange is that the screenshot shows 75FB4C as 116 (not 117), 251, 76. But 0x75 is 117 decimal, not 116. Converting 74FB4C into eSRGB gives a bizarre value with negative components. So that one digit difference makes a huge difference. This all seems to be due to rounding error when going between color models.

If you go the other way and start with an eSRGB of 00FF00 you get a P3 color of 75FB4C as expected.

You code to convert to hex is mostly fine. The real issue is the color conversion giving you an invalid color with negative components. The hex string code isn't really meant to work with negative values. But the color shouldn't have any negative components to being with.

The one thing you should do in your hex string function is to check the return value go getRed:green:blue:alpha: since it can fail in some cases.

  • Related