Writing a 16-bit grayscale image

I have a byte array containing pixel values for a 16bpp grayscale image. I need a solution for converting said array to a bitmap image. So far I've come up with this:

internal static Image imageFromArray(byte[] array)

{

const int WIDTH = 1472;

int height = (array.Length) / WIDTH / 2;

Bitmap bitmap = new Bitmap(1472, height, PixelFormat.Format16bppGrayScale);

for (int x = 0; x < height; x++)

for (int y = 0; y < WIDTH; y++)

bitmap.SetPixel(x, y, (Color)array[(y * 1472 + x) * 2]); Image image = bitmap;

return image;

}

But there is an error because I can't cast the byte as a color. So my question is, how do I actually translate my pixel data from the byte[] to the bitmap Is there a better way to do this using an unsafe code block

Thanks for your help. If its relevant, the image files I am using are about 16MB. They contain raw data, some number of rows by 1472 columns of unsigned 16-bit words. They are all 1472 pixels wide.



Answer this question

Writing a 16-bit grayscale image

  • ReneeC

    Hi,

    here is an example of how you would use the LockBits method to set bitmap image data:

    using System;
    using System.Drawing;
    using System.Drawing.Imaging;

    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    //Create pixel data to put in image, use 2 since it is 16bpp
    Random r = new Random();
    int width = 800;
    int height = 600;
    byte[] pixelValues = new byte[width * height * 2];
    for (int i = 0; i < pixelValues.Length; ++i)
    {
    //Just create random pixel values, don't care about
    //being greyscale values for example
    pixelValuesIdea = (byte)r.Next(0, 256);
    }

    CreateBitmapFromBytes(pixelValues, width, height);
    }

    private static void CreateBitmapFromBytes(byte[] pixelValues, int width, int height)
    {
    //Create an image that will hold the image data
    Bitmap pic = new Bitmap(width, height, PixelFormat.Format16bppGrayScale);

    //Get a reference to the images pixel data
    Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
    BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat);
    IntPtr pixelStartAddress = picData.Scan0;

    //Copy the pixel data into the bitmap structure
    System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, pixelStartAddress, pixelValues.Length);

    pic.UnlockBits(picData);
    pic.Save(@"c:\users\mark\mypic1.bmp", ImageFormat.Bmp);
    }
    }
    }

    Mark.



  • S_A_S

    Here is my code:

    internal static Image imageFromArray(byte[] array)

    {

    int width = 1472;

    int height = array.Length / width / 2;

    Bitmap b = new Bitmap(width, height, PixelFormat.Format16bppGrayScale);

    BitmapData bmData = b.LockBits(new Rectangle(0, 0, width, height),

    ImageLockMode.ReadWrite, PixelFormat.Format16bppGrayScale);

    int stride = bmData.Stride;

    System.IntPtr scan0 = bmData.Scan0;

    Marshal.Copy(array, 0, scan0, array.Length);

    b.UnlockBits(bmData);

    //Rote the image 90 degrees

    b.RotateFlip(RotateFlipType.Rotate90FlipX);

    Image image = b;

    return image;

    }

    The exception is an argument exception. Debugger points to Application.Run actually, and System.Drawing is throwing it. It seems 16bpp grayscale isn't supported even though it pops up as an option in Intellisence, unless I'm doing something wrong. Also all my image widths are 1472, and array is a byte[] containing pixel values (every 2 bytes represents 1 pixel).

    Losing precision is not an option, I need 16bpp grayscale.


  • DD_Helmetman

    If you put a breakpoint in your imageFromArray method does it step through all of the code successfully If you do a b.Save to save the image to disk does that work and show the image you are expecting

    Mark.



  • yasmina

    Specifically the exception is thrown at

    BitmapData bmData = b.LockBits(new Rectangle(0, 0, width, height),

    ImageLockMode.ReadWrite, PixelFormat.Format16bppGrayScale);

    PixelFormat.Format16bppGrayScale is not a valid bitmap format.


  • Sripall

    Hi,

      I could run this code and create a bitmap without any issues.  What exception are you getting   Is your byte array just pixel data or also image headers as well

     

    Mark.



  • GavH

    Hi InfiniZac,

    I am experiencing exactly the same problem; Format16bppGrayScale does not work but other formats do. Did you ever find a solution I'm dealing with 16 bit grayscale images as well!!

    Many thanks,
    123SB

  • ursus zeta

    Hi,

    your code will probably be very slow due to calling SetPixel which has terrible performance. You can do what you want to do by using the LockBits method, the following has an example which should show you how to proceed: http://msdn2.microsoft.com/en-us/library/5ey6h79d.aspx

    Mark.



  • Fulankazu

    I read your link but I am not sure how to translate that to what I want to do.

    I have an array of bytes. Every 2 bytes represents a grayscale value for a pixel in my image (16bpp). I want to create a bitmap from these pixel values.


  • Jeroen Hauser

    This post was very helpful; however, the code will not work.

    I've researched and discovered that the PixelFormat Format16bppGrayScale is not supported. Every time I try to run this code, my program crashes.

    :-(

    Converting to 8-bit is not an option. I need all 65+K shades of gray.


  • Johnathan Seal

    If I change the pixel format to almost anything other than Format16bppGrayScale, I can get the image to load. For instance Format16bppRgb555 works - but I don't have an RGB image, it has never been and never will be a color image. I get a really low-contrast high-noise image that vaguely resembles the image I'm supposed to have.

    I need a way to display 16-bit grayscale images in my form. Should I not use System.Drawing.Bitmap


  • Edward Smeathers

    Hi,

    what about if you use something like 48 bits per pixel RGB image, that way you will not lose any of your grayscale information when it is in the R, G or B component, then you will have to copy the data into each channel to make it gray and you should see you original picture, granted it will be lot larger in memory, but will still be presented correctly.



  • Writing a 16-bit grayscale image