4

编辑:我不断收到 OutOfMemoryException 未处理,我认为这是我将图像保存到隔离存储的方式,我认为这是我可以解决问题的地方,如何在保存之前减小图像的大小?(在我保存图像的地方添加了代码)

我从独立存储中打开图像,有时超过 100 张图像,我想循环播放这些图像,但是OutOfMemory Exception当故事板中加载了大约 100 到 150 张图像时,我得到了一个。我该如何处理这个异常,我已经降低了图像的分辨率。如何处理此异常并阻止我的应用程序崩溃?

我在这里得到了这一行的例外

image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage

这是我的代码

private void OnLoaded(object sender, RoutedEventArgs e)
    {


        IsolatedStorageFile isStoreTwo = IsolatedStorageFile.GetUserStoreForApplication();



        try
        {
            storyboard = new Storyboard
            {
                //RepeatBehavior = RepeatBehavior.Forever
            };

            var animation = new ObjectAnimationUsingKeyFrames();

            Storyboard.SetTarget(animation, projectImage);
            Storyboard.SetTargetProperty(animation, new PropertyPath("Source"));


            storyboard.Children.Add(animation);
            for (int i = 1; i <= savedCounter; i++)
            {
                BitmapImage image = new BitmapImage();

                image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage

                var keyframe = new DiscreteObjectKeyFrame
                {

                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(100 * i)),
                    Value = image
                };

                animation.KeyFrames.Add(keyframe);
            }
        }
        catch (OutOfMemoryException exc)
        {

            //throw;

        }



        Resources.Add("ProjectStoryBoard", storyboard);
        storyboard.Begin();
    }

编辑 这就是我将图像保存到隔离存储的方式,我认为这是我可以解决问题的地方,如何在将图像保存到隔离存储时减小图像的大小?

    void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
    {

        string fileName = folderName+"\\MyImage" + savedCounter + ".jpg";

        try
        {  

            // Save picture to the library camera roll.
            //library.SavePictureToCameraRoll(fileName, e.ImageStream);



            // Set the position of the stream back to start
            e.ImageStream.Seek(0, SeekOrigin.Begin);

            // Save picture as JPEG to isolated storage.
            using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
                {

                    // Initialize the buffer for 4KB disk pages.
                    byte[] readBuffer = new byte[4096];
                    int bytesRead = -1;

                    // Copy the image to isolated storage. 
                    while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                    {
                        targetStream.Write(readBuffer, 0, bytesRead);
                    }

                }

            }




        }
        finally
        {
            // Close image stream
            e.ImageStream.Close();
        }

    }

如果您能帮助我,我将不胜感激。

4

7 回答 7

7

图像在磁盘上的大小并不重要,因为当您将它们加载到内存中时,它们将被解压缩。图像所需的内存大约为(stride * height). stridewidth * bitsPerPixel)/8,然后向上舍入到下一个 4 字节的倍数。因此,1024x768 和每像素 24 位的图像将占用大约 2.25 MB。

您应该弄清楚未压缩的图像有多大,并使用该数字来确定内存要求。

于 2012-04-13T02:36:21.027 回答
5

您将收到 OutOfMemory 异常,因为您同时将所有图像存储在内存中以创建 StoryBoard。我认为您无法克服图像需要在屏幕上显示的未压缩位图大小。

所以要克服这个问题,我们必须考虑你的目标,而不是试图修复错误。如果您的目标是每 X 毫秒按顺序显示一张新图像,那么您有几个选择。

  1. 继续使用 StoryBoard,但使用 OnCompleted 事件链接它们。这样您就不必一次创建它们,而只需生成接下来的几个。如果您每 100 毫秒更改一次图像,它可能不够快。

  2. 使用我在此处的回答中提到的 CompositionTarget.Rendering 。如果您只是预加载下一个(而不是像您当前的解决方案那样将它们全部预加载),这可能会占用最少的内存。不过,您需要手动检查经过的时间。

  3. 重新考虑你在做什么。如果你说明你要做什么,人们可能会有更多的选择。

于 2012-04-16T14:53:39.983 回答
1

要回答帖子顶部的编辑,请尝试ImageResizer。有一个 NuGet 包和一个HanselBlog插曲。显然,这是基于 Asp.Net 的,但我相信您可以将其用于您的场景。

于 2012-04-17T09:54:01.933 回答
1

在设计层解决这类问题通常效果更好。

通过一些配置使应用程序对运行环境智能,使您的应用程序更加健壮。例如,您可以根据可用内存定义一些变量,如图像大小、图像计数、图像质量……并在运行时在应用程序中设置这些变量。所以你的应用程序总是有效的;在高内存机器上快,在低内存机器上慢;但永远不会崩溃。(不要相信在托管环境中工作意味着不用担心环境......设计总是很重要)

还有一些已知的设计模式,如延迟加载,您可以从中受益。

于 2012-04-20T13:02:06.413 回答
0

根据您的一条评论,您正在构建一个 Time Lapse 应用程序。用于 WP7 的商业延时应用程序将图像压缩为视频,而不是静止图像。例如延时摄影专业版

视频播放的重点是将相似或与时间相关的图像减少为高度压缩的流,不需要大量内存即可播放

如果您可以在您的应用程序中添加对视频进行编码的功能,您将避免尝试模拟视频播放器的问题(使用 100 多个单个全分辨率帧作为轻弹书)。

将图像处理到视频服务器端可能是另一种选择(但不如相机内友好)。

于 2012-04-18T16:10:27.037 回答
0

好的,图像 (1024x768) 的内存大小至少为 3 mb (argb)

不知道 ObjectAnimationUsingKeyFrames 如何在内部工作。也许您可以通过销毁 BitmapImage(和 KeyFrames)的实例来强制 gc,而不会丢失动画中的数据。(不可能,见评论!)

于 2012-04-13T01:18:52.747 回答
0

我不特别了解 windows phone,但是在 .net winforms 中,在执行长时间运行的任务时需要使用单独的线程。您使用的是 BackgroundWorker 还是等效的?终结器线程可能会被阻塞,这将阻止图像资源被释放。使用与 UI 线程不同的线程将允许 Dispose 方法自动运行。

于 2012-04-13T01:43:58.093 回答