保存图像文件和节省内存的最佳方法
在我的程序中,我正在创建一些大图片(Image
对象),并将它们保存到磁盘。然后我将它们添加到列表 List
中,但在保存 50 张图片并将它们作为 Image
对象添加到我的 imageList
后,它占用了失去记忆了。我尝试在 50 个图像上执行此操作,仅保存纯图像对象,我的程序在进程管理器中达到 160 MB。所以我必须找到一种方法来保存图片并将它们添加到列表中,而不会让程序耗尽所有内存。
所以我有几个解决方案,我很想听听您对它们的看法或者您是否有更好的解决方案。
- 压缩图像对象的
byte[]
数组。 - 压缩内存流对象的流。
- 将图像对象的
byte[]
数组转换为字符串,然后压缩该字符串。
我正在用 c# 做这个。
In my program i am creating some big pictures (Image
objects), and saving them to disk. Then I add them to a list List<Image>
but after saving 50 pictures and adding them as Image
objects to my imageList
it eats up a loooooot of memory. I tried doing this on 50 images and just saving pure image object, my program went up to 160 MB in process manager. So I must find out a way of saving the pictures and adding them to the list without the program eating up all memory.
So I have a couple of solutions and I would love to hear what you think about them or if you have any better ones.
- Compress the
byte[]
array of the image object. - Compress the stream of the memorysteam object.
- Convert the
byte[]
array of the image object to string and then compress the string.
I am doing this in c#.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不要使用 .Net DeflateStream 等压缩图像(因为有一个已知问题,在所有情况下它实际上都会增加数据的大小) - 将其直接保存为 .png 之类的文件。
确保处理您创建的图像(保存后)。
您无法压缩内存中的图像 - 因为 Windows GDI(.Net 使用的)本质上要求图像采用未压缩的位图形式(因此,当您加载压缩图像时,它将被解压缩)。
您应该考虑按需加载它们。这是一个类似于
ImageList
的类,您可能会发现它很有用:Do not compress your images using the .Net DeflateStream or such (as there is a known issue where it actually increases the size of the data, in all cases) - save it directly to something like a .png.
Make sure you dispose the images that you created (after you have saved them).
You can't compress the images in memory - because Windows GDI (which .Net uses) requires the images in, essentially, uncompressed bitmap form (so when you load a compressed image it will get decompressed).
You should look at loading them on-demand. Here is a class similar to
ImageList
which you may find useful:为什么要压缩?当然,您不必同时显示所有图像(不是全分辨率) - 因此,要么创建较小的拇指,要么仅显示一小部分。
why compress? Surely you don't have to show all images at the same time (not in full resolution) - so either create smaller thumbs or show only a small subset.
由于图像是通过滚动条更改的,为什么不只显示当前索引周围的图像子集,就像如果您有 10 个图像并且位于 #5,则仅加载 4/5/6 并卸载其余图像,并且如下滚动移动到6加载7,如果你有很多图像并且你担心滚动移动会比加载快,你可以加载3/4/5/6/7,当它移动到6时加载8,依此类推在。
since the images are changed by a scroll bar, why not show only the subset of images around the current index, like if you have 10 images and you are at #5, only load 4/5/6 and unload the rest, and as the scroll moves to 6 load 7, if you have lots of images and you are afraid the scroll movement will be faster than loading, you can load 3/4/5/6/7 and when it moves to 6 load 8, and so on.
使用 WPF 时,您只需将图像保存在 MemoryStreams 列表中,其中包含 PNG 或 JPEG 图像。然后,您可以使用某些转换器或包装类绑定到图像,该转换器或包装类创建分辨率降低的 ImageSource 对象。不幸的是,您没有说明您正在使用哪种技术,而且我目前不知道 WinForms 的解决方案。
执行此操作时,每个图像仅存储一些 kB,并且 UI 加载的图像将按比例缩小,因此使用的内存是有限的。
通过这种方法,我可以在扫描仪应用程序中加载 100 多个图像,并且它们全部显示在
ListBox
中,并带有VirtualizingStackPanel
并排,垂直分辨率为 800 像素。原始图像的分辨率超过 2200 x 3800 像素和 24 bpp。加载具有数百万像素的 PNG 通常需要一秒钟,但使用此解决方案,您无需从磁盘加载它们。
并且不要忘记处置和删除临时对象等。您还可以运行 GC.Collect() 来确保删除未使用的数据。
When using WPF you can simply save the images in a list of MemoryStreams which contain the images as PNG or JPEG. Then you can bind to the images using some converter or a wrapper class that creates an ImageSource object with a reduced resolution. Unfortunately you didn't tell which technique you are using and I currently don't know a solution for WinForms.
When doing this you'll only store some kB per image and the loaded image for the UI will be scaled down, so that the used memory is limited.
With this approach I could load over 100 images in a scanner application and they were all displayed in a
ListBox
with aVirtualizingStackPanel
side by side with a vertical resolution of 800 pixels. The original images had a resolution of over 2200 x 3800 pixels and 24 bpp.Loading a PNG with several million pixels normaly takes a second, but with this solution you won't need to load them from disk.
And don't forget to dispose and remove temporary objects etc. You can also run
GC.Collect()
to make sure that unused data will be removed.我喜欢第二个选择。使用 PNG 格式将图像保存到内存应该比使用 zlib 或 gzipstream 等常见压缩库更有效。
I like the 2nd choice. Saving your Image to memory using PNG format should be more efficient than using a common compress library like zlib or gzipstream.