title: Viewing a large bitmap image using memory mapped view
body: <p>I've a very large bitmap that I'm trying to view using a C# application . </p>
  
  <p>The main issue here I can't load it directly into memory , thus I tried to use memory mapped view library to load it using guidance from <a href="https://msdn.microsoft.com/en-us/library/dd997372%28v=vs.110%29.aspx" rel="nofollow noreferrer">Reference One</a>, <a href="https://msdn.microsoft.com/en-us/library/dd988186(v=vs.110).aspx" rel="nofollow noreferrer">Reference Two</a> , <a href="http://visualstudiomagazine.com/articles/2010/06/23/memory-mapped-files.aspx?m=1" rel="nofollow noreferrer">Reference Three</a> , <a href="https://stackoverflow.com/questions/11065689/processing-on-large-bitmaps-up-to-3gb?lq=1">Reference Four</a> and <a href="https://stackoverflow.com/questions/569889/how-do-i-use-large-bitmaps-in-net">Reference Five</a> . </p>
  
  <p><strong>What I reached till now is the following:-</strong> 
  Reading the bitmap in parts as I need ( For example I read the first 200 row). 
  Create another bitmap from the rows I read and display it. </p>
  
  <p><strong>Porblem:-</strong> 
  The reconstructed bitmap image part loses the color information and is displayed up side down. </p>
  
  <p>Example:- [Note I use low size image here and try to display part of it for testing purpose] </p>
  
  <p><em>The Real Image:-</em> 
  <img src="https://i.stack.imgur.com/EDvbo.png" alt="enter image description here"></p>
  
  <p><em>The output which should be (select first 200 row and reconstruct a smaller bitmap and display it):-</em> 
  <img src="https://i.stack.imgur.com/cGz2c.png" alt="enter image description here">
  As you can see the reconstructed image is colorless and upside down . </p>
  
  <p><strong>Now the code part:-</strong> 
      <em>class BMPMMF which is responsible for the whole process</em></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO;
  using System.IO.MemoryMappedFiles;
  using System.Drawing;
  using System.Runtime.InteropServices;
  using System.Drawing.Imaging;
  
  namespace BMPViewer
  {
      class BMPMMF
      {
          /// &lt;summary&gt;
          /// It opens the image using memory mapped view and read the needed 
          /// parts, then call CreateBM to create a partially bitmap
          /// &lt;/summary&gt;
          /// &lt;param name="bmpFilename"&gt;Path to the physical bitmap&lt;/param&gt;
          /// &lt;returns&gt;&lt;/returns&gt;
          public Bitmap readPartOfImage(string bmpFilename)
          {
              var headers = ReadHeaders(bmpFilename);
              var mmf = MemoryMappedFile.CreateFromFile(bmpFilename, FileMode.Open);
              int rowSize = headers.Item2.RowSize;    // number of byes in a row
  
             // Dictionary&lt;ColorObject, int&gt; rowColors = new Dictionary&lt;ColorObject, int&gt;();
  
              int colorSize = Marshal.SizeOf(typeof(MyColor));
              int width = rowSize / colorSize;//(headers.Item1.DataOffset+ rowSize) / colorSize;
              int height = 200;
              ColorObject cObj;
              MyColor outObj;
              ColorObject[][] rowColors = new ColorObject[height][];
              // Read the view image and save row by row pixel
              for (int j = 0; j &lt; height; j++)
              {
                  rowColors[j] = new ColorObject[width];
                  using (var view = mmf.CreateViewAccessor(headers.Item1.DataOffset + rowSize * j, rowSize, MemoryMappedFileAccess.Read))
                  {
                      for (long i = 0; i &lt; rowSize; i += colorSize)
                      {
  
                          view.Read(i, out outObj);
                          cObj = new ColorObject(outObj);
                          rowColors[j][i / colorSize] = cObj;
  
  
                      }
                  }
              }
              return CreateBM( rowColors );
  
          }
          /// &lt;summary&gt;
          /// Used to create a bitmap from provieded bytes 
          /// &lt;/summary&gt;
          /// &lt;param name="rowColors"&gt;Contains bytes of bitmap&lt;/param&gt;
          /// &lt;returns&gt;&lt;/returns&gt;
          private Bitmap CreateBM(ColorObject[][] rowColors )
          {
              int width = rowColors[0].Count();
              int height = rowColors.Count();
              //int width = rowColors.Values.Where(o =&gt; o == 0).Count();
              Bitmap bitm = new Bitmap(width, height, PixelFormat.Format24bppRgb);
              // new Bitmap(imgdat.GetUpperBound(1) + 1, imgdat.GetUpperBound(0) + 1, PixelFormat.Format24bppRgb);
              BitmapData bitmapdat = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), ImageLockMode.ReadWrite, bitm.PixelFormat);
              int stride = bitmapdat.Stride;
              byte[] bytes = new byte[stride * bitm.Height];
  
              for (int r = 0; r &lt; bitm.Height; r++)
              {
  
                  for (int c = 0; c &lt; bitm.Width; c++)
                  {
                      ColorObject color = rowColors[r][c];
                      bytes[(r * stride) + c * 3] = color.Blue;
                      bytes[(r * stride) + c * 3 + 1] = color.Green;
                      bytes[(r * stride) + c * 3 + 2] = color.Red;
  
                  }
              }
  
  
              System.IntPtr scan0 = bitmapdat.Scan0;
              Marshal.Copy(bytes, 0, scan0, stride * bitm.Height);
              bitm.UnlockBits(bitmapdat);
  
              return bitm;
          }
  
          /// &lt;summary&gt;
          /// Returns a tuple that contains necessary information about bitmap header 
          /// &lt;/summary&gt;
          /// &lt;param name="filename"&gt;&lt;/param&gt;
          /// &lt;returns&gt;&lt;/returns&gt;
          private Tuple&lt;BmpHeader, DibHeader&gt; ReadHeaders(string filename)
          {
              var bmpHeader = new BmpHeader();
              var dibHeader = new DibHeader();
              using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
              {
                  using (var br = new BinaryReader(fs))
                  {
                      bmpHeader.MagicNumber = br.ReadInt16();
                      bmpHeader.Filesize = br.ReadInt32();
                      bmpHeader.Reserved1 = br.ReadInt16();
                      bmpHeader.Reserved2 = br.ReadInt16();
                      bmpHeader.DataOffset = br.ReadInt32();
  
                      dibHeader.HeaderSize = br.ReadInt32();
                      if (dibHeader.HeaderSize != 40)
                      {
                          throw new ApplicationException("Only Windows V3 format supported.");
                      }
                      dibHeader.Width = br.ReadInt32();
                      dibHeader.Height = br.ReadInt32();
                      dibHeader.ColorPlanes = br.ReadInt16();
                      dibHeader.Bpp = br.ReadInt16();
                      dibHeader.CompressionMethod = br.ReadInt32();
                      dibHeader.ImageDataSize = br.ReadInt32();
                      dibHeader.HorizontalResolution = br.ReadInt32();
                      dibHeader.VerticalResolution = br.ReadInt32();
                      dibHeader.NumberOfColors = br.ReadInt32();
                      dibHeader.NumberImportantColors = br.ReadInt32();
                  }
              }
  
              return Tuple.Create(bmpHeader, dibHeader);
          }
      }
  
      public struct MyColor
      {
          public byte Red;
          public byte Green;
          public byte Blue;
          //public byte Alpha;
      }
      public class ColorObject
      {
          public ColorObject(MyColor c)
          {
              this.Red = c.Red;
              this.Green = c.Green;
              this.Blue = c.Blue;
             // this.Alpha = c.Alpha;
          }
          public byte Red;
          public byte Green;
          public byte Blue;
         // public byte Alpha;
      }
  
      public class BmpHeader
      {
          public short MagicNumber { get; set; }
          public int Filesize { get; set; }
          public short Reserved1 { get; set; }
          public short Reserved2 { get; set; }
          public int DataOffset { get; set; }
      }
  
      public class DibHeader
      {
          public int HeaderSize { get; set; }
          public int Width { get; set; }
          public int Height { get; set; }
          public short ColorPlanes { get; set; }
          public short Bpp { get; set; }
          public int CompressionMethod { get; set; }
          public int ImageDataSize { get; set; }
          public int HorizontalResolution { get; set; }
          public int VerticalResolution { get; set; }
          public int NumberOfColors { get; set; }
          public int NumberImportantColors { get; set; }
          public int RowSize
          {
              get
              {
                  return 4 * ((Bpp * Width) / 32);
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>This is how to use it : -</strong></p>
  
  <pre><code>   Bitmap bmpImage = bmp.readPartOfImage(filePath); // path to bitmap
     pictBoxBMP.Image = bmpImage; // set the picture box image to the new Partially created bitmap 
  </code></pre>
  
  <p><strong>Solution I seek:-</strong> 
  Just display the partial created bitmap correctly , my guess that there's a problem in bitmap reconstruction or in bitmap reading using memory mapped view .</p>
  
  <p><strong>Update#1</strong> : After applying <a href="https://stackoverflow.com/questions/28310592/viewing-a-large-bitmap-image-using-memory-mapped-view/28314519#28314519">@TaW solution</a> I got the colors displayed , even they are a little bit different from the original color but it's accepted . 
  <img src="https://i.stack.imgur.com/iZh2h.png" alt="enter image description here"></p>