问题描述
我正在尝试编写一个轻量级的图像查看应用程序.但是,.NET 存在系统内存限制.
I'm trying to write a light-weight image viewing application. However, there are system memory limitations with .NET.
尝试加载大型位图(9000 x 9000 像素 或更大,24 位)时,出现 System.OutOfMemoryException.这是在具有 2GB RAM(其中 1.3GB 已用完)的 Windows 2000 PC 上进行的.尝试加载文件也需要花费大量时间.
When trying to load large bitmaps (9000 x 9000 px or larger, 24-bit), I get a System.OutOfMemoryException. This is on a Windows 2000 PC with 2GB of RAM (of which 1.3GB is used up). It also takes a lot of time to attempt loading the files.
以下代码生成此错误:
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);
}
此外,这样做就足够了:
Also, it is enough to do just this:
Bitmap bitmap = new Bitmap(filename);
IntPtr handle = bitmap.GetHbitmap();
后一种代码旨在与 GDI 一起使用.在对此进行研究时,我发现这实际上是一个内存问题,其中 .NET 试图在单个连续内存块中分配两倍于所需的内存.
The latter code was intended for use with GDI. While researching this, I found out that this is in fact a memory issue where .NET tries to allocate twice as much as is needed in a single contigous block of memory.
http://bytes.com/groups/net-c/279493-drawing-large-bitmaps
我从其他应用程序(Internet Explorer、MS Paint 等)了解到可以打开大图像,而且速度相当快.我的问题是,如何在 .NET 中使用大位图?
I know from other applications (Internet Explorer, MS Paint etc.) that it IS possible to open large images, and rather quickly. My question is, how do I use large bitmaps with .NET?
无论如何要流式传输它们,或者非内存加载它们?
Is there anyway to stream them, or non-memory load them?
推荐答案
这是一个由两部分组成的问题.第一个问题是如何在不耗尽内存的情况下加载大图像(1),第二个问题是提高加载性能(2).
This is a two part question. The first question is how you can load large images without running out of memory (1), the second one is on improving loading performance (2).
(1) 考虑一个像 Photoshop 这样的应用程序,您可以在其中处理在文件系统上消耗千兆字节的巨大图像.在大多数系统(甚至 8GB x64 系统)上,将整个图像保存在内存中并仍然有足够的可用内存来执行操作(过滤器、图像处理等,甚至只是添加层)是不可能的.
(1) Concider an application like Photoshop where you have the ability to work with huge images consuming gigabites on the filesystem. Keeping the entire image in memory and still have enough free memory to perform operations (filters, image processing and so on, or even just adding layers) would be impossible on most systems (even 8gb x64 systems).
这就是诸如此类的应用程序使用交换文件概念的原因.在内部,我假设 photoshop 使用专有的文件格式,适合他们的应用程序设计,并支持从交换中加载部分文件,使他们能够将文件的一部分加载到内存中以进行处理.
That is why applications such as this uses the concept of swap files. Internally I'm assuming that photoshop uses a proprietary file format, suitable for their application design and built to support partial loads from the swap, enabling them to load parts of a file into memory to process it.
(2) Performande 可以通过为每种文件格式编写自定义加载器来改进(相当多).这要求您阅读要使用的文件格式的文件头和结构.一旦你掌握了它,它就不是那么难,但它不像调用方法那么简单.
(2) Performande can be improved (quite a lot) by writing custom loaders for each file format. This requires you to read up on the file headers and structure of the file formats you want to work with. Once you've gotten the hand of it its not ****that**** hard, but it's not as trivial as doing a method call.
例如,您可以在 Google 上搜索 FastBitmap 以查看有关如何非常快速地加载位图 (BMP) 文件的示例,其中包括解码位图标头.这涉及 pInvoke 并让您了解您所面临的问题,您需要定义位图结构,例如
For example you could google for FastBitmap to see examples on how you can load a bitmap (BMP) file very fast, it included decoding the bitmap header. This involved pInvoke and to give you some idea on what you are up against you will need to define the bitmap structues such as
[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) 和奇怪的东西,比如数据颠倒"存储在位图中,你需要考虑到这一点,否则当你打开它时你会看到一个镜像:-)
Possibly work with creating a DIB (http://www.herdsoft.com/ti/davincie/imex3j8i.htm) and oddities like data being stored "upside down" in a bitmap which you need to take into account or you'll see a mirror image when u open it :-)
现在仅用于位图.假设你想做 PNG,那么你需要做类似的事情,但解码 PNG 标头,最简单的形式并不是那么难,但如果你想获得完整的 PNG 规范支持,那么你就可以玩得很开心:-)
Now that's just for bitmaps. Say you wanted to do PNG then you'd need to do similar stuff but decoding the PNG header, which in its simplest form isnt that hard, but if you want to get full PNG specification support then you are in for a fun ride :-)
PNG 与位图不同,因为它使用基于块的格式,其中具有标题",您可以定位以查找不同的数据.我在玩格式时使用的一些块的示例是
PNG is different to say a bitmap since it uses a chunk based format where it has "headers" you can loacate to find the diffrent data. Example of some chunks I used while playing with the format was
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 校验和.因此,您想要采用的每种文件格式都会增加一组不同的挑战.
You are also going to have to learn about Adler32 checksums for PNG files. So each file format you'd want to do would add a different set of challenges.
我真的希望我能在我的回复中提供更完整的源代码示例,但这是一个复杂的主题,老实说我自己没有实现交换,所以我无法就此给出太多可靠的建议.
I really wish I could give more complete source code examples in my reply but it's a complex subject, and to be honest I've not implemented a swap myself so I wouldn't be able to give too much solid advice on that.
简短的回答是 BCL 中的图像处理能力并不那么热门.中等的答案是尝试找出是否有人编写了可以帮助您的图像库,而长期的答案是挽起袖子自己编写应用程序的核心.
The short answer is that the image processing cababilities in the BCL isn't that hot. The medium answer would be to try and find if someone has written an image library that could help you and the long answer would be to pull up your sleeves and write the core of your application yourself.
因为你在现实生活中认识我,所以你知道在哪里可以找到我;)
Since you know me in real-life you know where to find me ;)
这篇关于如何在 .NET 中使用大位图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!