4

我正在开发一个用于将图像上传到 Web 服务器的 Windows Phone 应用程序。我正在将设备中的所有图像选择到一个List 对象中。我正在将所有位图图像一一转换为字节 []。

我的代码

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”类型的异常,但未在用户代码中处理

4

3 回答 3

2

我能做些什么来解决这个错误?

改变你做事的方式,使用更少的内存。

例如,不是转换每张图片然后上传它们,而是转换一张图片,上传它,转换下一张,等等。

如果你真的想一次处理所有的图片,你可以将字节数组存储在隔离的存储中,而不是将它们保存在内存中,并在需要时将它们读回。

基本上,重新考虑您的流程并使用存储在给定时间使用更少的内存。

或者要求微软取消 Windows Phone 的内存限制,但这可能有点棘手。

于 2013-07-30T12:54:41.203 回答
1

问题在于 GC 和位图图像如何协同工作,如本错误报告中所述:https ://connect.microsoft.com/VisualStudio/feedback/details/679802/catastrophic-failure-exception-throw-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();
    }
}
于 2013-07-30T12:58:53.573 回答
0

我找到了将位图图像转换为字节 [] 数组的新方法。无需将图像写入内存。野兔是代码

 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;
    }
于 2013-08-05T10:52:48.767 回答