WPF 使用不安全代码快速从数组转 WriteableBitmap
原文:WPF 使用不安全代码快速从数组转 WriteableBitmap 本文告诉大家一个快速的方法,直接把数组转 WriteableBitmap 先来说下以前的方法,以前使用的是 BitmapSource ,这个方法是大法官方提供的。 其中 dest 是一个大数组,数据大小为 ,经常在转换的时候出现内存不足异常。假如现在内存占用是 1.5G ,转换的图片大小是 为何还有 500 M 内存却出现内存不足?因为图片转换需要的是一段大的连续内存空间。砸桌子,再说一次,图片转换需要一段【大的连续】内存空间,虽然有500M内存,但是连续的空间没有那么多。 这就是以前方法的缺点。 使用不安全代码转换是把数组直接复制到WriteableBitmap,请看使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用 - walterlv,这里讲了如何从 Bitmap 转 WriteableBitmap ,于是下面只需要把数组转 Bitmap 就可以了。 我在最后会给大家全部代码,所以现在讲原理。 如果已经拿到了数组,知道数组的存放,那么就可以直接把数组复制到 WriteableBitmap 就可以显示。数组的存放就是数组是如何放数据的,是不是还在想,上面的 dest 是一个大数组,他的计算是 因为没有直接从数组转 WriteableBitmap 所以需要先把数组转 Bitmap ,可以使用的方法请看下面 Bitmap 的数据类型可以是任意,因为只是把他的数据转换到 WriteableBitmap 所以不需要指定他的数据 获得 Bitmap 就可以把他转 WriteableBitmap ,请看下面的代码 代码的 CopyFrom 就是吕毅提供的方法。 使用这个函数更新,不需要在更新了修改 Image 的 Source 因为会自动更新,用这个方法播放 gif 的性能比找到的Magick.NET库的性能都好。 对比一下性能,这时原先的 BitmapSource 方法占用内存 这是使用不安全代码占用内存 实际跑一张 gif 图的性能 可以看到这个方法可以节省很多的内存,而且占用的 cpu 很低,因为没有很多gc 但是不要太高兴,因为不安全代码的exception是接不住的,下面请修改一下代码,让他输入错误,于是就出现异常,结果程序就关了。 所以使用这个方法还是很大的坑。 全部的代码: 我把代码给小伙伴看,他说可以直接从数组转 WriteableBitmap ,我使用他的想法,修改了程序,请看代码 实际上微软已经提供了不安全代码的转换,请看下面代码 stride 一般就是 本文会经常更新,请阅读原文:
BitmapSource.Create(LogicalWidth, LogicalHeight, 96, 96, PixelFormats.Bgra32, null,
dest,
stride);
2000*2000 ,于是几乎一跑就出现内存不足。
为什么是*4,因为存放的数据是 A R B G 一个点需要4个int来放。那么放的顺序是什么?这就是PixelFormat指定的类型,可以使用Bgra32或者其他的格式,不过指定了格式就需要数组存放和指定一样 unsafe
{
fixed (int* ptr = _dest)
{
try
{
using (Bitmap image = new Bitmap(LogicalWidth, LogicalHeight, LogicalWidth * 4,
PixelFormat.Format16bppArgb1555, new IntPtr(ptr)))
{
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
unsafe
{
fixed (int* ptr = _dest)
{
try
{
using (Bitmap image = new Bitmap(LogicalWidth, LogicalHeight, LogicalWidth * 4,
PixelFormat.Format16bppArgb1555, new IntPtr(ptr)))
{
CopyFrom(source,image);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}




Application.Current?.Dispatcher.BeginInvoke((Action) (() =>
{
unsafe
{
fixed (int* ptr = _dest)
{
try
{
using (Bitmap image = new Bitmap(LogicalWidth, LogicalHeight, LogicalWidth * 4,
PixelFormat.Format16bppArgb1555, new IntPtr(ptr)))
{
CopyFrom(_source, image);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}));
private void UpdateSource()
{
Application.Current?.Dispatcher.Invoke(() =>
{
_source = new WriteableBitmap(LogicalWidth, LogicalHeight, 96, 96,
System.Windows.Media.PixelFormats.Bgra32, null);
});
}
public static void CopyFrom(WriteableBitmap wb, Bitmap bitmap)
{
if (wb == null)
throw new ArgumentNullException(nameof(wb));
if (bitmap == null)
throw new ArgumentNullException(nameof(bitmap));
var ws = wb.PixelWidth;
var hs = wb.PixelHeight;
var wt = bitmap.Width;
var ht = bitmap.Height;
if (ws != wt || hs != ht)
throw new ArgumentException("暂时只支持相同尺寸图片的复制。");
var width = ws;
var height = hs;
var bytes = ws * hs * wb.Format.BitsPerPixel / 8 ;
var rBitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly, bitmap.PixelFormat);
wb.Lock();
unsafe
{
Buffer.MemoryCopy(rBitmapData.Scan0.ToPointer(), wb.BackBuffer.ToPointer(), bytes, bytes);
}
wb.AddDirtyRect(new Int32Rect(0, 0, width, height));
wb.Unlock();
bitmap.UnlockBits(rBitmapData);
}
unsafe
{
fixed (int* ptr = _dest)
{
_source.Lock();
var bytes = LogicalWidth * LogicalHeight * _source.Format.BitsPerPixel / 8;
Buffer.MemoryCopy(ptr,_source.BackBuffer.ToPointer(), bytes, bytes);
_source.AddDirtyRect(new Int32Rect(0, 0, LogicalWidth, LogicalHeight));
_source.Unlock();
}
}
bitmapImage.WritePixels(new Int32Rect(0, 0, 宽度, 高度), 图片数据, stride, 0)
4*宽度 因为一个像素使用4个byte
https://lindexi.gitee.io/lindexi/post/WPF-%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%AE%89%E5%85%A8%E4%BB%A3%E7%A0%81%E5%BF%AB%E9%80%9F%E4%BB%8E%E6%95%B0%E7%BB%84%E8%BD%AC-WriteableBitmap.html
,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:
https://lindexi.gitee.io
),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请
与我联系
。
WPF 使用不安全代码快速从数组转 WriteableBitmap的更多相关文章
- 2018-8-10-WPF-使用不安全代码快速从数组转-WriteableBitmap
title author date CreateTime categories WPF 使用不安全代码快速从数组转 WriteableBitmap lindexi 2018-08-10 19:16:5 ...
- 转载: Emmet:HTML/CSS代码快速编写神器
Emmet:HTML/CSS代码快速编写神器 因为文章严禁转载,那本着做一个遵纪守法的好公民,我就不转载了,把链接放下面,方便查阅. http://www.iteye.com/news/27580
- WPF案例 (三) 模拟QQ“快速换装"界面
原文:WPF案例 (三) 模拟QQ"快速换装"界面 这个小程序使用Wpf模拟QQ快速换装页面的动画特效,通过使用组合快捷键Ctrl+Left或Ctrl+Right,可实现Image ...
- javascript中快速求数组的全部元素的相加之和
js中快速求数组的全部元素的相加之和: var arr = [1,2,3,4,5];var sum = eval(arr.join('+')); console.log(sum); 运行结果: 15
- C语言/C++编程学习:栈的代码实现之数组方案
C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...
- c#字符串加载wpf控件模板代码 - 简书
原文:c#字符串加载wpf控件模板代码 - 简书 ResourceManager resManagerA = new ResourceManager("cn.qssq666.Properti ...
- WPF Grid 用 C# 代码后台设置
WPF Grid 用 C# 代码后台设置 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-21 参考: System.Wind ...
- 5_PHP数组_3_数组处理函数及其应用_1_快速创建数组的函数
以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. 一.快速创建数组的函数 1. range() 函数 程序: <?php $numbers = range(1 ...
- C#/WPF/WinForm/.NET程序代码实现软件程序开机自动启动的两种常用方法的示例与源码下载带详细注释-源码代码-注册表方式-启动目录快捷方式
C#/WPF/WinForm/.NET程序代码实现软件程序开机自动启动的两种常用方法的示例与源码下载带详细注释-源码代码-注册表方式-启动目录快捷方式 C#实现自动启动的方法-两种方法 源码下载地址: ...
随机推荐
- jvisualvm 工具使用
VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不需要特定参数,监控工具在bin/jvisualvm.exe). https:// ...
- 37、mipg-streamer的使用讲解
讲解mjpg-streamer 其功能: 1.控制摄像头采集数据(通过ioctl采集数据,所有不支持CMOS,CMOS之前写驱动的时候是通过read,所有需要修改mjpg-streamer的源码或者C ...
- Google guava工具类的介绍和使用
概述 工具类 就是封装平常用的方法,不需要你重复造轮子,节省开发人员时间,提高工作效率.谷歌作为大公司,当然会从日常的工作中提取中很多高效率的方法出来.所以就诞生了guava.. 高效设计良好的API ...
- /bin/bash^M: bad interpreter: 没有那个文件或文件夹
执行脚本时出现了这样一个错误,打开之后并没有找到所谓的^M,查了之后才知道原来是文件格式的问题,也就是linux和windows之间的不全然兼容... 详细细节无论,假设验证: vim test.sh ...
- gdbserver远程调试嵌入式linux应用程序方法
此处所讲的是基于gdb和gdbsever的远程调试方法.环境为:PC机:win7.虚拟机:10.04.下位机:飞嵌TE2440开发板. 嵌入式linux应用程序的开发一般都是在linux里面编写好代码 ...
- 致ITFriend用户
) 全权处理,相关问题请和他沟通. 祝大家中秋节快乐,一家团团圆圆. 小雷FansUnion 湖北 武汉 2014年9月7日 --------------------------------- ...
- 【Codeforces Round #439 (Div. 2) A】The Artful Expedient
[链接] 链接 [题意] [题解] 暴力 [错的次数] 在这里输入错的次数 [反思] 在这里输入反思 [代码] #include <bits/stdc++.h> using namespa ...
- 关于.c和.h 和定义变量的问题
最初调试的时候是因为有个错误在wavplay.h文件中 于是我跳到了recorderl.h中:从图中看到引用了main.h 出现这个问题的具体原因还是不太清楚: 不过我任务是因为: wavplay.h ...
- CSS边框作图
原文 简书原文:https://www.jianshu.com/p/537a878304f2 大纲 1.border-style的值 2.利用border作图——基本图形 3.利用border作图—— ...
- [转载]Surging教学视频资源汇总
surging是什么 surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希,随机,轮询.压力最小优先作 ...