0

in a university project my team and I have to build a scanning unit. After processing the scanning unit returns a Byte Array consisting of 8-bit grayscale values (approx 3,7k Pixels in the Heigth and 20k Pixels in the Width, this huge resolution is necessary, so setting PixelData Pixelwise is no option as this would take to much time).

While searching the internet i have found an answer in This SO topic. I tried it implementing as the following:

public static class Extensions
{
    public static Image ImageFromArray(
    this byte[] arr, int width, int height)
    {
        var output = new Bitmap(width, height, PixelFormat.Format16bppGrayScale);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect,
            ImageLockMode.ReadWrite, output.PixelFormat);
        var ptr = bmpData.Scan0;
        Marshal.Copy(arr, 0, ptr, arr.Length);
        output.UnlockBits(bmpData);
        return output;
    }
}

I tried running the Function with an array filled like this:

        testarray[0] = 200;
        testarray[1] = 255;
        testarray[2] = 90;
        testarray[3] = 255;
        testarray[4] = 0;
        testarray[5] = 0;
        testarray[6] = 100;
        testarray[7] = 155;

And wanted to show the bmp in a picturebox with:

pictureBox1.Image = Extensions.ImageFromArray(testarray, 2, 2);

When debugging, the code runs trough the function, but the result is the Errorimage showing.

Also, if someone knows an easier method to compute the task, it would be very nice to share the way. I could not find a way to

  1. Use a 8-bit-grayscale Pixelformat in C#
  2. Create a BitMap Object including a Stream AND the PixelFormat

Thank you very much for your help :)

Blitzeloh
  • 13
  • 1
  • 5
  • ErrororImage?? I doubt you can display or create a 200k x 37k sized Bitmap directly. You would have to look into libraries or [look here](http://stackoverflow.com/questions/29175585/what-is-the-maximum-resolution-of-c-sharp-net-bitmap)- Also I don't think `Format16bppGrayScale` is supported. – TaW May 01 '16 at 11:58
  • 1
    You're going to have a hard time finding a FORMAT that supports something that large, let alone a library. That's above 4GB of image data. You need one of the heavy duty formats used for scientific stuff. Perhaps the assignment can be clarified, since the choice of output format should be in the specs, since consuming it wouldn't be straightforward either. PNG can do it too, I think, if you can figure out how to write PNG tags yourself and then start writing the data line by line. I'd be looking at the PNG specs and practice writing small pngs, myself. – zeromus May 01 '16 at 12:39
  • 1
    Since all your preconceptions about what's feasible are wildly wrong, maybe you should write about what youre really trying to do for some more general advice. As far as displaying the BMP in a picturebox: give up. Displaying something that large is a different task entirely. You need a mapping program that can stream chunks from the disk. – zeromus May 01 '16 at 12:40
  • I asked my team members about the resolution again, it was 3,7k x 20k. Was my fault there. @TaW the default white background red cross image (im totally new to c#, so sorry if i cant explain that better) – Blitzeloh May 01 '16 at 13:50
  • @zeromus does the picturebox not automatically scale an image down to the size of the picture box? – Blitzeloh May 01 '16 at 13:53
  • Ah, ok, that sounds better. However `Format16bppGrayScale` unfortunately is not supported. Yes it is in the enumeration but still not supported in GDI+. Hence probably the error-image. So, yes you would have to go for a different pixelformat. – TaW May 01 '16 at 13:56
  • @TaW So it will end in writing an algorithm that transforms my byte array into a byte array which includes all the information needed to let c# know how to properly create the image out of it? Do you have any idea which format would be the best then / where to look up how to these structures look? – Blitzeloh May 01 '16 at 14:12
  • Use Format8bppIndexed and set the obvious palette – zeromus May 01 '16 at 14:13
  • If you can live with the loss ofinformation, yes. If you can't either investigate how you would use the results; normal monitors won't do it. For some application using a RGB mapping with false colors could help; for others it is no option. - The conversion int[] -> byte[] should be fast enough, as long as you are not using the bitmap yet. – TaW May 01 '16 at 14:46

1 Answers1

1
  1. Use Format8bppIndexed and set the obvious palette

    Bitmap ImageFromArray(byte[] arr, int width, int height)
    {
        var output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
        var rect = new Rectangle(0, 0, width, height);
        var bmpData = output.LockBits(rect,ImageLockMode.WriteOnly, output.PixelFormat);
        var ptr = bmpData.Scan0;
        if (bmpData.Stride != width)
            throw new InvalidOperationException("Cant copy directly if stride mismatches width, must copy line by line");
        Marshal.Copy(arr, 0, ptr, width*height);
        output.UnlockBits(bmpData);
        var palEntries = new Color[256];
        var cp = output.Palette;
        for (int i = 0; i < 256; i++)
            cp.Entries[i] = Color.FromArgb(i, i, i);
        output.Palette = cp;            
        return output;
    }
    
  2. Set PictureBox.SizeMode to StretchImage. You'll probably need that.

zeromus
  • 1,648
  • 13
  • 14
  • Thank you for your answer, im getting a result with this procedure at least. Anyway, the result is not what i was expecting. I set a 16 byte Array as the parameter, the first 8 slots '255' the last 8 slots '0', widht and height a value of '4', expecting a cube with one half colored white, the other half colored black. The result is this: https://imgur.com/Nox5V9h . I have no clue why. – Blitzeloh May 01 '16 at 17:31
  • http://stackoverflow.com/questions/29157/how-do-i-make-a-picturebox-use-nearest-neighbor-resampling http://stackoverflow.com/questions/20776605/missing-half-of-first-pixel-column-after-a-graphics-transform-scale Picturebox sucks. Youll never get perfect results. You wont need perfect results when displaying those giant images. You may not like whatever results you get in any case. Youll have to do the rendering yourself with System.Drawing.Graphics, and you may STILL not like the results. All these systems are inadequate for anything but lazily displaying photographs. – zeromus May 01 '16 at 23:24
  • Ah i see, i saved the image to disk and the result was just fine. Thank you very much :) – Blitzeloh May 02 '16 at 10:05
  • That is one weird exception you got there... "Cant copy directly if stride mismatches width, must copy line by line" - so, um... [why don't you, then](https://stackoverflow.com/a/43967594/395685), instead of throwing that exception? As for the pictureBox zoom issue, it's answered [here](https://stackoverflow.com/a/13484101/395685). – Nyerguds Mar 20 '18 at 09:38