Author Topic: Bitmap pixel color change  (Read 3337 times)

0 Members and 1 Guest are viewing this topic.

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Bitmap pixel color change
« on: May 14, 2007, 07:08:58 PM »
I've got a bitmap that I want to change two colors in.
I want to change black pixels to white and vice-verse.

After iterating the bitmap one pixel at a time using getpixel and setpixel I found that it was too slow for my needs.
I found another way that I would like to try but it is a bit over my head.

Here is what I have so far:
Code: [Select]
       
        private Bitmap SetBlackBackground(Bitmap aBmp)
        {
            Bitmap bmp = aBmp;

            System.Drawing.Imaging.PixelFormat pxf = System.Drawing.Imaging.PixelFormat.Format32bppRgb;
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, pxf);

            IntPtr ptr = bmpData.Scan0;
            int numBytes = bmp.Width * bmp.Height * 3;
            byte[] rgbValues = new byte[numBytes];
            int g = 0;
            int b = 0;
            // BREAKS ON THE NEXT LINE
            Marshal.Copy(ptr, rgbValues, 0, numBytes);
            for (int counter = 0; counter < rgbValues.Length; counter += 3)
            {
                g = counter + 1;
                b = counter + 2;
                if ((rgbValues[counter] == 255) & (rgbValues[g] == 255) & (rgbValues[b] == 255))
                {
                    rgbValues[counter] = 0;
                    rgbValues[g] = 0;
                    rgbValues[b] = 0;
                }
                else
                {
                    if ((rgbValues[counter] == 0) & (rgbValues[g] == 0) & (rgbValues[b] == 0))
                    {
                        rgbValues[counter] = 255;
                        rgbValues[g] = 255;
                        rgbValues[b] = 255;
                    }
                }
            }

            Marshal.Copy(rgbValues, 0, ptr, numBytes);

            bmp.UnlockBits(bmpData);

            return bmp;
        }

The code breaks where indicated above.
The error says "Attempted to read or write protected memory".
This is my first encounter with "Marshal" so I'm not sure where to start looking for the error.

Don't be shy.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bitmap pixel color change
« Reply #1 on: May 14, 2007, 09:05:44 PM »
No Idea Mark, Sorry.

A side note : Do you need the 'Allow unsafe Code' option toggled on for Marshal to work.?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

MickD

  • King Gator
  • Posts: 3639
  • (x-in)->[process]->(y-out) ... simples!
Re: Bitmap pixel color change
« Reply #2 on: May 14, 2007, 09:29:01 PM »
Have a look at this link, looks like it may be of use.

<edit>note, that is an unsafe method, If I can dig up my Petzolds' for C# I'll see if I can find something more suitable for .net, I remember seeing it in there somewhere.
hth
« Last Edit: May 14, 2007, 09:34:13 PM by MickD »
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8740
  • AKA Daniel
Re: Bitmap pixel color change
« Reply #3 on: May 14, 2007, 09:50:11 PM »
Also have a look at the samples in  http://msdn2.microsoft.com/en-us/library/ms146635.aspx


mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Bitmap pixel color change
« Reply #4 on: May 15, 2007, 12:43:18 PM »
Thanks for your responses.
Here is code that works for an AutoCAD thumbnail bitmap:

Code: [Select]
        private Bitmap SetBlackBackground(Bitmap aBmp)
        {
            Bitmap bmp = aBmp;

            System.Drawing.Imaging.PixelFormat pxf = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, pxf);

            IntPtr ptr = bmpData.Scan0;
            int numBytes = (bmp.Width * bmp.Height) * 4;
            byte[] rgbValues = new byte[numBytes];
            int g = 0;
            int b = 0;
            Marshal.Copy(ptr, rgbValues, 0, numBytes);
            for (int counter = 0; counter < rgbValues.Length; counter += 4)
            {
                g = counter + 1;
                b = counter + 2;
                if ((rgbValues[counter] == 255) & (rgbValues[g] == 255) & (rgbValues[b] == 255))
                {
                    rgbValues[counter] = 0;
                    rgbValues[g] = 0;
                    rgbValues[b] = 0;
                }
                else
                {
                    if ((rgbValues[counter] == 0) & (rgbValues[g] == 0) & (rgbValues[b] == 0))
                    {
                        rgbValues[counter] = 255;
                        rgbValues[g] = 255;
                        rgbValues[b] = 255;
                    }
                }
            }
            Marshal.Copy(rgbValues, 0, ptr, numBytes);
            bmp.UnlockBits(bmpData);
            return bmp;
       }

I changed the pixelformat and the counter increment.
It is much MUCH faster than getpixel/setpixel.

This method is misnamed. It doesn't set the background to black but instead inverts black and white.
It will not work with all bitmap formats but it could be easily be adjusted to handle them.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8740
  • AKA Daniel
Re: Bitmap pixel color change
« Reply #5 on: May 15, 2007, 03:26:26 PM »
See if this will blow up your computer

Code: [Select]
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
//
namespace bitmapstauuf
{
  public class bmpstuff
  {
    //NOTE: UNSAFE WEAR PROTECTION
    public unsafe Bitmap SetBlackBackground(Bitmap obmp)
    {
      Bitmap abmp = new Bitmap(obmp);
      BitmapData bmpData = abmp.LockBits(new Rectangle(0, 0, abmp.Width, abmp.Height),
                            ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
      byte* ptr = (byte*)bmpData.Scan0;
      for (int i = 0; i < bmpData.Height; i++)
      {
        for (int j = 0; j < bmpData.Width; j++)
        {
          byte b = ptr[0];
          byte g = ptr[1];
          byte r = ptr[2];
          if (((b == 255) & (g == 255)) & (b == 255))
          {
            b = g = r = 0;
          }
          else if (((b == 0) & (g == 0)) & (r == 0))
          {
            b = g = r = 255;
          }
          ptr += 3;
        }
        ptr += bmpData.Stride - (bmpData.Width * 3);
      }
      abmp.UnlockBits(bmpData);
      return abmp;
    }
  }
}

edit: return a new bmp;
« Last Edit: May 15, 2007, 03:34:39 PM by Danielm103 »

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8740
  • AKA Daniel
Re: Bitmap pixel color change
« Reply #6 on: May 15, 2007, 10:07:49 PM »
Nope that didn't work :oops:

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8740
  • AKA Daniel
Re: Bitmap pixel color change
« Reply #7 on: May 15, 2007, 10:36:25 PM »
Fixed,
Code: [Select]
public unsafe Bitmap SetBlackBackground(Bitmap obmp)
    {
      Bitmap abmp = new Bitmap(obmp);
      BitmapData bmpData = abmp.LockBits(new Rectangle(0, 0, abmp.Width, abmp.Height),
                            ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
      byte* ptr = (byte*)bmpData.Scan0;
      for (int i = 0; i < bmpData.Height; i++)
      {
        for (int j = 0; j < bmpData.Width; j++)
        {
          byte b = ptr[0];
          byte g = ptr[1];
          byte r = ptr[2];
          if (b == 255 & g == 255 & r == 255)
          {
            ptr[0]= ptr[1]= ptr[2] = 0;
          }
          else if (b == 0 & g == 0 & r == 0)
          {
            ptr[0] = ptr[1] = ptr[2] = 255;
          }
          ptr += 4;
        }
      }
      abmp.UnlockBits(bmpData);
      return abmp;
    }


idea was from http://www.bytemycode.com/snippets/snippet/412/
« Last Edit: May 15, 2007, 10:45:13 PM by Danielm103 »