Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi, I'm currently making a program that opens a bitmap for viewing from a non-standard format. I have succeeded in getting the bitmap data and have opened it into a Bitmap object. Now I want to be able to select one (or a mix of ARGB) of the colour channels to display.

 

I have achieved this by cycling through all of the pixels using for statements and changing the pixels ARGB colour values one by one. But as was expected this takes alot of time with larger images.

 

Is there a quicker (much quicker) way of doing this?

  • Leaders
Posted

There is, but it isn't nearly as simple to write as it would be using GetPixel/SetPixel. You'll need to understand image manipulation (I'm sure you do) and binary math.

 

Simply put, you would create an array, use the Marshal class (not sure which namespace) to copy the raw pixel data to the array, modify the raw pixel data, and finally copy it back to the bitmap.

 

 

First create an array (Int32s and UInt32s are ideal, especially with 32-bit ARGB images) with the appropriate size to hold pixel data. For a 32-bit bitmap, the size of the array would simply be the width of the image multiplied by the height of the image.

 

Next you would lock the bitmap. The object returned by the Lock function contains a pointer to the raw pixel data (named Scan0). Call Marshal.Copy to copy the data from Scan0 to your array. For the length argument, pass the length of the array.

 

Now you can modify the raw pixel data. For example, to view only blue data (exclude red, green, and alpha), use could use code akin to the following:

// storing raw image data in img[]
// IM NOT SURE ABOUT THE BYTE ORDER
int fullAlpha = 0xFF << 24; 
int blueMask = 0xFF; 
for(int i = 0; i < img.Length; i++) {
   img[i] = img[i] & blueMake // Extract blue data
       | fillAlpha; // and make it fully opaque.
}

 

Lastly, you would use Marshal.Copy to copy the image data back to the bitmap and unlock the bitmap.

 

 

 

Some people might tell you to forget the whole Array/Marshal.Copy thing and use pointers, but that requires unsafe code (more permissions), can only be done in C#, and in my experience, actually seems to be slower than using the Marshal class.

 

If you run into any problems coding, I'll be glad to give you a hand

[sIGPIC]e[/sIGPIC]
Posted

Working channel viewing

 

Thankyou very much for your help ;) . After doing a bit of research (and trial and error) I managed to get it working, and its much faster than my previous method.

 

Heres the code (with minor alterations) that i'm now using, incase anybody else is interested or if improvements can be made:

 

(This is C# code.)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

Bitmap BitmImage;
private void ChangeChannel(bool A,bool R,bool G,bool B)
{
   //The bitmap is re-loaded on each run to replace channels that have 
   //already been removed
   BitmImage = new Bitmap("c:\\Bitmap.bmp") //Your bitmap object/file goes here.

   //Lock the bitmap into unmanaged memory.
   BitmapData BD = BitmImage.LockBits(new Rectangle(new Point(0, 0),   
       BitmImage.Size), ImageLockMode.ReadWrite,
       PixelFormat.Format32bppArgb);
      
   //Set up the array that will accomodate the raw bitmap data.
   Int32[] RawImgData = new Int32[bitmImage.Width * BitmImage.Height];

   //Copy the locked bitmap data into the previously made array from the Scan0 pointer
   //in the BitmapData object.
   Marshal.Copy(BD.Scan0, RawImgData, 0, RawImgData.Length);

   Int32 AlphaMask = 0;
   Int32 RedMask = 0;
   Int32 GreenMask = 0;
   Int32 BlueMask = 0;

   //If the alpha boolean (A) it set to true, ignore the Red,Green and Blue channels.
   //The values are byte-shifted to match the 32 bit ARGB Format.
   AlphaMask = 0xFF << 24;
   if (!A && R) { RedMask = 0xFF << 16; } else { RedMask = 0x00 << 16; }
   if (!A && G) { GreenMask = 0xFF << 8; } else { GreenMask = 0x00 << 8; }
   if (!A && B) { BlueMask = 0xFF << 0; } else { BlueMask = 0x00 << 0; }

   //Cycle through the raw data, altering the image to remove unwanted channels.
   for (int i = 0; i < RawImgData.Length; i++)
   {
       Int32 tmp = 0;
       if (A)
       {
           //Make "tmp" equal the Alpha value for this pixel.
           tmp = RawImgData[i] & AlphaMask;

           //Replace the alpha value with FF to make the image fully opaque.
           RawImgData[i] = 0xFF << 24; 

           //Byte-shift the alpha value and replace the colour channels to make 
           //a white alpha representation.
           RawImgData[i] += tmp >> 8;  
           RawImgData[i] += tmp >> 16;
           RawImgData[i] += tmp >> 24;
       }
       else
       {
       // Perform a logical AND operation on the pixel data to remove unwanted data.
       tmp += RawImgData[i] & RedMask;
       tmp += RawImgData[i] & GreenMask;
       tmp += RawImgData[i] & BlueMask;
       RawImgData[i] = tmp | AlphaMask;
       }
   }
       
   //Copy the edited bitmap data back to the unmanaged memory location, Scan0.
   Marshal.Copy(RawImgData, 0, BD.Scan0, RawImgData.Length);
   BitmImage.UnlockBits(BD); //Unlock the bitmap object and use the edited bitmap.
   ViewBox.Size = BitmImage.Size;
   ViewBox.Image = BitmImage;
}

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...