1

Currently when I want to add a grey color on a Bitmap I use the following

Bitmap.SetPixel(x,y, new Color.FromArgb(100,100,100);

My question more is. It uses some steps that are not required in my opinion:

  1. We have a greyscale color: 100
  2. I have to convert it into a real RGB color (100,100,100)
  3. Then it calculates what color comes out of it, and it's a greyscale again (100)

Requestion

Is there something like this

Bitmap.SetPixel(x,y, new GreyColor(100));
Timo Willemsen
  • 8,717
  • 9
  • 51
  • 82
  • 2
    What kind of "something"? Your question is very vague. – Oded Nov 06 '10 at 11:20
  • Well, my 'problem' is. Is that by using this method, I have a greyscale, im converting it in a color (`Color.FromArgb()`) and then let the program convert it in a greyscale again. – Timo Willemsen Nov 06 '10 at 11:21
  • 1
    i didn't get it, what do you mean? –  Nov 06 '10 at 11:22
  • That hardly explains anything. What "greyscale" have you got? Where from? How are you converting? – Oded Nov 06 '10 at 11:23
  • Well, I have a picturing which doesn't have any real colors, just grayscales. It just didn't make sementically any sense to me why I'd have to convert that value to a RGB Color. – Timo Willemsen Nov 06 '10 at 11:28

3 Answers3

2

There's isn't anything built in to convert a brightness value to a color.

To get the brightness of a color, use the GetBrightness method. It returns a value between 0.0 and 1.0, so you have to scale it up to get a 0-255 value:

Color c = betPixel(x, y);
int brightness = (int)Math.Round(c.GetBrightness() * 255.0);

You can make extension methods to make the code simpler:

public static ColorExtensions {

  public static Color ToGrayscale(this int brightness) {
    return Color.FromArgb(brightness, brightness, brightness);
  }

  public static int FromGrayscale(this Color color) {
    return (int)Math.Round(color.GetBrightness() * 255.0);
  }

}

Usage:

bitmap.SetPixel(x, y, 100.ToGrayscale());
int g = bitmap.GetPixel(x, y).FromGrayscale();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
2

No, there is no such thing as a GreyColor in .NET. A GreyColor is just a particular case of a color, the same way that lime green is a particular case of a color. There is no need for complicating the model.

There are some pre-defined colors that you can use if you can find the color you're looking for. These simply return a Color object that has an ARGB value matching the pre-defined color, so they're really not doing anything different than your code is doing above. They're simply there for the convenience of the programmer who can't or doesn't want to remember the not-so-intuitive RGB color model.

You seem to be concerned about the potential expense or redundancy of creating a Color object, but there are a couple of reasons why this shouldn't be a concern. You can think of the FromArgb method as an overloaded constructor for the Color object: this is the way that you create a color other than the pre-defined ones. It simply creates the color object that is defined as the RGB values that you specify. In fact, there's really no other way to represent a color (aside from alternative color models such as HSV, but even then you'd have to specify three separate values: a hue of 0, a saturation of 0, and a value of 39). We humans can describe colors in much more abstract ways, but a computer doesn't really understand or care about these things. The documentation for the Color structure itself explains that it just represents the RGB values, along with the alpha (transparency) value. It's a very small object that contains about 4 byte values. And that's precisely how the method that you pass the color to (Bitmap.SetPixel) is going to draw the color, based on those red, green, and blue values.

It's also worth pointing out that Color is a structure, which is a value type, rather than a reference type. That means, among other things, that it lives inline, wherever your variable is defined. It doesn't point to another object, it lives locally on the stack rather than on the heap, and the stack is cheap. This makes it at least somewhat less expensive than a reference type such as a class.

Finally, I'd be remiss if I didn't point out that this type of micro-optimization is rarely going to make any difference in the performance of your code.

In short, no there's no such thing, but that's nothing to worry about.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
1

You can create 8bpp-indexed bitmaps and work with them:

var bmp = new Bitmap(width, height,
    System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

You'll have to write your own get/set pixel methods though, for example (not tested, but should give a general idea how to do it):

public static byte GetIndexedPixel(this Bitmap bitmap, int x, int y)
{
    var bd = bitmap.LockBits(new Rectangle(x, y, 1, 1),
        System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    var color = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0);
    bitmap.UnlockBits(bd);
    return color;
}

public static void SetIndexedPixel(this Bitmap bitmap, int x, int y, byte color)
{
    var bd = bitmap.LockBits(new Rectangle(x, y, 1, 1),
        System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    System.Runtime.InteropServices.Marshal.WriteByte(bd.Scan0, color);
    bitmap.UnlockBits(bd);
}

Generally, i dont think you should do it, if you don't generate in-memory byte arrays of grayscale pixels and want to convert them to bitmap in several CopyMemory calls. If you use SetPixel/GetPixel though, performance might be not an issue.

max
  • 33,369
  • 7
  • 73
  • 84