0

I am trying to increase the red value of an image by fifty percent. Here is my code:

public static Bitmap IncreaseRedFiftyPercent(Bitmap b)
    {
        Bitmap temp = (Bitmap) b;
        Bitmap bmap = (Bitmap)temp.Clone();
        Color c;
        for (int i = 0; i < bmap.Width; i++)
        {
            for (int j = 0; j < bmap.Height; j++)
            {
                c = bmap.GetPixel(i, j);
                byte increase = c.R + c.R * 0.5;  //This line gives error

                bmap.SetPixel(i, j, Color.FromArgb(increase, c.G, c.B));
            }
        }
        b = (Bitmap)bmap.Clone();
        return b;
    }

Here is what i do: I read all pixels of the picture, and increase the red value by fifty percent and keep blue and green the same. But the line

byte increase = c.R + c.R * 0.5;  //This line gives error

gives me an error saying that

Cannot implicitly convert type 'double' to 'byte'. An explicit conversion exists (are you missing     
a cast?)    

And i cannot convert double to byte? It looks like sensible what i am doing, what is wrong here?

Thanks

user2246674
  • 7,621
  • 25
  • 28
yrazlik
  • 10,411
  • 33
  • 99
  • 165
  • There is only one line that even matters - the last one. `byte b = somedouble;` is invalid. You must explicitly cast a *double* back to a *byte* (e.g. `(byte)somedouble`); the error message says there is no implicit conversion (as there is from byte -> double). – user2246674 Oct 01 '13 at 22:31
  • just use `byte increase = (byte)(c.R + c.R * 0.5);` – Ilya Ivanov Oct 01 '13 at 22:35
  • Thanks for the answers, i did that but it does not seem like red increased. How can i check whether my code is doing what i really want? I tried to use some image viewers to increase red and compare the pictures but i could not do it. Any sugestions l,ke some programs to check it? – yrazlik Oct 01 '13 at 22:38
  • @panpa: set a break point and inspect the value of the variable before and after. You don't expect the end result be more than 255, do you? – Andrew Savinykh Oct 01 '13 at 22:40
  • @zespri thanks, but this is a 2048*3096 pixels picture. Should i check for all the red values of all pixels? I thought i can just increase red by an image viewer and compare results – yrazlik Oct 01 '13 at 22:44
  • @panpa: isn't it what your code is already doing? – Andrew Savinykh Oct 01 '13 at 22:48
  • @panpa: You should only need to check a couple. If it is working for some pixels it is likely working for all. If it isn't working for one then well, you've found a bug to fix (and it probably isn't working with any). If there is a lot of colours with red=0 you could set a conditional breakpoint so you are only checking the values for ones that should change. – Chris Oct 01 '13 at 22:48
  • These questions might also help you: http://stackoverflow.com/questions/4343624/integer-summing-blues-short-short-problem/4347752#4347752 and http://stackoverflow.com/questions/941584/byte-byte-int-why – Eric Lippert Oct 01 '13 at 22:50
  • @Chris yeah you are right i already checked a few and they are all right, i just wanted to see the whole picture to be completely sure and to be sure there are no buggy pixels, but you are right it should be working for all – yrazlik Oct 01 '13 at 22:51
  • 1
    Using `SetPixel` on every pixel in an image tends to be very slow. If your performance is unacceptable, you can try editing the image memory more directly. See [Bob Powell's Tutorial](http://bobpowell.net/lockingbits.aspx). This is admittedly slightly advanced, as hinted by the use of the `unsafe` keyword. – Brian Oct 02 '13 at 13:45

3 Answers3

8

Arithmetic in C# is performed by first determining which operator to use by choosing from a list of possible operators:

int * int --> int
long * long --> long
double * double --> double

and so on; that list is quite long.

In your case the best operator is double * double --> double, and so the byte is converted to double. This is lossless. But the result is a double; it might have a fractional part, and its magnitude might be larger than the largest possible byte. Converting back to byte is lossy. Therefore you are required to say "I guarantee that I really want to make this lossy conversion" by inserting a cast to byte.

Now, before you do so you should make sure that you are in fact doing the right thing! If the byte is already at, say, 200, then increasing it by 50% to the double 300.00 and then converting that back to a byte that can only be between 0 and 255 is likely to produce unexpected results. Think carefully before you insert that cast.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
5

You could use this instead, although it won't account for overflow (any result over 255 will roll over to 0):

byte increase = (byte)(c.R + c.R / 2);

Note that I use /2 instead of *0.5 to use integer math instead of floating-point math. If you're processing lots of large images the performance difference could be significant.

Based on your requirement something like this may work:

byte increase = (byte)(Math.Min(c.R + c.R / 2 , 255));
D Stanley
  • 149,601
  • 11
  • 178
  • 240
1

The problem is that when you take a byte (eg c.R) and multiply by a double (eg 0.5) then the result is a double (because a byte may not have the precision to hold the result). You are then trying to assign this to a byte and as the error message says no implicit conversion exists so you have to explicitly convert it.

This can be done with something like

byte increase = (byte)(c.R + c.R * 0.5);

And I've been reminded by another answer that this won't check for overflow so if c.R is more than 170 then you will get overflow issues. To this end you will want to do something like D Stanley's Min technique.

Chris
  • 27,210
  • 6
  • 71
  • 92