web-dev-qa-db-fra.com

Vérifiez si UIColor est sombre ou lumineux?

J'ai besoin de déterminer si une UIColor sélectionnée (choisie par l'utilisateur) est foncée ou lumineuse, donc je peux changer la couleur d'une ligne de texte qui se trouve au-dessus de cette couleur, pour une meilleure lisibilité.

Voici un exemple dans Flash/Actionscript (avec démo): http://web.archive.org/web/20100102024448/http://theflashblog.com/?p=17

Des pensées?

À la vôtre, André

[~ # ~] mise à jour [~ # ~]

Merci aux suggestions de tous, voici le code de travail:

- (void) updateColor:(UIColor *) newColor
{
    const CGFloat *componentColors = CGColorGetComponents(newColor.CGColor);

    CGFloat colorBrightness = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
    if (colorBrightness < 0.5)
    {
        NSLog(@"my color is dark");
    }
    else
    {
        NSLog(@"my color is light");
    }
}

Encore merci :)

98
Andre

Le W3C a les éléments suivants: http://www.w3.org/WAI/ER/WD-AERT/#color-contrast

Si vous ne faites que du texte en noir ou blanc, utilisez le calcul de la luminosité des couleurs ci-dessus. S'il est inférieur à 125, utilisez du texte blanc. S'il est égal ou supérieur à 125, utilisez du texte noir.

modifier 1: biais vers le texte noir. :)

modifier 2: La formule à utiliser est ((valeur rouge * 299) + (valeur verte * 587) + (valeur bleue * 114))/1000.

69
Erik Nedwidek

Voici une extension Swift (3) pour effectuer cette vérification.

Cette extension fonctionne avec des couleurs en niveaux de gris. Cependant, si vous créez toutes vos couleurs avec l'initialiseur RVB et n'utilisez pas les couleurs intégrées telles que UIColor.black et UIColor.white, alors vous pouvez éventuellement supprimer les vérifications supplémentaires.

extension UIColor {

    // Check if the color is light or dark, as defined by the injected lightness threshold.
    // Some people report that 0.7 is best. I suggest to find out for yourself.
    // A nil value is returned if the lightness couldn't be determined.
    func isLight(threshold: Float = 0.5) -> Bool? {
        let originalCGColor = self.cgColor

        // Now we need to convert it to the RGB colorspace. UIColor.white / UIColor.black are greyscale and not RGB.
        // If you don't do this then you will crash when accessing components index 2 below when evaluating greyscale colors.
        let RGBCGColor = originalCGColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil)
        guard let components = RGBCGColor?.components else {
            return nil
        }
        guard components.count >= 3 else {
            return nil
        }

        let brightness = Float(((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000)
        return (brightness > threshold)
    }
}

Tests:

func testItWorks() {
    XCTAssertTrue(UIColor.yellow.isLight()!, "Yellow is LIGHT")
    XCTAssertFalse(UIColor.black.isLight()!, "Black is DARK")
    XCTAssertTrue(UIColor.white.isLight()!, "White is LIGHT")
    XCTAssertFalse(UIColor.red.isLight()!, "Red is DARK")
}

Remarque: mise à jour vers Swift 3 12/7/18

31
josh-fuggle

En utilisant la réponse d'Erik Nedwidek, j'ai trouvé ce petit extrait de code pour une inclusion facile.

- (UIColor *)readableForegroundColorForBackgroundColor:(UIColor*)backgroundColor {
    size_t count = CGColorGetNumberOfComponents(backgroundColor.CGColor);
    const CGFloat *componentColors = CGColorGetComponents(backgroundColor.CGColor);

    CGFloat darknessScore = 0;
    if (count == 2) {
        darknessScore = (((componentColors[0]*255) * 299) + ((componentColors[0]*255) * 587) + ((componentColors[0]*255) * 114)) / 1000;
    } else if (count == 4) {
        darknessScore = (((componentColors[0]*255) * 299) + ((componentColors[1]*255) * 587) + ((componentColors[2]*255) * 114)) / 1000;
    }

    if (darknessScore >= 125) {
        return [UIColor blackColor];
    }

    return [UIColor whiteColor];
}
30
Remy Vanherweghem

Swift3

extension UIColor {
    var isLight: Bool {
        var white: CGFloat = 0
        getWhite(&white, alpha: nil)
        return white > 0.5
    }
}

// Usage
if color.isLight {
    label.textColor = UIColor.black
} else {
    label.textColor = UIColor.white
}
28
neoneye

Ma solution à ce problème dans une catégorie (tirée d'autres réponses ici). Fonctionne également avec des couleurs en niveaux de gris, ce qui, au moment de la rédaction, ne fait aucune des autres réponses.

@interface UIColor (Ext)

    - (BOOL) colorIsLight;

@end

@implementation UIColor (Ext)

    - (BOOL) colorIsLight {
        CGFloat colorBrightness = 0;

        CGColorSpaceRef colorSpace = CGColorGetColorSpace(self.CGColor);
        CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);

        if(colorSpaceModel == kCGColorSpaceModelRGB){
            const CGFloat *componentColors = CGColorGetComponents(self.CGColor);

            colorBrightness = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
        } else {
            [self getWhite:&colorBrightness alpha:0];
        }

        return (colorBrightness >= .5f);
    }

@end
7
mattsven

Version Swift 4

extension UIColor {
    func isLight() -> Bool {
        guard let components = cgColor.components, components.count > 2 else {return false}
        let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000
        return (brightness > 0.5)
    }
}
7
Kaiyuan Xu

Plus simple Swift 3 extension:

extension UIColor {
    func isLight() -> Bool {
        guard let components = cgColor.components else { return false }
        let redBrightness = components[0] * 299
        let greenBrightness = components[1] * 587
        let blueBrightness = components[2] * 114
        let brightness = (redBrightness + greenBrightness + blueBrightness) / 1000
        return brightness > 0.5
    }
}
4
Sunkas

Si vous préférez la version bloc:

BOOL (^isDark)(UIColor *) = ^(UIColor *color){
    const CGFloat *component = CGColorGetComponents(color.CGColor);
    CGFloat brightness = ((component[0] * 299) + (component[1] * 587) + (component[2] * 114)) / 1000;

    if (brightness < 0.75)
        return  YES;
    return NO;
};
3
kakilangit

UIColor a la méthode suivante pour convertir en espace colorimétrique HSB:

- (BOOL)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha;
2
Cuddy

La méthode suivante consiste à trouver la couleur claire ou foncée en Swift langue basée sur le blanc en couleur.

func isLightColor(color: UIColor) -> Bool 
{
   var white: CGFloat = 0.0
   color.getWhite(&white, alpha: nil)

   var isLight = false

   if white >= 0.5
   {
       isLight = true
       NSLog("color is light: %f", white)
   }
   else
   {
      NSLog("Color is dark: %f", white)
   }

   return isLight
}

La méthode suivante consiste à trouver la couleur claire ou foncée dans Swift en utilisant des composants de couleur.

func isLightColor(color: UIColor) -> Bool 
{
     var isLight = false

     var componentColors = CGColorGetComponents(color.CGColor)

     var colorBrightness: CGFloat = ((componentColors[0] * 299) + (componentColors[1] * 587) + (componentColors[2] * 114)) / 1000;
     if (colorBrightness >= 0.5)
     {
        isLight = true
        NSLog("my color is light")
     }
     else
     {
        NSLog("my color is dark")
     }  
     return isLight
}
2
abhi

Pour moi, utiliser uniquement CGColorGetComponents n'a pas fonctionné, j'obtiens 2 composants pour UIColors comme le blanc. Je dois donc d'abord vérifier l'espace colorimétrique. C'est ce que j'ai trouvé qui a fini par être la version Swift de la réponse de @ mattsven.

Espace colorimétrique pris à partir d'ici: https://stackoverflow.com/a/16981916/4905076

extension UIColor {
    func isLight() -> Bool {
        if let colorSpace = self.cgColor.colorSpace {
            if colorSpace.model == .rgb {
                guard let components = cgColor.components, components.count > 2 else {return false}

                let brightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000

                return (brightness > 0.5)
            }
            else {
                var white : CGFloat = 0.0

                self.getWhite(&white, alpha: nil)

                return white >= 0.5
            }
        }

        return false
    }
2
Lucho

Pour tout ce qui n'est pas grisâtre, l'inverse RVB d'une couleur est généralement très contrasté avec elle. La démo inverse simplement la couleur et la désature (la convertit en gris).

Mais générer une belle combinaison de couleurs apaisantes est assez compliqué. Regarder :

http://particletree.com/notebook/calculating-color-contrast-for-legible-text/

2
rep_movsd
- (BOOL)isColorLight:(UIColor*)color
{
    CGFloat white = 0;
    [color getWhite:&white alpha:nil];
    return (white >= .5);
}
0
Mike Glukhov

L'utilisation de HandyUIKit en fait une évidence , par exemple:

import HandyUIKit    

UIColor.black.hlca.luminance     // => 0.0
UIColor.white.hlca.luminance     // => 1.0
UIColor.lightGray.hlca.luminance // => 0.70
UIColor.darkGray.hlca.luminance  // => 0.36
UIColor.red.hlca.luminance       // => 0.53
UIColor.green.hlca.luminance     // => 0.87
UIColor.blue.hlca.luminance      // => 0.32

En utilisant simplement .hlca.luminance sur n'importe quelle instance de UIColor vous donnera la valeur correcte pour la légèreté perçue . La plupart des autres approches ne prennent pas en compte le fait que les humains perçoivent des couleurs différentes (même lorsque la saturation et la luminosité sont les mêmes) à différents niveaux de luminosité . Les valeurs luminance en tiennent compte.

Lisez cet excellent article de blog ou l'entrée Wikipedia sur le LAB espace colorimétrique pour plus d'explications. Ils expliqueront également pourquoi le système de couleurs HSB avec sa valeur brightness n'est que la moitié de la solution.

À titre indicatif: notez que la valeur luminance de la couleur vert pur est beaucoup plus élevée que sur la couleur bleu pur . C'est tout simplement parce que les humains perçoivent le bleu pur comme une couleur beaucoup plus sombre que le vert pur.

0
Dschee

Si vous souhaitez retrouver la luminosité de la couleur, voici un pseudo code:

public float GetBrightness(int red, int blue, int green)
{
    float num = red / 255f;
    float num2 = blue / 255f;
    float num3 = green / 255f;
    float num4 = num;
    float num5 = num;
    if (num2 > num4)
        num4 = num2;
    if (num3 > num4)
        num4 = num3;
    if (num2 < num5)
        num5 = num2;
    if (num3 < num5)
        num5 = num3;
    return ((num4 + num5) / 2f);
}

S'il est> 0,5, il est clair et sinon sombre.

0
Bryan Denny