.net c#影像到记忆体变慢

Image to memory slow
2021-09-14
  •  译文(汉语)
  •  原文(英语)

我主要想提建议.

我的程序在屏幕上显示了多个大图像.每个图像都在1-4 mbs之间.150 DPI和6000x4000分辨率,24位深度.

我还有许多其他设置,可以给我较小的图像..但是我需要高质量的图像.

好吧,所以它很慢..但不是那么慢...唯一真正不好的部分是当我从一个图像切换到另一个图像时.

因此,我基本上每个图像都有2张图像.1个缩略图和1个HQ.当用户放大图像时,我会加载HQ,而当用户缩小图像时,它将切换到缩略图图像.

就在那个切换点,用户必须等待大约4-8秒,才能将HQ图像加载到内存中并绘制到屏幕上.

以下是加载HQ图像时使用的代码

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
                {
    FileStream fs = new FileStream(ActiveImage.imagePath, FileMode.Open, FileAccess.Read, FileShare.Read);

    MemoryStream ms = new MemoryStream();
    fs.CopyTo(ms);
    ms.Seek(0, SeekOrigin.Begin);
    fs.Close();

    BitmapImage bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
    bitmap.StreamSource = ms;
    bitmap.EndInit();
    //bitmap.Freeze();

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}

以下是我加载Thumb图像时使用的代码

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
{
    FileStream fs = new FileStream(ActiveImage.thumbPath, FileMode.Open, FileAccess.Read, FileShare.Read);

    MemoryStream ms = new MemoryStream();
    fs.CopyTo(ms);
    ms.Seek(0, SeekOrigin.Begin);
    fs.Close();

    BitmapImage bitmap = new BitmapImage();
    RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.NearestNeighbor);
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
    bitmap.StreamSource = ms;
    bitmap.EndInit();
    //bitmap.Freeze();

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}

有什么优化的方法吗?有更好的办法吗?请记住,仅当用户查看单个图像时,我才需要HQ清晰的图像.

我想MemoryStream可能会出来,但我将其添加为一种测试.

速聊1:
与该问题无关(可能),但是其中可能存在一些内存泄漏以及未处理的内存流.您应该像使用绘图上下文一样将它们放在使用的内部.
速聊2:
我一定会尝试删除多余的内存流并比较速度;不考虑磁盘/内存的任何加载优化,您将执行相同的复制步骤两次:一次到memorystream,再一次转移到bitmap.
速聊3:
而且,如果您发现额外的内存流方法更有效,则可以尝试使用Marshal.Copy复制到字节数组,然后从该数组创建内存流(随机想法)
速聊4:
快速说明..我之所以在其中添加内存流是因为..如果我将图像加载到MS中,然后加载到位图中,则可以根据需要在计算机上编辑图像文件.直接从文件流到位图,图像文件基本上被锁定.
解决过程1

只是一个猜测,但这不是将所有潜在的优化留给WPF并仅通过其URI加载图像的"最佳"解决方案:

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
{
    var bitmap = new BitmapImage(new Uri(ActiveImage.imagePath));
    // alternatively, if it is a relative path
    // var bitmap = new BitmapImage(new Uri(ActiveImage.imagePath, UriKind.Relative));

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}

I mostly would like advice..

My program displays multiple Large images on the screen.. Which are between 1-4 mbs each.. 150 DPI, and 6000x4000 resolution, 24 bit depth..

I have many other settings which will give me smaller images.. but I need high qualitity images..

Ok, so It's slow.. but not that slow... The only really bad part is when I switch from 1 image to the other..

So, I have basically 2 Images for every image.. 1 Thumb, and 1 HQ.. When the user zooms into an image I load the HQ, and when the user zooms out, it switches to the thumb image..

Right at that switching point, the user has to wait about 4-8 seconds for the HQ image to load into the memory and draw to the screen..

Below is the code I use when I load the HQ image

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
                {
    FileStream fs = new FileStream(ActiveImage.imagePath, FileMode.Open, FileAccess.Read, FileShare.Read);

    MemoryStream ms = new MemoryStream();
    fs.CopyTo(ms);
    ms.Seek(0, SeekOrigin.Begin);
    fs.Close();

    BitmapImage bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
    bitmap.StreamSource = ms;
    bitmap.EndInit();
    //bitmap.Freeze();

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}

Below is the code I use when I load the Thumb image

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
{
    FileStream fs = new FileStream(ActiveImage.thumbPath, FileMode.Open, FileAccess.Read, FileShare.Read);

    MemoryStream ms = new MemoryStream();
    fs.CopyTo(ms);
    ms.Seek(0, SeekOrigin.Begin);
    fs.Close();

    BitmapImage bitmap = new BitmapImage();
    RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.NearestNeighbor);
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
    bitmap.StreamSource = ms;
    bitmap.EndInit();
    //bitmap.Freeze();

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}

Any way to optimize this? Is there some better way? Remember I need a HQ crystal clear image only when the user is looking at a single image..

I suppose the MemoryStream could come out, but I added that as a kind of test..

Talk1:
Unrelated (possibly) to the question, but you might have some memory leaks in there with un-disposed memory streams. You should put them inside of usings like you are with the drawing context.
Talk2:
I would definitely try removing the extra memorystream and compare speed; not factoring in any loading optimization from disk/memory, you're doing the same copy step twice: once to memorystream, and again to transfer to bitmap.
Talk3:
And if you find the extra memorystream approach is more efficient, you can try Marshal.Copy to a byte array, then create the memory stream from that (random idea)
Talk4:
Quick note.. I the reason I added the memory stream in there was that.. If I load the image into the MS then to the bitmap, it allows me to edit the image file on the computer if I want.. If you go directly from filestream to bitmap, the image file is locked basically..
Solutions1

Just a guess, but wouldn't it perhaps be the "best" solution to leave all potential optimization to WPF, and just load the image by its URI:

using (DrawingContext dc = ActiveImage.imageDV.RenderOpen())
{
    var bitmap = new BitmapImage(new Uri(ActiveImage.imagePath));
    // alternatively, if it is a relative path
    // var bitmap = new BitmapImage(new Uri(ActiveImage.imagePath, UriKind.Relative));

    dc.DrawImage(bitmap, new Rect(ActiveImage.position, ActiveImage.size));
}
转载于:https://stackoverflow.com/questions/15593510/image-to-memory-slow

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入