我正在开发一个Windows手机应用程序,可用于将图像上传到Web服务器。我正在从设备中选择所有图像到一个列表对象。我将所有位图图像逐个转换为byte []。
我的代码
public byte[] ConvertToBytes(BitmapImage bitmapImage)
{
byte[] data = null;
WriteableBitmap wBitmap = null;
using (MemoryStream stream = new MemoryStream())
{
wBitmap = new WriteableBitmap(bitmapImage);
wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
//data = stream.GetBuffer();
data = stream.ToArray();
DisposeImage(bitmapImage);
return data;
}
}
public void DisposeImage(BitmapImage image)
{
if (image != null)
{
try
{
using (MemoryStream ms = new MemoryStream(new byte[] { 0x0 }))
{
image.SetSource(ms);
}
}
catch (Exception ex)
{
}
}
}
从位图转换为字节
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("ImagesZipFolder"))
{
//MediaImage mediaImage = new MediaImage();
//mediaImage.ImageFile = decodeImage(new byte[imgStream[0].Length]);
//lstImages.Items.Add(mediaImage);
store.CreateDirectory("ImagesZipFolder");
for (int i = 0; i < imgname.Count(); i++)
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(@"ImagesZipFolder\" + imgname[i], FileMode.CreateNew,store))
//using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(@"ImagesZipFolder\text.txt" , System.IO.FileMode.OpenOrCreate, store))
{
// byte[] bytes = new byte[imgStream[i].Length];
byte[] bytes = ConvertToBytes(ImgCollection[i]);
stream.Write(bytes, 0, bytes.Length);
}
}
}
else {
directory = true;
}
}
我的模拟器中有91张图片。当我将所有这些位图图像转换为 byte [] 时,在wBitmap = new WriteableBitmap(bitmapImage);
行上出现以下错误
System.Windows.ni.dll中出现“System.OutOfMemoryException”类型的异常,但未在用户代码中处理
我该怎么做才能解决这个错误?
网络服务
如果我们向Web服务发送大量文件,是否会出现错误,如
System.ServiceModel.ni.dll中出现“System.OutOfMemoryException”类型的异常,但未在用户代码中处理
答案 0 :(得分:2)
我该怎么做才能解决这个错误?
改变你做事的方式,减少记忆。
例如,不是转换每张图片然后上传它们,转换图片,上传图片,转换下一张图片,等等。
如果您真的想一次处理所有图片,可以将字节数组存储在隔离的存储中,而不是将它们保存在内存中,并在需要时将其读回。
基本上,重新考虑您的过程并使用存储在给定时间使用更少的内存。
或者要求微软取消Windows Phone的内存限制,但这可能有点棘手。
答案 1 :(得分:1)
问题在于GC和位图图像如何一起工作,如本错误报告中所述:https://connect.microsoft.com/VisualStudio/feedback/details/679802/catastrophic-failure-exception-thrown-after-loading-too-many-bitmapimage-objects-from-a-stream#details
来自报告:
当Silverlight加载图像时,框架会保留引用和 缓存解码图像,直到流控制返回到UI 线程调度员。当你像这样紧紧地加载图像时, 即使您的应用程序没有保留引用,GC也不能 释放图像,直到我们在流量控制时释放我们的参考 返回。
处理完20张左右的图像后,您可以停止并排队下一张图像 使用Dispatcher.BeginInvoke设置只是为了分解工作 一批处理。这将允许我们释放不是的图像 由您的申请保留。
我理解当前的解码行为并不明显 Silverlight保留了这些引用,但更改了解码器 设计可能影响其他领域,所以现在我建议处理 这样的图像分批。
现在,如果你真的试图加载500张图片并保留它们,那么你 根据图像大小,仍有可能内存不足。如果 您正在处理多页文档,您可能希望改为使用 在后台按需加载页面并在外出时释放它们 用几页缓冲区查看,这样你就不会超过 合理的纹理记忆限制。
<强>修正:强>
private List<BitmapImage> Images = .....;
private List<BitmapImage>.Enumerator iterator;
private List<byte[]> bytesData = new List<byte[]>();
public void ProcessImages()
{
if(iterator == null)
iterator = Images.GetEnumerator();
if(iterator.MoveNext())
{
bytesData.Add(ConvertToBytes(iterator.Current));
//load next images
Dispatcher.BeginInvoke(() => ProcessImages());
}else{
//all images done
}
}
public static byte[] ConvertToBytes(BitmapImage bitmapImage)
{
using (MemoryStream stream = new MemoryStream())
{
var wBitmap = new WriteableBitmap(bitmapImage);
wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
return stream.ToArray();
}
}
答案 2 :(得分:0)
我找到了将Bitmap Image转换为byte []数组的新方法。无需在内存中写入图像。 野兔是代码
public byte[] GetBytes(BitmapImage bi)
{
WriteableBitmap wbm = new WriteableBitmap(bi);
return ToByteArray(wbm);
}
public byte[] ToByteArray(WriteableBitmap bmp)
{
// Init buffer
int w = bmp.PixelWidth;
int h = bmp.PixelHeight;
int[] p = bmp.Pixels;
int len = p.Length;
byte[] result = new byte[4 * w * h];
// Copy pixels to buffer
for (int i = 0, j = 0; i < len; i++, j += 4)
{
int color = p[i];
result[j + 0] = (byte)(color >> 24); // A
result[j + 1] = (byte)(color >> 16); // R
result[j + 2] = (byte)(color >> 8); // G
result[j + 3] = (byte)(color); // B
}
return result;
}