使用内存映射视图查看大型位图图像 [英] Viewing a large bitmap image using memory mapped view

查看:151
本文介绍了使用内存映射视图查看大型位图图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用C#应用程序查看一个非常大的位图。



这里的主要问题我无法将其直接加载到内存中,因此我尝试使用内存映射视图库来使用我得到了显示的颜色,即使它们与原始颜色略有不同,但它已被接受。

解决方案

我相信你没有得到Stride的权利。从你的颜色结构/类来看,你使用24Bpp ..



对于24Bpp,添加的填充将是宽度%4 所以在 RowSize getter更改

 返回4 *((Bpp * Width)/ 32); 

  return(Bpp / 8 * Width)+ Width%4; 

对于一般情况,您可以获得步幅的填充

 填充=宽度%(4 *(4  - (Bpp / 8)); 

根据定义,行的顺序是颠倒的(即自下而上),但是你自上而下创建它!所以在 CreateBM 更改

  for(int r = 0; r< bitm.Height; r ++)

  for(int r = bitm.Height  -  1; r> 0; r--)

至于颜色:先尝试修理这些东西,然后报告结果,好吗?


I've a very large bitmap that I'm trying to view using a C# application .

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 Reference One, Reference Two , Reference Three , Reference Four and Reference Five .

What I reached till now is the following:- 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.

Porblem:- The reconstructed bitmap image part loses the color information and is displayed up side down.

Example:- [Note I use low size image here and try to display part of it for testing purpose]

The Real Image:-

The output which should be (select first 200 row and reconstruct a smaller bitmap and display it):- As you can see the reconstructed image is colorless and upside down .

Now the code part:- class BMPMMF which is responsible for the whole process

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
    {
        /// <summary>
        /// It opens the image using memory mapped view and read the needed 
        /// parts, then call CreateBM to create a partially bitmap
        /// </summary>
        /// <param name="bmpFilename">Path to the physical bitmap</param>
        /// <returns></returns>
        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<ColorObject, int> rowColors = new Dictionary<ColorObject, int>();

            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 < 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 < rowSize; i += colorSize)
                    {

                        view.Read(i, out outObj);
                        cObj = new ColorObject(outObj);
                        rowColors[j][i / colorSize] = cObj;


                    }
                }
            }
            return CreateBM( rowColors );

        }
        /// <summary>
        /// Used to create a bitmap from provieded bytes 
        /// </summary>
        /// <param name="rowColors">Contains bytes of bitmap</param>
        /// <returns></returns>
        private Bitmap CreateBM(ColorObject[][] rowColors )
        {
            int width = rowColors[0].Count();
            int height = rowColors.Count();
            //int width = rowColors.Values.Where(o => 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 < bitm.Height; r++)
            {

                for (int c = 0; c < 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;
        }

        /// <summary>
        /// Returns a tuple that contains necessary information about bitmap header 
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        private Tuple<BmpHeader, DibHeader> 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);
            }
        }
    }
}

This is how to use it : -

   Bitmap bmpImage = bmp.readPartOfImage(filePath); // path to bitmap
   pictBoxBMP.Image = bmpImage; // set the picture box image to the new Partially created bitmap 

Solution I seek:- 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 .

Update#1 : After applying @TaW solution I got the colors displayed , even they are a little bit different from the original color but it's accepted .

解决方案

I believe you don't get the Stride right. Judging from your Color structure/class, you use 24Bpp..

For 24Bpp the padding to add would be Width % 4 so in the RowSize getter change

return 4 * ((Bpp * Width) / 32);

to

return (Bpp / 8 * Width) + Width % 4;

For the general case you can get the padding for the stride as

Padding = Width % (4 * (4 - (Bpp / 8) ); 

The order of the rows is upside down (i.e. bottom up) by definition but you create it top down! So in the CreateBM change

for (int r = 0; r < bitm.Height; r++)

to

for (int r = bitm.Height - 1 ; r > 0; r--)

As for the colors: Try fixing these things first, then report back with the results, ok?

这篇关于使用内存映射视图查看大型位图图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆