我正在尝试编写一个轻量级图像查看应用程序.但是,.NET存在系统内存限制.
当尝试加载大位图(9000 x 9000 px或更大,24位)时,我得到一个System.OutOfMemoryException.这是在具有2GB RAM(其中1.3GB用完)的Windows 2000 PC上.尝试加载文件也需要很长时间.
以下代码生成此错误:
Image image = new Bitmap(filename); using (Graphics gfx = this.CreateGraphics()) { gfx.DrawImage(image, new Point(0, 0)); }
这段代码也是如此:
Stream stream = (Stream)File.OpenRead(filename); Image image = Image.FromStream(stream, false, false); using (Graphics gfx = this.CreateGraphics()) { gfx.DrawImage(image, new Rectangle(0, 0, 100, 100), 4000, 4000, 100, 100, GraphicsUnit.Pixel); }
此外,它就足以做到这一点:
Bitmap bitmap = new Bitmap(filename); IntPtr handle = bitmap.GetHbitmap();
后一个代码旨在与GDI一起使用.在研究这个问题时,我发现这实际上是一个内存问题,.NET试图在单个内存块中分配两倍的内存.
http://bytes.com/groups/net-c/279493-drawing-large-bitmaps
我从其他应用程序(Internet Explorer,MS Paint等)了解到,可以打开大图像,而且很快.我的问题是,如何在.NET中使用大型位图?
无论如何流式传输它们,还是非内存加载它们?
这是一个两部分问题.第一个问题是如何在不耗尽内存的情况下加载大型图像(1),第二个问题是提高加载性能(2).
(1)Concider像Photoshop一样的应用程序,你可以在文件系统上使用巨大的图像消耗gigabite.在大多数系统(甚至8gb x64系统)上,将整个图像保留在内存中并且仍然有足够的可用内存来执行操作(过滤器,图像处理等,甚至只是添加图层)是不可能的.
这就是为什么像这样的应用程序使用交换文件的概念.在内部我假设photoshop使用专有的文件格式,适合他们的应用程序设计并构建为支持来自交换的部分负载,使他们能够将文件的一部分加载到内存中来处理它.
(2)通过为每种文件格式编写自定义加载器,可以改进(非常多)Performande.这需要您阅读要使用的文件格式的文件头和结构.一旦你掌握了它,那就不是****,但它并不像做方法调用那样微不足道.
例如,您可以google for FastBitmap查看有关如何快速加载位图(BMP)文件的示例,其中包括解码位图标头.这涉及到pInvoke并且为了让你对你所遇到的内容有所了解,你将需要定义位图结构,例如
[StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BITMAPFILEHEADER { public Int16 bfType; public Int32 bfSize; public Int16 bfReserved1; public Int16 bfReserved2; public Int32 bfOffBits; } [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFO { public BITMAPINFOHEADER bmiHeader; public RGBQUAD bmiColors; } [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFOHEADER { public uint biSize; public int biWidth; public int biHeight; public ushort biPlanes; public ushort biBitCount; public BitmapCompression biCompression; public uint biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public uint biClrUsed; public uint biClrImportant; }
可能需要创建一个DIB(http://www.herdsoft.com/ti/davincie/imex3j8i.htm)和奇怪的数据,比如数据被"颠倒"存储在位图中,您需要考虑或者您会看到当你打开它时的镜像:-)
现在这只是针对位图.说你想做PNG然后你需要做类似的东西,但解码PNG标题,这是最简单的形式并不难,但如果你想得到完整的PNG规范支持,那么你是一个有趣的旅程: - )
PNG与位图不同,因为它使用基于块的格式,它具有"标题",您可以放置以查找不同的数据.我在播放格式时使用的一些块的示例是
string[] chunks = new string[] {"?PNG", "IHDR","PLTE","IDAT","IEND","tRNS", "cHRM","gAMA","iCCP","sBIT","sRGB","tEXt","zTXt","iTXt", "bKGD","hIST","pHYs","sPLT","tIME"};
您还必须了解PNG文件的Adler32校验和.因此,您想要做的每种文件格式都会增加一系列不同的挑战.
我真的希望我能在回复中提供更完整的源代码示例,但这是一个复杂的主题,说实话我自己没有实现交换,所以我不能给出太多可靠的建议.
简短的回答是BCL中的图像处理能力并不高.中等答案是尝试找出是否有人编写了可以帮助您的图像库,而长期的答案就是拉起袖子并自己编写应用程序的核心.
既然你在现实生活中认识我,你就知道在哪里找到我;)