UIColorが暗いか明るいかを確認しますか?


107

選択したUIColor(ユーザーが選んだ)が暗いか明るいかを判断する必要があるので、読みやすくするために、その色の上にあるテキスト行の色を変更できます。

Flash / Actionscriptの例(デモあり)は次のとおりです。http//web.archive.org/web/20100102024448/http://theflashblog.com/?p = 173

何かご意見は?

乾杯、アンドレ

更新

みんなの提案のおかげで、ここに作業コードがあります:

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

もう一度ありがとう :)


一部の色には、UIColor.blackなどの3つのコンポーネントがないようです。
グレンハウズ

回答:


75

W3Cには次のものがあります。http//www.w3.org/WAI/ER/WD-AERT/#color-contrast

黒または白のテキストのみを使用している場合は、上記の色の明るさの計算を使用してください。125未満の場合は、白いテキストを使用します。125以上の場合は、黒いテキストを使用します。

編集1:黒いテキストに偏る。:)

編集2:使用する数式は、((赤の値* 299)+(緑の値* 587)+(青の値* 114))/ 1000です。


色の赤、緑、青の値を取得する方法を知っていますか?
Andre

を使用NSArray *components = (NSArray *)CGColorGetComponents([UIColor CGColor]);して、アルファを含むカラーコンポーネントの配列を取得できます。ドキュメントでは、それらの順序を指定していませんが、赤、緑、青、アルファになると思います。また、ドキュメントから、「配列のサイズは、色の色空間のコンポーネントの数よりも1つ多い」と述べています。-それは理由を述べていません...
Jasarien 2010年

それは奇妙です...使用:NSArray * components =(NSArray *)CGColorGetComponents(newColor.CGColor); NSLog(@ "マイカラーコンポーネント%f%f%f%f"、コンポーネント[0]、コンポーネント[1]、コンポーネント[2]、コンポーネント[3]); 値を取得できるかどうかを確認するために、0のインデックスのみが変更されているようです。他の色は、選択した色に関係なく同じままです。なぜだろう?
Andre

とった。NSArrayは使用できません。代わりにこれを使用してください:const CGFloat * components = CGColorGetComponents(newColor.CGColor); また、順序は次のとおりです。赤はコンポーネント[0]です。緑はコンポーネント[1]です。青はコンポーネントです[2]。alphaはコンポーネントです[3]。
Andre

ああ、私の悪い。C配列ではなく、CFArrayRefが返されると思いました。ごめんなさい!
Jasarien

44

これは、このチェックを実行するためのSwift(3)拡張機能です。

この拡張機能はグレースケールカラーで機能します。ただし、RGB初期化子で、すべての色を作成し、使用していない場合のような色に建てられたUIColor.blackUIColor.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


6
よく働く。Swift 2.0の場合-明るさの計算でコンパイラエラーが発生しました:「式が複雑すぎて、適切な時間で解けません。式を個別の部分式に分割することを検討してください」。タイプを追加することで修正しました: "let bright =(((components [0] * 299.0)as CGFloat)+((components [1] * 587.0)as CGFloat)+((components [2] * 114.0))as CGFloat )/(CGFloatとして1000.0) "
GK100

1
Swift 2.1でも同じ問題が発生しました。でコンポーネントにアクセスする代わりに、コンポーネントの変数を作成するだけでこの問題を解決しましたcomponents[0]。このように:let componentColorX: CGFloat = components[1]
ペトリッツ2015年

1
Xcodeは明るさを示しています= "式が複雑すぎて妥当な時間で解決できません。式を個別の部分式に分解することを検討してください"
daidai

だいだい、表現を単純化するだけ。最後の分割は不要です。0から1の範囲で作業する必要はありません。1000で除算しないで、値が500より大きいかどうかを確認してください。
aronspring 2016年

32

Erik Nedwidekの答えを使用して、簡単に含めるための小さなコードスニペットを思いつきました。

- (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];
}

私はこのコードを使用し、完全に機能しましたが、[UIColor blackColor]を設定すると、darknessScore = 149.685を返します。これがなぜ起こっているのか説明できますか?
DivineDesert

3
このコードは、などの非RGBカラーでは機能しませんUIColor whiteColor, grayColor, blackColor
rmaddy 2014年

@rmaddyなぜですか?それとも、whiteColor、grayColor、およびblackColor RGBカラーではないのですか?
mattsven 2015

1
@rmaddy RGBカラースペースとグレースケールの色の違いをプログラムでどのように確認できますか?
mattsven 2015

1
@maddy Nevermind!助けてくれてありがとう- stackoverflow.com/questions/1099569/...
mattsven

31

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
}

私にとってはこれが一番です。チェックの白の範囲をニーズに合わせて設定することもでき、非常にシンプルでネイティブです。ありがとう。
Andreas777

9

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

1
コンポーネントは2つしかなく、RGB表現ではないため、UIColor.whiteのようなデフォルトのシステムカラーではおそらく機能しません。
2018

7

カテゴリ内のこの問題に対する私の解決策(ここの他の回答から引用)。また、これを書いている時点では、他のどの回答も行わないグレースケールカラーでも機能します。

@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

RGB以外の色の適切な処理-魅力のように動作します。
ハトゥニケ2015

5

よりシンプルな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
    }
}

2
コンポーネントは2つしかなく、RGB表現ではないため、UIColor.whiteのようなデフォルトのシステムカラーではおそらく機能しません。
2018

ほんとだ!色を16進数の文字列に変換してからUIColorに戻し、それを考慮することができます。
Sunkas

3

ブロックバージョンを使用する場合:

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

灰色がかっていないものすべてについては、色のRGB反転は通常、それと非常に対照的です。デモは単に色を反転させ、彩度を下げます(灰色に変換します)。

しかし、心地よい色の組み合わせを生成することは非常に複雑です。見る :

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


1
そのiPhoneバージョンがあった場合のみ:D
Andre

色のRGB値(方法がわからない)を取得し、それらの値の逆の新しい色を作成した場合、それは非常に基本的なレベルで機能するはずですか?
Andre

2

次の方法は、白の色に基づいてSwift言語で色が明るいか暗いかを見つけることです。

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
}

次の方法は、カラーコンポーネントを使用してSwiftで色が明るいか暗いかを見つけることです。

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

CGColorGetComponentsのみを使用してもうまくいかなかったため、白のようなUIColorsの2つのコンポーネントを取得しました。だから私は最初に色空間モデルをチェックする必要があります。これは、@ 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
    }

2

UIColorには、HSB色空間に変換する次のメソッドがあります。

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

1
- (BOOL)isColorLight:(UIColor*)color
{
    CGFloat white = 0;
    [color getWhite:&white alpha:nil];
    return (white >= .85);
}

追加されたSwift 5バージョン:

var white: CGFloat = 0.0
color.getWhite(&white, alpha: nil)
return white >= .85 // Don't use white background

1
これUIColorはグレースケールカラーの場合にのみ機能します。ランダムなRGBカラーはこのコードでは機能しません。
rmaddy 2014年

0

色の明るさを確認したい場合は、いくつかの擬似コードを次に示します。

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

0.5より大きい場合は明るく、それ以外の場合は暗くなります。


2
各色に均等に重みを付けることはできません。私たちの目は青に対して偏りがあり、多少は赤です。
Erik Nedwidek

@ErikNedwidek:結局のところ、質問は単に色の明るさを尋ねるだけです:)
Bryan Denny
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.