question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Proposal] Color Conversion Extensions

See original GitHub issue

ColorConversionExtensions

  • Proposed
  • Prototype
  • Implementation
    • iOS Support
    • Android Support
    • macOS Support
    • Windows Support
  • Unit Tests
  • Sample
  • Documentation

Summary

Extension methods for Color, e.g. ToRgbString, ToCmykString

Detailed Design

    public static class ColorConversionExtensions
    {
        /// <returns>RGB(255, 255, 255)</returns>
        public static string ToRgbString(this Color c) => $"RGB({c.GetByteRed()},{c.GetByteGreen()},{c.GetByteBlue()})";

        /// <returns>RGBA(255, 255, 255, 255)</returns>
        public static string ToRgbaString(this Color c) =>
            $"RGBA({c.GetByteRed()}, {c.GetByteGreen()}, {c.GetByteBlue()}, {c.GetByteAlpha()})";

        /// <returns>#FFFFFF</returns>
        public static string ToHexRgbString(this Color c) =>
            $"#{c.GetByteRed():X2}{c.GetByteGreen():X2}{c.GetByteBlue():X2}";

        /// <returns>#FFFFFFFF</returns>
        public static string ToHexRgbaString(this Color c) =>
            $"#{c.GetByteRed():X2}{c.GetByteGreen():X2}{c.GetByteBlue():X2}{c.GetByteAlpha():X2}";

        /// <returns>CMYK(100%,100%,100%,100%)</returns>
        public static string ToCmykString(this Color c) =>
            $"CMYK({c.GetPercentCyan():P},{c.GetPercentMagenta():P},{c.GetPercentYellow():P},{c.GetPercentBlackKey():P})";

        /// <returns>CMYK(100%,100%,100%,100%,100%)</returns>
        public static string ToCmykaString(this Color c) =>
            $"CMYKA({c.GetPercentCyan():P},{c.GetPercentMagenta():P},{c.GetPercentYellow():P},{c.GetPercentBlackKey():P},{c.Alpha:P})";

        /// <returns>HSLA(360,100%,100%)</returns>
        public static string ToHslString(this Color c) => $"HSL({c.GetHue():P},{c.GetSaturation():P},{c.GetLuminosity():P})";

        /// <returns>HSLA(360°,100%,100%,100%)</returns>
        public static string ToHslaString(this Color c) =>
            $"HSLA({c.GetDegreeHue()}°,{c.GetSaturation():P},{c.GetLuminosity():P},{c.Alpha:P})";

        public static Color WithRed(this Color baseColor, double newR) =>
            Color.FromRgba(newR, baseColor.Green, baseColor.Blue, baseColor.Alpha);

        public static Color WithGreen(this Color baseColor, double newG) =>
            Color.FromRgba(baseColor.Red, newG, baseColor.Blue, baseColor.Alpha);

        public static Color WithBlue(this Color baseColor, double newB) =>
            Color.FromRgba(baseColor.Red, baseColor.Green, newB, baseColor.Alpha);

        public static Color WithAlpha(this Color baseColor, double newA) =>
            Color.FromRgba(baseColor.Red, baseColor.Green, baseColor.Blue, newA);

        public static Color WithRed(this Color baseColor, byte newR) =>
            Color.FromRgba((double)newR / 255, baseColor.Green, baseColor.Blue, baseColor.Alpha);

        public static Color WithGreen(this Color baseColor, byte newG) =>
            Color.FromRgba(baseColor.Red, (double)newG / 255, baseColor.Blue, baseColor.Alpha);

        public static Color WithBlue(this Color baseColor, byte newB) =>
            Color.FromRgba(baseColor.Red, baseColor.Green, (double)newB / 255, baseColor.Alpha);

        public static Color WithAlpha(this Color baseColor, byte newA) =>
            Color.FromRgba(baseColor.Red, baseColor.Green, baseColor.Blue, (double)newA / 255);

        public static Color WithCyan(this Color baseColor, double newC) =>
            Color.FromRgba((1 - newC) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - baseColor.GetPercentMagenta()) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - baseColor.GetPercentYellow()) * (1 - baseColor.GetPercentBlackKey()),
                           baseColor.Alpha);

        public static Color WithMagenta(this Color baseColor, double newM) =>
            Color.FromRgba((1 - baseColor.GetPercentCyan()) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - newM) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - baseColor.GetPercentYellow()) * (1 - baseColor.GetPercentBlackKey()),
                           baseColor.Alpha);

        public static Color WithYellow(this Color baseColor, double newY) =>
            Color.FromRgba((1 - baseColor.GetPercentCyan()) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - baseColor.GetPercentMagenta()) * (1 - baseColor.GetPercentBlackKey()),
                           (1 - newY) * (1 - baseColor.GetPercentBlackKey()),
                           baseColor.Alpha);

        public static Color WithBlackKey(this Color baseColor, double newK) =>
            Color.FromRgba((1 - baseColor.GetPercentCyan()) * (1 - newK),
                           (1 - baseColor.GetPercentMagenta()) * (1 - newK),
                           (1 - baseColor.GetPercentYellow()) * (1 - newK),
                           baseColor.Alpha);

        public static byte GetByteRed(this Color c) => ToByte(c.Red * 255);

        public static byte GetByteGreen(this Color c) => ToByte(c.Green * 255);

        public static byte GetByteBlue(this Color c) => ToByte(c.Blue * 255);

        public static byte GetByteAlpha(this Color c) => ToByte(c.Alpha * 255);

        // Hue is a degree on the color wheel from 0 to 360. 0 is red, 120 is green, 240 is blue.
        public static double GetDegreeHue(this Color c) => c.GetHue() * 360;

        // Note : double Percent R, G and B are simply Color.R, Color.G and Color.B

        public static double GetPercentBlackKey(this Color c) => 1 - Math.Max(Math.Max(c.Red, c.Green), c.Blue);

        public static double GetPercentCyan(this Color c) =>
            (1 - c.Red - c.GetPercentBlackKey()) / (1 - c.GetPercentBlackKey());

        public static double GetPercentMagenta(this Color c) =>
            (1 - c.Green - c.GetPercentBlackKey()) / (1 - c.GetPercentBlackKey());

        public static double GetPercentYellow(this Color c) =>
            (1 - c.Blue - c.GetPercentBlackKey()) / (1 - c.GetPercentBlackKey());

        public static Color ToInverseColor(this Color baseColor) =>
            Color.FromRgb(1 - baseColor.Red, 1 - baseColor.Green, 1 - baseColor.Blue);

        public static Color ToBlackOrWhite(this Color baseColor) => baseColor.IsDark() ? Colors.Black : Colors.White;

        public static Color ToBlackOrWhiteForText(this Color baseColor) =>
            baseColor.IsDarkForTheEye() ? Colors.White : Colors.Black;

        public static Color ToGrayScale(this Color baseColor)
        {
            var avg = (baseColor.Red + baseColor.Blue + baseColor.Green) / 3;
            return Color.FromRgb(avg, avg, avg);
        }

        public static bool IsDarkForTheEye(this Color c) =>
            (c.GetByteRed() * 0.299) + (c.GetByteGreen() * 0.587) + (c.GetByteBlue() * 0.114) <= 186;

        public static bool IsDark(this Color c) => c.GetByteRed() + c.GetByteGreen() + c.GetByteBlue() <= 127 * 3;

        static byte ToByte(double input)
        {
            if (input < 0)
                return 0;
            if (input > 255)
                return 255;
            return (byte)Math.Round(input);
        }
    }

Usage Syntax

XAML Usage

N/A

C# Usage

var rgbString = Colors.Grey.ToRgbString();

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:15 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
PieEatingNinjascommented, Dec 2, 2021

Just a small update: making good progress on this! Writing the unit tests already has been valuable as I identified some ‘issues’, but I’ll elaborate on that when the PR arrives. image (that’s currently 4451 tests)

Got a small question though: The GetPercentXXX-methods and the GetDegreeHue-method return doubles. Is that intentionally? Do we really need this precision? Any decimal value in Color and in our extension methods is of type float.

1reaction
PieEatingNinjascommented, Nov 25, 2021

I’ll make it so! 😁 It’s a lot of work generating all the test data, so it’ll probably take a while before I got everything tested.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Thread: [Extension Proposal] RGB to HSL
What an extension like this would do is take RGB (red, green, and blue) data and let the user be able to retrieve...
Read more >
Color fonts. Overview of the proposals for color extensions ...
Overview of the proposals for color extensions of the OpenType font format. By Adam Twardoch on 2013-09-19 in News.
Read more >
A Guide To Proposal Color Team Reviews & Ratings
Proposal color reviews consist of a disciplined, logical process to bring an RFP response to completion in winning form.
Read more >
[Proposal]: Roles and extensions #5496 - dotnet csharplang
Roles and extensions present as first-class types, with names and conversions; Stretch goal: Roles and extensions can implement interfaces on ...
Read more >
@babel/plugin-proposal-json-strings | ...
Fast, reliable, and secure dependency management.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found