Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a GrayScaleBrushes class

Tags:

c#

.net

gdi+

Recently I came across a .NET color chart based on their hue and brightness value. What stroke me is the crazy grayscale chart. For example, DarkGray is actually lighter then Gray ? Also, I can't see any logic in the gradation of rgb values, it goes from 0 to 105 to 128 ?

0   : Black
105 : DimGray 
128 : Gray
169 : DarkGray!
192 : Silver
211 : LightGray 
220 : Gainsboro
245 : Ghostwhite
255 : White

http://sites.google.com/site/cdeveloperresources/

color chart - see link above

What I want is a GrayScaleBrushes class which behaves exactly like the Brushes class, but with my custom scheme, like :

GrayScaleBrushes.Pct05
GrayScaleBrushes.Pct10
GrayScaleBrushes.Pct15
..all the way to.Pct95
...
ie: e.FillRectangle( GrayScaleBrushes.Pct05, exampleRect );

How to do that, making sure that the brushes will dispose correctly ?

Edit: The .NET Brushes class looks like the following (disassembled using reflector ).

public sealed class Brushes
{
    // Fields
    private static readonly object AliceBlueKey = new object();

    // Methods
    private Brushes()
    {
    }

    // Properties
    public static Brush AliceBlue
    {
        get
        {
            Brush brush = (Brush) SafeNativeMethods.Gdip.ThreadData[AliceBlueKey];
            if (brush == null)
            {
                brush = new SolidBrush(Color.AliceBlue);
                SafeNativeMethods.Gdip.ThreadData[AliceBlueKey] = brush;
            }
            return brush;
        }
    }
}

SafeNativeMethods seems unaccessible to me. Suppose I just returned a SolidBrush in a static method, would that make everything dispose correctly ? (And how to test that?)

public sealed class GrayScaleBrushes
{
    private static SolidBrush pct05 = null;

    public static SolidBrush Pct05
    {
        get
        {
            if (pct05 == null)
            {
                int rgbVal = GetRgbValFromPct( 5 );
                pct05 = new SolidBrush(Color.FromArgb(rgbVal, rgbVal, rgbVal));
            }
            return pct05;
        }
    }

    private static int GetRgbValFromPct(int pct)
    {
        return 255 - (int)(((float)pct / 100f) * 255f);
    }
}
like image 464
Run CMD Avatar asked Jan 10 '11 19:01

Run CMD


3 Answers

The SafeNativeMethods is in this case just a simple cache that holds a copy of the brush. So a second call to the property getter won't create a new instance. Instead it will always return the same brush.

To accomplish this you could rewrite your function maybe like this:

public static class GrayScaleBrushes
{
    private static SolidBrush _Pct05;

    public static SolidBrush Pct05
    {
        get
        {
            if (_Pct05 == null)
            {
                var value = GetRgbValFromPct(5);
                _Pct05 = new SolidBrush(Color.FromArgb(value, value, value));
            }

            return _Pct05;
        }
    }

    private static int GetRgbValFromPct(int pct)
    {
        // no need to convert to float and back to int again
        return 255 - ((pct * 255) / 100);
    }
}

This solution will create the gray scales as needed but by the costs of checking for the null every time it is called. You can accomplish this speed problem by changing it again a memory problem by taking an approach like this:

public static class GrayScaleBrushes
{
    public static readonly SolidBrush Pct05;

    static GrayScaleBrushes()
    {
        var value = GetRgbValFromPct(5);
        Pct05 = new SolidBrush(Color.FromArgb(value, value, value));
    }
}

But i think in this case it just a matter of taste, cause nor the speed nor the memory will be a real problem in both cases.

like image 151
Oliver Avatar answered Oct 18 '22 17:10

Oliver


The Brushes class is static can only leak a small number of resources corresponding to the number of colors defined so just let those resources be cleaned up upon application exit. Instead concern yourself with ensuring that your brushes are not actually created unless they are referenced. That will speed up startup and ensure that unused colors don't consume resources.

like image 45
Rick Sladkey Avatar answered Oct 18 '22 17:10

Rick Sladkey


I would recommend the following:

Create a static class GrayScaleBrushes

Create a static Dictionary of with the intensity percentage (int) as the key,

Create a single static Indexed Property 'Pct' that you would use like GrayScaleBrushes.Pct[10] which would return the dictionary entry.

Now you could either do as Oliver said and create the dictionary entries on the fly as they're called, or you could use a static constructor to loop through the 20 entries and add them to the dictionary.

This method woud save you from having to create and maintain the 20 odd properties. Cheers.

like image 1
Andrew Hanlon Avatar answered Oct 18 '22 15:10

Andrew Hanlon