1

I am currently working on a project that requires having an image over than 80,000 pixels in size. I know Bitmap in C# allows only 65,635 widths at maximum.

I thought of using byte array that contains greyscale color from 0 to 255, but I have no clue how to do that. (Of course, image are in a greyscale colors.)

How could I generate that kind of file/image and saved it on my machine for future use?

  • this might be similar to [this question](http://stackoverflow.com/questions/11065689/processing-on-large-bitmaps-up-to-3gb). – andreim May 12 '17 at 16:39

1 Answers1

3

My solution is to save images into a byte array data, which has a size of 2 147 483 648 (depending if you are using 32bpp image or 8bpp, it could vary from 2 147 483 648 pixel for one single image of 8bpp to 536 870 912 pixel for 32bpp. You also might have to allow gcAllowVeryLargeObjects to true to enable data of that size. Once done, when you want to display your image into your own viewer/winforms/or anything like, you have to instanciate a bitmap array that contains multiple bitmap that constructs your final image. I recommand having 32 768 pixel large images because Graphics.DrawImage only allows you to draw a maximum of 32 768pixel.

To create your bitmap with the byte array you've just saved, you have to create an empty bitmap with wanted size, and use LockBits and UnlockBits to set the byteArray Data directly into your bitmap. You can use something like this, that'll do the job :

BitmapData bmpData = m_ImageArray[range.Item1].LockBits(new Rectangle(0, 0, m_ImageArray[range.Item1].Width, m_ImageArray[range.Item1].Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
              IntPtr scan = bmpData.Scan0;

              for (int i = 0; i < m_ImageArray[range.Item1].Height; i++)
              {
                 System.Runtime.InteropServices.Marshal.Copy(RawBitmapImage.Data, i * ImageWidth + range.Item1 * firstBitmapWidth, scan, m_ImageArray[range.Item1].Width);
                 scan += bmpData.Stride;
              }

              m_ImageArray[range.Item1].UnlockBits(bmpData);

What the code above does is to lockBits of each bitmaps of the array 1 by 1, copy the appropriate chunk of data from the byteArray (RawBitmapImage.Data) and copy them into the scan which is a pointer to your bitmap data using Marshal.Copy (extremely fast, I tried with image doing 200 000pixel * 5000pixel and takes about 200ms to load).

Once you've created all your bitmap, just make multiple draw calls to your graphicsContext.DrawImage and drawthem one by one specifying the appropriate source and destination to the screen.

If you need any help doing this, or any questions, feel free to comment !

  • 3
    Just a FYI, arrays are not unlimited size either, they are only accessible by using a signed integer that starts at 0, so at most it could hold 2147483648 elements. (You also would need to set [gcAllowVeryLargeObjects](https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element) to be true) – Scott Chamberlain Jul 12 '17 at 18:17
  • 2
    Thanks ! Edited my answer ! I hope this could be useful to someone else in the future. –  Jul 12 '17 at 19:52