需求:在WPF程序运行过程中,会用WriteableBitmap对象绘制视频流中每一帧的图像,需要将某一帧图片显示在前端XAML页面,同时将该图片保存到数据库中,并且实现从数据库中取出图片显示。解决步骤如下:
1.前台显示图片
前台控件为image控件,需要指定控件的imagesoure属性,因此需要将WriteableBitmap对象转换为BitmapImage对象
public BitmapImageAndByte ConvertWriteableBitmapoBitmapImage(WriteableBitmap writeableBitmap)
{
BitmapImage bitmapImage = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(writeableBitmap));
encoder.Save(stream);
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
return bitmapImage;
}
指定image控件的imageSource属性为该bitmapImage,即可显示图片
2.保存图片到数据库
2.1 图片格式转换
图片保存到MySQL数据库需要先将不同格式的图片保存为byte[ ]数组,无论是本地图片还是网络图片,或者是本次需求中内存里的图片,道理是一样的:转换为byte,存入数据库。
数据库中的字段类型可以根据自己要存取图片的大小来决定,tinyblob、blob、mediumblob等等。
数据库类型如下:
根据需求,我需要将WriteableBitmap对象转化为byte数组
public byte[] ConvertWriteableBitmapToByte(WriteableBitmap writeableBitmap)
{
byte[] imgByte = null;
using (MemoryStream stream = new MemoryStream())
{
try
{
stream.Position = 0;
using (BinaryReader br = new BinaryReader(stream))
{
imgByte = br.ReadBytes((int)stream.Length);
}
}
catch (Exception ex)
{
Console.WriteLine("convert error:" + ex.ToString());
}
}
return imgByte;
}
这段代码和第一步中的转换类似,可以根据需要合并在一个函数中。
2.2 将byte[]存入数据库中
public byte[] PostureByte1 { get; set; }
public void SaveImgToDatabase()
{
String connetStr = "server=localhost;port=3306;user=root;password=1234;database=test;";
MySqlConnection conn = null;
try
{
conn = new MySqlConnection(connetStr);
//string sql = "insert into testimages(img) values(‘{0}‘)";
//sql = string.Format(sql, PostureByte1);
//MySqlCommand cmd = new MySqlCommand(sql, conn);
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText= "insert into testimages(img) values(@img)";
cmd.Parameters.Add("@img", MySqlDbType.MediumBlob);//数据类型很重要
cmd.Parameters[0].Value = PostureByte1;//0代表commandText中的第一个参数
cmd.Connection = conn;//设置数据库连接
conn.Open();
var result = cmd.ExecuteNonQuery();
if (result != -1)
{
Console.WriteLine("插入成功,插入的byte[]长度为:" + PostureByte1.Length);
}
}
catch (Exception ex)
{
Console.WriteLine("插入失败:" + ex.ToString());
}
finally
{
if (conn!=null)
{
conn.Close();
}
}
}
注意上段代码中注释掉的部分,直接存放byte到数据库中,会丢失数据。这就造成取出取出byte后,无法还原为图片。所以需要在放入数据库时指定数据的类型为MySqlDbType.MediumBlob。
存放结果:
3.显示数据库中的图片
分为两部分,首先从数据库中取出blob数据,也就是byte[],然后将其转换为BitmapImage对象
3.1 从数据库中取出blob数据
public byte[] ShowImgFromDatabase()
{
String connetStr = "server=localhost;port=3306;user=root;password=1234;database=test;";
MySqlConnection conn = null;
byte[] imgbyte=null;
try
{
conn = new MySqlConnection(connetStr);
conn.Open();
string sql = "select * from testimages";
MySqlCommand cmd = new MySqlCommand(sql, conn);
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())//这里只取出了数据库中的一个记录,根据需要自行更改逻辑
{
long len = reader.GetBytes(reader.GetOrdinal("img"), 0, null, 0, 0);//先获取字段的长度
imgbyte = new byte[len];//根据获取到的长度初始化一个byte数组
len = reader.GetBytes(reader.GetOrdinal("img"), 0, imgbyte, 0, (int)len);//将数据写入数组
}
reader.Close();
return imgbyte;
}
catch (Exception ex)
{
Console.WriteLine("读取失败:" + ex.ToString());
return null;
}
finally
{
if (conn != null)
{
conn.Close();
}
}
}
3.2 将blob类型也就是byte[]转换为BitmapImage
private BitmapImage ConvertByteToBitmapImage(byte[] imgbyte)
{
BitmapImage bmp = null;
try
{
using (var ms = new MemoryStream(imgbyte))
{
ms.Seek(0, SeekOrigin.Begin);
bmp = new BitmapImage();
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.StreamSource = ms;
bmp.EndInit();
bmp.Freeze();
}
return bmp;
}
catch (Exception ex)
{
Console.WriteLine("转换失败:"+ex.ToString());
bmp = null;
}
return bmp;
}
获取到BitmapImage后,赋值给对应的image控件,完成显示。