Is there an easy way to take all the pixels in a PictureBox and decrement their RGB values in C#? If so, could I get some code to have as an example? If someone doesn't mind, that is.
I made this up on the spot, it may not work properly:

Code:
Bitmap image = (Bitmap)pictureBox.Image;
for (int y = 0; y < image.Height; y++)
for (int x = 0; x < image.Width; x++)
{
Color oldColor = image.GetPixel(x, y);
Color newColor = Color.FromArgb(oldColor.A - 1, oldColor.R - 1, oldColor.G - 1, oldColor.B - 1);
image.SetPixel(x, y, newColor);
}
pictureBox.Image = image;
It seems to work Very Happy Thanks. Is there any way to keep it from going below 0? Or would I have to do a ternary thing:
Code:
oldColor.R -1 < 0 ? 0 : oldColor.R - 1

Code:
Bitmap image = (Bitmap)pictureBox.Image; 
for (int y = 0; y < image.Height; y++) 
for (int x = 0; x < image.Width; x++) 

Color oldColor = image.GetPixel(x, y);
int A = oldColor.A - 1;
int R = oldColor.R - 1;
int G = oldColor.G - 1;
int B = oldColor.B - 1;
A = A < 0 ? 0 : A;
R = A < 0 ? 0 : R;
G = A < 0 ? 0 : G;
B = A < 0 ? 0 : B;
Color newColor = Color.FromArgb(A, R, G, B); 
image.SetPixel(x, y, newColor); 

pictureBox.Image = image;
Note this code also decrements the alpha channel, as well as RGB.
I noticed that, and changed it in my code Smile Thanks SIr Smile
Just curious, what is this for?
A program to draw lines and then make them fade out gradually. I am setting some pixels to white and letting a timer decrement all the pixels. I think I'm going to make it decrement by a larger value (like 10).
Fun stuff, sounds interesting.
Note that whilst SirCmpwn's code works it is also very slow; you'd certainly notice it on larger images! The Width and Height properties incur quite a hefty overhead between managed .NET and unmanaged GDI+, and GetPixel/SetPixel lock and unlock the image every single time they are called. It is better to cache the Width/Height properties yourself and to lock/unlock the entire image just once.


Code:
Bitmap bmp = (Bitmap)pictureBox.Image;

// Retrieve the width and height of the image (just the once).
int width = bmp.Width, height = bmp.Height;

// Lock the bitmap so we can access its internal data.
var lockedBmp = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
try {

   // Create an array of 32-bit integers to store the pixels in.
   // One array element is one pixel.
   // "Stride" is the total width of the image in bytes and may be larger than the width of the image data * 4 due to alignment/padding.
   var pixelData = new int[lockedBmp.Height * lockedBmp.Stride / 4];

   // Copy the data from the bitmap to our array.
   // BitmapData.Scan0 is the address of the first pixel in the image.
   Marshal.Copy(lockedBmp.Scan0, pixelData, 0, pixelData.Length);

   // Loop over each pixel in the image.
   for (int i = 0; i < pixelData.Length; ++i) {
      // Retrieve the current pixel data as a Color structure.
      var pixelColour = Color.FromArgb(pixelData[i]);
               
      // Adjust and store the new colour.
      pixelData[i] = Color.FromArgb(
         pixelColour.A,
         Math.Max(0, pixelColour.R - 1),
         Math.Max(0, pixelColour.G - 1),
         Math.Max(0, pixelColour.B - 1)
      ).ToArgb();
   }

   // Copy the data back from our array into the image:
   Marshal.Copy(pixelData, 0, lockedBmp.Scan0, pixelData.Length);

} finally {
   // Unlock the bitmap when we're done.
   bmp.UnlockBits(lockedBmp);
}
Ah, that explains why it was so laggy when it was running. Thank you greatly Benryves! One question, what is "Marshal.Copy()", is it the same thing as using ldir on the z80s?
Marshal.Copy can be used to copy a block of data between a managed array and unmanaged memory. I suppose you could say it is a bit like LDIR in that regard, except that it transfers data between two different memory environments (managed/unmanaged).
Huzzah for Ben and his knowledge and well-commented code. Wink
benryves wrote:
Note that whilst SirCmpwn's code works it is also very slow; you'd certainly notice it on larger images! The Width and Height properties incur quite a hefty overhead between managed .NET and unmanaged GDI+, and GetPixel/SetPixel lock and unlock the image every single time they are called. It is better to cache the Width/Height properties yourself and to lock/unlock the entire image just once.


Note however that this solves the question you asked, but *NOT* the problem.

Your solution is a bad one for the problem you describe (fade out a line). You are modifying tons and tons of pixels unnecessarily, and in a way that can't easily be improved in the future (eg, switching to hardware accelerated drawing).

It works, but really poorly (and it blanket affects the entire image, not just the lines to fade out).

An alternative approach would be to track what lines you are displaying, and just keep redrawing that specific line with a color that slowly fades to the background color (if it's a solid color this is really easy, if it isn't you'll need to do like an alpha blend on the background image), and then removing the line from your list once it finishes animating out.

Also, you really don't want to use a PictureBox, you should really just do the drawing yourself.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement