ChatGPT解决这个技术问题 Extra ChatGPT

如何将 UIColor 转换为 HEX 并在 NSLog 中显示

I have checked several links on how to convert UIColor codes to HEX however I am not sure on how to call to the method to display them in NSLog. I haven't got the reputation to comment so posting as a question is my last resort. I want it to display when I run my app in the log.

Second, where do I input the RGB color number ( R = 30, G = 171, B = 13)? I see that all examples use Array [0], [1], [2] which normally refers to index position, so where do I add the color values?

I have this code:

- (NSString *) hexFromUIColor:(UIColor *)color {

    if (CGColorGetNumberOfComponents(color.CGColor) < 4) {
        const CGFloat *components = CGColorGetComponents(color.CGColor);
        color = [UIColor colorWithRed:components[30] green:components[141] blue:components[13] alpha:components[1]];
    }
    if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) != kCGColorSpaceModelRGB) {
        return [NSString stringWithFormat:@"#FFFFFF"];
    }
    return [NSString stringWithFormat:@"#%02X%02X%02X", (int)((CGColorGetComponents(color.CGColor))[0]*255.0), (int)((CGColorGetComponents(color.CGColor))[1]*255.0), (int)((CGColorGetComponents(color.CGColor))[2]*255.0)];

}

Links I have checked:

hex color from uicolor

How to convert HEX RGB color codes to UIColor?

I have tried to call the method in viewDidLoad however it wont work without UIColor. I am sure it's something simple.

Thanks to anyone who answers.

What is the code I use in my viewDidLoad to call to this method in order to display in NSLog?

On this github project github.com/toby4242/UIColor-extensions/tree/master/… there is a method called hexFromUIColor: all you need to do is call it like NSString *hexStr = [UIColor hexFromUIColor:[UIColor redColor]]; Just take the code that you need.

K
Kampai

Swift 5:

func hexStringFromColor(color: UIColor) -> String {
    let components = color.cgColor.components
    let r: CGFloat = components?[0] ?? 0.0
    let g: CGFloat = components?[1] ?? 0.0
    let b: CGFloat = components?[2] ?? 0.0

    let hexString = String.init(format: "#%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255)))
    print(hexString)
    return hexString
 }

func colorWithHexString(hexString: String) -> UIColor {
    var colorString = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
    colorString = colorString.replacingOccurrences(of: "#", with: "").uppercased()

    print(colorString)
    let alpha: CGFloat = 1.0
    let red: CGFloat = self.colorComponentFrom(colorString: colorString, start: 0, length: 2)
    let green: CGFloat = self.colorComponentFrom(colorString: colorString, start: 2, length: 2)
    let blue: CGFloat = self.colorComponentFrom(colorString: colorString, start: 4, length: 2)

    let color = UIColor(red: red, green: green, blue: blue, alpha: alpha)
    return color
}

func colorComponentFrom(colorString: String, start: Int, length: Int) -> CGFloat {

    let startIndex = colorString.index(colorString.startIndex, offsetBy: start)
    let endIndex = colorString.index(startIndex, offsetBy: length)
    let subString = colorString[startIndex..<endIndex]
    let fullHexString = length == 2 ? subString : "\(subString)\(subString)"
    var hexComponent: UInt32 = 0

    guard Scanner(string: String(fullHexString)).scanHexInt32(&hexComponent) else {
        return 0
    }
    let hexFloat: CGFloat = CGFloat(hexComponent)
    let floatValue: CGFloat = CGFloat(hexFloat / 255.0)
    print(floatValue)
    return floatValue
}

How to use

let red =  CGFloat(30.0)
let green =  CGFloat(171.0)
let blue =  CGFloat(13.0)
let alpha =  CGFloat(1.0)

let color = UIColor(red: CGFloat(red/255.0), green: CGFloat(green/255.0), blue: CGFloat(blue / 255.0), alpha: alpha)
let colorCode = self.hexStringFromColor(color: color)
print(colorCode)

let resultColor = self.colorWithHexString(hexString: colorCode)
print(resultColor)

Objective-C:

- (NSString *)hexStringFromColor:(UIColor *)color {
    const CGFloat *components = CGColorGetComponents(color.CGColor);

    CGFloat r = components[0];
    CGFloat g = components[1];
    CGFloat b = components[2];

    return [NSString stringWithFormat:@"#%02lX%02lX%02lX",
            lroundf(r * 255),
            lroundf(g * 255),
            lroundf(b * 255)];
}

After getting hex code string, Call below method to get UIColor

- (UIColor *) colorWithHexString: (NSString *) hexString
{
    NSString *colorString = [[hexString stringByReplacingOccurrencesOfString: @"#" withString: @""] uppercaseString];

    NSLog(@"colorString :%@",colorString);
    CGFloat alpha, red, blue, green;

    // #RGB
    alpha = 1.0f;
    red   = [self colorComponentFrom: colorString start: 0 length: 2];
    green = [self colorComponentFrom: colorString start: 2 length: 2];
    blue  = [self colorComponentFrom: colorString start: 4 length: 2];

    return [UIColor colorWithRed: red green: green blue: blue alpha: alpha];
}


- (CGFloat) colorComponentFrom: (NSString *) string start: (NSUInteger) start length: (NSUInteger) length {
    NSString *substring = [string substringWithRange: NSMakeRange(start, length)];
    NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring];
    unsigned hexComponent;
    [[NSScanner scannerWithString: fullHex] scanHexInt: &hexComponent];
    return hexComponent / 255.0;
}

How to use

// ( R = 30, G = 171, B = 13)? 
CGFloat red = 30.0;
CGFloat green = 171.0;
CGFloat blue = 13.0; 
CGFloat alpha = 255.0
UIColor *color = [UIColor colorWithRed:(red/255.0) green:(green/255.0) blue:(blue/255.0) alpha:(alpha/255.0)];
NSString *colorCode = [self hexStringFromColor:color];
NSLog(@"Color Code: %@", colorCode);

UIColor *resultColor = [self colorWithHexString:colorCode];

How do I call it so it will then display though, it's not displaying for me.
So where is the NSLog() to display the hex value to console? This doesn't answer the question it just shows how to convert
You're not understanding my question, perhaps I am not being clear. In my viewDidLoad method, what is the code I use to call it and display the result in the log?
That did it. Thank you for including the NSLog. Got the tick from me :-)
This code is not safe unless you're certain you're dealing with RGBA or HSVA colours. (HSVA are automatically mapped to RGBA.) But try this with a greyscale color, and you'll access memory out of bounds. It also returns an invalid alpha value. I'd strongly suggest Jeff's answer below instead.
V
Valentin Shergin

And finally the version which works with alpha-component and uses right multiplier

extension UIColor {
    var hexString: String? {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0

        let multiplier = CGFloat(255.999999)

        guard self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
            return nil
        }

        if alpha == 1.0 {
            return String(
                format: "#%02lX%02lX%02lX",
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier)
            )
        }
        else {
            return String(
                format: "#%02lX%02lX%02lX%02lX",
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier),
                Int(alpha * multiplier)
            )
        }
    }
}

I'm curious why 255.999999 is the right multiplier instead of the (seemingly) widely-used 255.
J
Jeff

Kampai's answer works for RGB colors, but not for monochrome (UIColor colorWithWhite:alpha:). It also doesn't handle alpha, which HEX supports. Here's a slightly modified version of hexStringFromColor:

+ (NSString *)hexStringFromColor:(UIColor *)color
{
    CGColorSpaceModel colorSpace = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor));
    const CGFloat *components = CGColorGetComponents(color.CGColor);

    CGFloat r, g, b, a;

    if (colorSpace == kCGColorSpaceModelMonochrome) {
        r = components[0];
        g = components[0];
        b = components[0];
        a = components[1];
    }
    else if (colorSpace == kCGColorSpaceModelRGB) {
        r = components[0];
        g = components[1];
        b = components[2];
        a = components[3];
    }

    return [NSString stringWithFormat:@"#%02lX%02lX%02lX%02lX",
            lroundf(r * 255),
            lroundf(g * 255),
            lroundf(b * 255),
            lroundf(a * 255)];
}

How do I detect whether I am trying to get monochrome as opposed to standard RGB with the colorspace check? All I can see is the change in opacity when testing. Thanks.
Nevermind, I found this to alter the monochrome aka grayscale: [UIColor colorWithWhite:(0.2125 * red) + (0.7154 * green) + (0.0721 * blue) alpha:alpha];
m
m_katsifarakis

Other Swift answers crash for UIColors like white, where there are only 2 components returned by CGColor.

Here's a Swift 4 version that does not have that problem and also returns transparency information in the end of the string if that is required (web format).

The color is first converted to the sRGB colorspace before generating the HEX String to work properly even with Grayscale or other color spaces.

For example:

White will return #FFFFFF

White with 50% opacity will return #FFFFFF7F

extension UIColor {
    var hexString: String {
        let cgColorInRGB = cgColor.converted(to: CGColorSpace(name: CGColorSpace.sRGB)!, intent: .defaultIntent, options: nil)!
        let colorRef = cgColorInRGB.components
        let r = colorRef?[0] ?? 0
        let g = colorRef?[1] ?? 0
        let b = ((colorRef?.count ?? 0) > 2 ? colorRef?[2] : g) ?? 0
        let a = cgColor.alpha

        var color = String(
            format: "#%02lX%02lX%02lX",
            lroundf(Float(r * 255)),
            lroundf(Float(g * 255)),
            lroundf(Float(b * 255))
        )

        if a < 1 {
            color += String(format: "%02lX", lroundf(Float(a * 255)))
        }

        return color
    }
}

OLD VERSION

This version did not work properly with certain colors in non-RGB color spaces.

extension UIColor {
    var hexString: String {
        let colorRef = cgColor.components
        let r = colorRef?[0] ?? 0
        let g = colorRef?[1] ?? 0
        let b = ((colorRef?.count ?? 0) > 2 ? colorRef?[2] : g) ?? 0
        let a = cgColor.alpha

        var color = String(
            format: "#%02lX%02lX%02lX",
            lroundf(Float(r * 255)),
            lroundf(Float(g * 255)),
            lroundf(Float(b * 255))
        )

        if a < 1 {
            color += String(format: "%02lX", lroundf(Float(a)))
        }

        return color
    }
}

a (alpha) is Float value from 0 to 1 so you much do: ------- color += String(format: "%02lX", lroundf(Float(a * 255)))
just implemented this snippet and it works perfect for the moment. Haven't figured out a lot about colors, still have to work on understanding it better :)
This will not work for black colour as there will be also less components. one of the other solutions might solve it
You are absolutely right @JulianKról! My code failed to account for non-RGB color spaces. Please check my updated answer.
I still think it will not make it. Test what you get for black and white colour and you will see if it is right or not :)
A
Artem Sydorenko

Swift way:

extension UIColor {
    var hexString: String {
        cgColor.components![0..<3]
            .map { String(format: "%02lX", Int($0 * 255)) }
            .reduce("#", +)
    }
}

If you need hex with alpha just remove [0..<3] from code.

Another safer implementation, that works fine with one component colors (like UIColor.white, UIColor.black):

    var hexString: String {
        var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0
        getRed(&r, green: &g, blue: &b, alpha: nil)
        return [r, g, b].map { String(format: "%02lX", Int($0 * 255)) }.reduce("#", +)
    }

J
Joel Kopelioff

In Swift, I simply created an extension to UIColor...

extension UIColor
{

    var hexString:NSString {
        let colorRef = CGColorGetComponents(self.CGColor)

        let r:CGFloat = colorRef[0]
        let g:CGFloat = colorRef[1]
        let b:CGFloat = colorRef[2]

        return NSString(format: "#%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255)))
    }
}

I
Isuru
extension UIColor {
    var hexString: String? {
        guard let components = self.cgColor.components else { return nil }

        let red = Float(components[0])
        let green = Float(components[1])
        let blue = Float(components[2])
        return String(format: "#%02lX%02lX%02lX", lroundf(red * 255), lroundf(green * 255), lroundf(blue * 255))
    }
}

I
Ivan Cantarino

Based on Kampai's answer, here's the SwiftUI version.

extension Color {
    func hexString() -> String {
        let components = self.cgColor?.components
        let r: CGFloat = components?[0] ?? 0.0
        let g: CGFloat = components?[1] ?? 0.0
        let b: CGFloat = components?[2] ?? 0.0

        let hexString = String.init(format: "#%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255)))
        return hexString
    }
}

M
Mr T

This is the correct order if you need the colors for Android. the alpha goes first:

extension UIColor {
    var hexString: String? {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0

        let multiplier = CGFloat(255.999999)

        guard self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
            return nil
        }

        if alpha == 1.0 {
            return String(
                format: "#%02lX%02lX%02lX",
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier)
            )
        }
        else {
            return String(
                format: "#%02lX%02lX%02lX%02lX",
                Int(alpha * multiplier),
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier)
            )
        }
    }
}

Then call as:

debugPrint("testColor > ", self.testColor().hexString!)

M
Mostafa Abbastabar

Or you can use .hexCode if use this extension for UIColor.

Like this:

extension UIColor {
    var hexCode: String {
        get{
            let colorComponents = self.cgColor.components!
            if colorComponents.count < 4 {
                return String(format: "%02x%02x%02x", Int(colorComponents[0]*255.0), Int(colorComponents[0]*255.0),Int(colorComponents[0]*255.0)).uppercased()
            }
            return String(format: "%02x%02x%02x", Int(colorComponents[0]*255.0), Int(colorComponents[1]*255.0),Int(colorComponents[2]*255.0)).uppercased()
        }
    }
}

var myColor: UIColor?
myColor = UIColor(red: 1, blue: 1, green: 1, alpha: 1.0)
print(myColor!.hexCode) // output: 
// if you use API, you can do something like this:
print("#\(myColor!.hexCode)") // output: #FFFFFF

H
Haris

The swift 2 answer converted to swift 3

var hexString: String {
    let components = self.cgColor.components

    let red = Float((components?[0])!)
    let green = Float((components?[1])!)
    let blue = Float((components?[2])!)
    return String(format: "#%02lX%02lX%02lX", lroundf(red * 255), lroundf(green * 255), lroundf(blue * 255))
}

Crashes for colors in UIExtendedGrayColorSpace - black for example, since components array size is 2. You shouldn't force unwrap the components.
G
Grant Luck

Potential Trap When Dealing With Alpha: HEX strings come in different formats, some have their alpha at the start of the hex string and other formats have it at the end. Depending on your background you may have a different idea of how the hex string is formatted. For Android developers it will likely be with the alpha at the start, for Web developers it will likely be at the end of the string. SO ALWAYS STATE THE FORMAT OF THE HEX STRING to avoid confusion. Android hex strings are required to have the alpha at the start. So that is a trap people may fall into when it comes to hex strings (I did) and is thus important to say what the expected format is. So if you are developing an app for both iOS and Android what out for this trap.

Links: https://en.wikipedia.org/wiki/RGBA_color_space for details on why a HEX string maybe formatted in different ways, some cases with the alpha at the start. Android links https://developer.android.com/reference/android/graphics/Color.html and https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4

PLEASE NOTE FOR #AARRGGBB Hex string format Use the following code so the Alpha is at the start of the string.

(Note: if color == null black is returned).

+(NSString*)hexStringFromColor:(UIColor *)color
{

    CGFloat r = 0, g = 0, b = 0, a = 1;

    if (color) {
        [color getRed:&r green:&g blue:&b alpha:&a];
    }

    return [NSString stringWithFormat:@"#%02lX%02lX%02lX%02lX",
            lroundf(a * 255.0),
            lroundf(r * 255.0),
            lroundf(g * 255.0),
            lroundf(b * 255.0)
            ];

}

thanks for your answer. Do you have any evidence to support your claim that "result in the wrong color due to placing the alpha at the end"? I'd love to read about it or witness it. I am inclined to disagree given the following documentation by apple the explicitly state the alpha component is initialised last - developer.apple.com/documentation/uikit/uicolor/1621931-init further reading can be found here: developer.apple.com/documentation/uikit/uicolor
I will update my answer as I do cross platform development (iOS and Android) and therefore refer to HEX Strings as #AARRGGBB. Here is a link for the various formats a HEX string can be. en.wikipedia.org/wiki/RGBA_color_space
App Dev Guy, your links refer to UIColor which you are correct are init with the alpha variable last. However for a HEX string it may be formatted with the alpha at the start or at the end depending on the format being used.
yes, correct. The question however infers displaying the result in the NSLog, which in this case is specific to iOS. Naturally displaying the alpha component in string or otherwise, makes sense to do so last. Perhaps consider adding your link to support your answer so other readers better understand what you're referring to :-)
en.wikipedia.org/wiki/RGBA_color_space for details on why a HEX string maybe formatted in different ways, some cases with the alpha at the start. Android hex strings are required to have the alpha at the start. So that is a trap people may fall into when it comes to hex strings (I did) and is thus important to say what the expected format is. So if you are sending a hex string to mobile apps be sure to state the format. Android links developer.android.com/reference/android/graphics/Color.html and gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
o
oscarr

Swift 5

extension Collection {
    public subscript(safe index: Index) -> Element? {
        return startIndex <= index && index < endIndex ? self[index] : nil
    }
}
extension UIColor {
    var hexString: String {
        let components = cgColor.components
        let r: CGFloat = components?[safe: 0] ?? 0.0
        let g: CGFloat = components?[safe: 1] ?? 0.0
        let b: CGFloat = components?[safe: 2] ?? 0.0

        let hexString = String(format: "#%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)),
                               lroundf(Float(b * 255)))

        return hexString
    }
}

D
Den

SwiftUI

P3 Color to HEX

extension Color {

    var hex: String {
        guard let colorSpace = CGColorSpace(name: CGColorSpace.displayP3), let color = UIColor(self).cgColor.converted(to: colorSpace, intent: .defaultIntent, options: nil),
          let components = color.components, 3 <= components.count else { return "" }

        return String(format: "#%02lX%02lX%02lX%02lX", lroundf(Float(components[0] * 255)), lroundf(Float(components[1] * 255)), lroundf(Float(components[2] * 255)), lroundf(Float(components[3] * 255)))
     }
}