Проверьте, является ли UIColor темным или светлым? - PullRequest
97 голосов
/ 24 марта 2010

Мне нужно определить, является ли выбранный UIColor (выбранный пользователем) темным или светлым, чтобы я мог изменить цвет строки текста, расположенной поверх этого цвета, для лучшей читаемости.

Вот пример во Flash / Actionscript (с демонстрацией): http://web.archive.org/web/20100102024448/http://theflashblog.com/?p=173

Есть мысли?

Ура, Andre

UPDATE

Спасибо всем за предложения, вот рабочий код:

- (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");
    }
}

Еще раз спасибо:)

Ответы [ 15 ]

69 голосов
/ 24 марта 2010

W3C имеет следующее: http://www.w3.org/WAI/ER/WD-AERT/#color-contrast

Если вы делаете только черный или белый текст, используйте приведенный выше расчет яркости цвета. Если это ниже 125, используйте белый текст. Если это 125 или выше, используйте черный текст.

редактировать 1: смещение в сторону черного текста. :)

edit 2: Используемая формула: ((значение Red * 299) + (значение Green * 587) + (значение Blue * 114)) / 1000.

30 голосов
/ 14 марта 2015

Вот расширение Swift (3) для выполнения этой проверки.

Это расширение работает с оттенками серого. Однако, если вы создаете все свои цвета с помощью инициализатора RGB и не используете встроенные цвета, такие как UIColor.black и UIColor.white, то, возможно, вы можете удалить дополнительные проверки.

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)
    }
}

Тесты:

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")
}

Примечание. Обновлено до Swift 3 12/7/18

30 голосов
/ 19 августа 2013

Используя ответ Эрика Недуоллкка, я придумал небольшой фрагмент кода для легкого включения.

- (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];
}
27 голосов
/ 15 октября 2016

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
}
7 голосов
/ 17 ноября 2017

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 голосов
/ 22 апреля 2015

Мое решение этой проблемы в категории (взято из других ответов здесь). Также работает с полутоновыми цветами, что на момент написания ни один из других ответов не делал.

@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
4 голосов
/ 20 марта 2017

Расширение Simpler Swift 3:

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
    }
}
3 голосов
/ 02 декабря 2014

Если вы предпочитаете блочную версию:

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;
};
2 голосов
/ 12 октября 2018

UIColor имеет следующий метод для преобразования в цветовое пространство HSB :

- (BOOL)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha;
2 голосов
/ 23 ноября 2017

Для меня использование только CGColorGetComponents не сработало, я получил 2 компонента для UIColors, как белый. Поэтому я должен сначала проверить цветовое пространство модели. Это то, что я придумал, и это оказалось быстрой версией ответа @ mattsven.

Цветовое пространство взято отсюда: 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
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...