anonymous anonymous - 4 months ago 31
C# Question

Bitmap to int[,] conversion and vice versa

Consider the following two routines.

//Tested
///Working fine.
public static Bitmap ToBitmap(int [,] image)
{
int Width = image.GetLength(0);
int Height = image.GetLength(1);
int i, j;
Bitmap bitmap = new Bitmap(Width, Height);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* address = (byte*)bitmapData.Scan0;

for (i = 0; i < bitmapData.Height; i++)
{
for (j = 0; j < bitmapData.Width; j++)
{
// write the logic implementation here
address[0] = (byte)image[j, i];
address[1] = (byte)image[j, i];
address[2] = (byte)image[j, i];
address[3] = (byte)255;
//4 bytes per pixel
address += 4;
}//end for j

//4 bytes per pixel
address += (bitmapData.Stride - (bitmapData.Width * 4));
}//end for i
}//end unsafe
bitmap.UnlockBits(bitmapData);
return bitmap;// col;
}

//Tested
///Working fine.
public static int[,] ToInteger(Bitmap bitmap)
{
int[,] array2D = new int[bitmap.Width, bitmap.Height];

BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppRgb);

unsafe
{
byte* address = (byte*)bitmapData.Scan0;

int paddingOffset = bitmapData.Stride - (bitmap.Width * 4);//4 bytes per pixel

for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
byte[] temp = new byte[4];
temp[0] = address[0];
temp[1] = address[1];
temp[2] = address[2];
temp[3] = address[3];

array2D[j, i] = BitConverter.ToInt32(temp, 0);

//4-bytes per pixel
address += 4;//4-channels
}
address += paddingOffset;
}
}
bitmap.UnlockBits(bitmapData);

return array2D;
}


These two routines work fine for 32bpp images. These routines only work when pixel format is set to
PixelFormat.Format32bpp
. If I use
PixelFormat.Format8bppIndexed
, it generates an exception.

In order to avoid that exception (also, I couldn't achieve seamless conversion between
byte
and
int
because of address calculation problem), I need to convert that 32 bit
Bitmap
to gray-scale every time the
int[,]
is converted back to a
Bitmap
. I want to get rid of this problem.

Bitmap grayscale = Grayscale.ToGrayscale(InputImage);

//Here, the Bitmap is treated as a 32bit image
//to avoid the exception eventhough it is already
//an 8bpp grayscale image.
int[,] i1 = ImageDataConverter.ToInteger(grayscale);

Complex[,] comp = ImageDataConverter.ToComplex(i1);

int[,] i2 = ImageDataConverter.ToInteger(comp);

Bitmap b2 = ImageDataConverter.ToBitmap(i2);

//It is already a Grayscale image.
//But, the problem is, b2.PixelFormat is set to
//PixelFormat.Formap32bpp because of those routines.
//Hence the unnecessay conversion.
b2 = Grayscale.ToGrayscale(b2);


I need to modify them to operate on 8bpp indexed (grayscale) images only.

How can I achieve that?

Answer
public static int[,] ToInteger(Bitmap bitmap)
{
    int[,] array2D = new int[bitmap.Width, bitmap.Height];

    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                            ImageLockMode.ReadWrite,
                                            PixelFormat.Format8bppIndexed);
    int bytesPerPixel = sizeof(byte);

    unsafe
    {
        byte* address = (byte*)bitmapData.Scan0;

        int paddingOffset = bitmapData.Stride - (bitmap.Width * bytesPerPixel);

        for (int i = 0; i < bitmap.Width; i++)
        {
            for (int j = 0; j < bitmap.Height; j++)
            {
                byte[] temp = new byte[bytesPerPixel];

                for (int k = 0; k < bytesPerPixel; k++)
                {
                    temp[k] = address[k];
                }

                int iii = 0;

                if (bytesPerPixel >= sizeof(int))
                {
                    iii = BitConverter.ToInt32(temp, 0);
                }
                else
                {
                    iii = (int)temp[0];
                }

                array2D[j, i] = iii;

                address += bytesPerPixel;
            }
            address += paddingOffset;
        }
    }
    bitmap.UnlockBits(bitmapData);

    return array2D;
}

public static Bitmap ToBitmap(int[,] image)
{
    int Width = image.GetLength(0);
    int Height = image.GetLength(1);
    int i, j;

    Bitmap bitmap = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);

    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height),
                             ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

    int bytesPerPixel = sizeof(byte);

    unsafe
    {
        byte* address = (byte*)bitmapData.Scan0;

        for (i = 0; i < bitmapData.Height; i++)
        {
            for (j = 0; j < bitmapData.Width; j++)
            {
                byte[] bytes = BitConverter.GetBytes(image[j, i]);

                for (int k = 0; k < bytesPerPixel; k++)
                {
                    address[k] = bytes[k];
                }

                address += bytesPerPixel;
            }

            address += (bitmapData.Stride - (bitmapData.Width * bytesPerPixel));
        }
    }
    bitmap.UnlockBits(bitmapData);

    Grayscale.SetGrayscalePalette(bitmap);

    return bitmap;
}