title: How do you convert a byte array to a Bitmap instance (.NET)?
body: <p>I am working with cameras (in this case monochrome) in VB.NET. The API of the cameras is in C++ and the manufacturer provides wrappers. As is typical in these cases, the image is returned as a <code>Byte</code> array. In my particular case it's 8 bits per pixel so there's no fancy bitpacking to undo.</p>
  
  <p>I was <strong>flabbergasted</strong> that .NET has so little support for this type of thing. Searching online I found various topics, but it doesn't help that in many cases people have a byte array corresponding to image data (that is, read an image file into a byte array and then have .NET interpret the array as a file, with header and everything).</p>
  
  <p>In this case I need to convert an array of raw pixel values into, particularly, something I can display on-screen.</p>
  
  <p>There doesn't seem to be any built-in way to do this, because the 8bpp format built into .NET is indexed (needs a palette) but it doesn't seem that setting the palette is supported. Again, this really surprised me. <a href="https://stackoverflow.com/questions/2517477/converting-24bpp-to-4bpp-with-gdi-in-vb-net">This</a> is the most promising topic I found.</p>
  
  <p>So the only way I found to do this is to create a <code>Bitmap</code> and then copy the pixel values pixel by pixel. In my case an 8 MPixel image took <em>several seconds</em> on the fastest i7 when using <code>SetPixel</code>.</p>
  
  <p>The alternative I found to using <code>SetPixel</code> is <code>LockBits</code>, which then gives you access to the (unmanaged) array of bytes that constitutes the image. It seems wasteful, because I have to manipulate the array in .NET and then copy it back to unmananaged space. I'm already copying the original image data once (so the original can be reused or discarded by the rest of what's going on) so although significantly faster than using <code>SetPixel</code> this still seems wasteful.</p>
  
  <p>Here is the VB code I have:</p>
  
  <pre class="lang-vb prettyprint-override"><code>Public Function GetBitmap(ByRef TheBitmap As System.Drawing.Bitmap) As Integer
      Dim ImageData() As Byte
      Dim TheWidth, TheHeight As Integer
      'I've omitted the code here (too specific for this question) which allocates
      'ImageData and then uses Array.Copy to store a copy of the pixel values
      'in it. It also assigns the proper values to TheWidth and TheHeight.
  
      TheBitmap = New System.Drawing.Bitmap(TheWidth, TheHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
      Dim TheData As System.Drawing.Imaging.BitmapData = TheBitmap.LockBits(
          New System.Drawing.Rectangle(0, 0, TheWidth, TheHeight), Drawing.Imaging.ImageLockMode.ReadWrite, TheBitmap.PixelFormat)
      Dim Image24(Math.Abs(TheData.Stride) * TheHeight) As Byte
      'Then we have two choices: to do it in parallel or not. I tried both; the sequential version is commented out below.
      System.Threading.Tasks.Parallel.For(0, ImageData.Length, Sub(i)
                                                                   Image24(i * 3 + 0) = ImageData(i)
                                                                   Image24(i * 3 + 1) = ImageData(i)
                                                                   Image24(i * 3 + 2) = ImageData(i)
                                                               End Sub)
      'Dim i As Integer
      'For i = 0 To ImageData.Length - 1
      '    Image24(i * 3 + 0) = ImageData(i)
      '    Image24(i * 3 + 1) = ImageData(i)
      '    Image24(i * 3 + 2) = ImageData(i)
      'Next
      System.Runtime.InteropServices.Marshal.Copy(Image24, 0, TheData.Scan0, Image24.Length)
      TheBitmap.UnlockBits(TheData)
  
      'The above based on
      'http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx
  
      Return 1
  
  End Function
  </code></pre>
  
  <p>For an 8 MPixel image the sequential version consumes about 220 milliseconds from creating <code>TheBitmap</code> up to (and including) the call to <code>TheBitmap.UnlockBits()</code>. The parallel version is much more inconsistent but ranges between 60 and 80 milliseconds. Considering I'm acquiring from four cameras simultaneously and streaming to disk with plenty of time to spare, this is pretty disappointing. The API comes with sample code in C++ which can display from all four cameras simultaneously at full frame rate (17 fps). It never deals with <code>Bitmap</code>, of course, since GDI accesses arrays of raw pixel values.</p>
  
  <p>In summary, I have to travel across the managed/unmanaged barrier simply because there is no direct way to take an array of pixel values and "stuff" it into a <code>Bitmap</code> instance. In this case I'm also copying the pixel values into an 24bpp <code>Bitmap</code> because I cannot "set" the palette in an indexed image so 8bpp is not a viable format for display.</p>
  
  <p>Is there no better way?</p>