WPF BitmapSourceToArray and ArrayToBitmapSource

   WPF时至今日,也是N多开发人员的必修课了,但是也许很多人和我一样遇到了某种需求,需要把图片存进数据库,在必要的时候再查出来予以显示,问题就出来了,WPF相对Winform改动的东西还是比较多的,例如没有了Bitmap,改成了BitmapImage,原来Winform里的Image也没有了,在WPF里变成了一个控件。可是数据库只能存放byte[],而我们在WPF里操作最直接的是BitmapSource,这可如何是好,必须进行相互间的转化了。

  百度谷歌搜狗了N久无果,虽然找到一些,但是经测试全都不行,无一例外的达不到效果,无奈只好拍脑袋自己搞。。

  经过一系列蛋疼的测试,感觉BitmapSource下的CopyPixels方法还靠点谱,然后就先搞了个,但是怎么测试这个方法给我们的byte[]正确呢,还要在转回去才能看到效果,我一向信奉事实说话,然后就上msdn各种翻,最后锁定BitmapSource下的Create方法,于是开始测试,测试程序很简单,界面上两个Image控件,左边一个,右边一个,中间一个Button,click里面就一句话

1 image2.Source = ArrayToBitmapSource(BitmapSourceToArray((BitmapSource)image1.Source));

当我写完这句的时候就开始浑身蛋疼。。Create需要的参数我没办法提供,这可怎么搞,接着拍脑袋,由于ArrayToBitmapSource这个方法因为需求只能获得一个byte[],只好在这个byte[]上动脑筋了,既然他是数组,是用来存放数据的玩意儿,那么我可不可以通过他把Create需要的东西传进去呢,于是看了下Create的参数类型,除了一个PixelFormat枚举之外全是int,我靠,爽歪歪吧。。

然后就开始敲:

 1 public byte[] BitmapSourceToArray(BitmapSource bitmapSource)
2 {
3 int height = bitmapSource.PixelHeight;
4 int width = bitmapSource.PixelWidth;
5 int stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
6 byte[] bits = new byte[height * stride + 3];
7 bitmapSource.CopyPixels(bits, stride, 0);
8 bits[bits.Length - 3] = (byte)(width);
9 bits[bits.Length - 2] = (byte)(width);
10 bits[bits.Length - 1] = (byte)(width);
11 return bits;
12 }
public BitmapSource ArrayToBitmapSource(byte[] imageBytes)
{
PixelFormat pf = PixelFormats.Bgra32;
int width = (imageBytes[imageBytes.Length -3]);

int height = (imageBytes[imageBytes.Length - 2]);

int rawStride = (imageBytes[imageBytes.Length - 1]);


List<Byte> tempList = imageBytes.ToList();
tempList.RemoveRange(imageBytes.Length - 3, 3);
imageBytes = tempList.ToArray();
BitmapSource bmpImage = BitmapSource.Create(width, height,
96, 96, pf, null,
imageBytes, rawStride);
return bmpImage;
}

看上去很美,或许会有人觉得这样就可以了,可是当我写下(byte)进行强制转换的时候,心里就感觉有问题了,果然,编译运行报错了,很自然的我断点看了下width值在强转过程中是否丢失精度,一看发现确实如此,怎么办呢,一个是int,一个是byte,突然我就想起来当初写象棋的时候用一个int存放四个byte来表示一种走法,这里可不可以用呢,int是32位的,byte是8位的,由于都是正数,无视符号位,嘿嘿,这不刚好四个byte可以表示一个int吗,于是激动的拿着键盘开敲:

 1  public byte[] BitmapSourceToArray(BitmapSource bitmapSource)
2 {
3 int height = bitmapSource.PixelHeight;
4 int width = bitmapSource.PixelWidth;
5 int stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
6 byte[] bits = new byte[height * stride + 12];
7 bitmapSource.CopyPixels(bits, stride, 0);
8 bits[bits.Length - 12] = (byte)(width >> 24);
9 //16711680就是二进制的:
10 // 0000 0000 1111 1111 0000 0000 0000 000011
11 bits[bits.Length - 11] = (byte)(width&16711680);
12 //65280就是二进制的:
13 // 0000 0000 0000 0000 1111 1111 0000 000014
14 bits[bits.Length - 10] = (byte)(width &65280);
15 //255对应的二进制就是:
16 // 0000 0000 0000 0000 0000 0000 1111 111117
17 bits[bits.Length - 9] = (byte)(width & 255);
18 bits[bits.Length - 8] = (byte)(height >> 24);
19 bits[bits.Length - 7] = (byte)(height&16711680);
20 bits[bits.Length - 6] = (byte)(height&65280);
21 bits[bits.Length - 5] = (byte)(height & 255);
22 bits[bits.Length - 4] = (byte)(stride >> 24);
23 bits[bits.Length - 3] = (byte)(stride &16711680);
24 bits[bits.Length - 2] = (byte)(stride &65280);
25 bits[bits.Length - 1] = (byte)(stride & 255);
26 return bits;
27 }
 1 public BitmapSource ArrayToBitmapSource(byte[] imageBytes)
2 {
3 PixelFormat pf = PixelFormats.Bgra32;
4 int width = (imageBytes[imageBytes.Length - 12] << 24)
5 + (imageBytes[imageBytes.Length - 11] << 16)
6 + (imageBytes[imageBytes.Length - 10] << 8)
7 + (imageBytes[imageBytes.Length - 9]);
8
9 int height = (imageBytes[imageBytes.Length - 8] << 24)
10 + (imageBytes[imageBytes.Length - 7] << 16)
11 + (imageBytes[imageBytes.Length - 6] << 8)
12 + (imageBytes[imageBytes.Length - 5]);
13
14 int rawStride = (imageBytes[imageBytes.Length - 4] << 24)
15 + (imageBytes[imageBytes.Length - 3] << 16)
16 + (imageBytes[imageBytes.Length - 2] << 8)
17 + (imageBytes[imageBytes.Length - 1]);
18
19
20 List<Byte> tempList = imageBytes.ToList();
21 tempList.RemoveRange(imageBytes.Length - 12, 12);
22 imageBytes = tempList.ToArray();
23 BitmapSource bmpImage = BitmapSource.Create(width, height,
24 96, 96, pf, null,
25 imageBytes, rawStride);
26 return bmpImage;
27 }


然后那个激动啊,点了下按钮开始测试,卡了半天愣是没看到那个美女图片出来,好歹给个反应啊,不一会儿vs2010表态了:
{System.ArgumentException: 值不在预期的范围内。 ---> System.ArgumentException: 值不在预期的范围内。

顿时我就内牛满面,太不给面子了吧,这什么个情况嘛 T_T

然后我就想,换个写法试试,于是擦了把泪拿起键盘开敲:

public byte[] BitmapSourceToArray(BitmapSource bitmapSource)
{
int height = bitmapSource.PixelHeight;
int width = bitmapSource.PixelWidth;
int stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
byte[] bits = new byte[height * stride + 12];
bitmapSource.CopyPixels(bits, stride, 0);
bits[bits.Length - 12] = (byte)(width >> 24);
bits[bits.Length - 11] = (byte)((width << 8) >> 24);
bits[bits.Length - 10] = (byte)((width << 16) >> 24);
bits[bits.Length - 9] = (byte)(width & 255);

bits[bits.Length - 8] = (byte)(height >> 24);
bits[bits.Length - 7] = (byte)((height << 8) >> 24);
bits[bits.Length - 6] = (byte)((height << 16) >> 24);
bits[bits.Length - 5] = (byte)(height & 255);

bits[bits.Length - 4] = (byte)(stride >> 24);
bits[bits.Length - 3] = (byte)((stride << 8) >> 24);
bits[bits.Length - 2] = (byte)((stride << 16) >> 24);
bits[bits.Length - 1] = (byte)(stride & 255);
return bits;
}
 1 public BitmapSource ArrayToBitmapSource(byte[] imageBytes)
2 {
3 PixelFormat pf = PixelFormats.Bgra32;
4 int width = (imageBytes[imageBytes.Length - 12] << 24)
5 + (imageBytes[imageBytes.Length - 11] << 16)
6 + (imageBytes[imageBytes.Length - 10] << 8)
7 + (imageBytes[imageBytes.Length - 9]);
8
9 int height = (imageBytes[imageBytes.Length - 8] << 24)
10 + (imageBytes[imageBytes.Length - 7] << 16)
11 + (imageBytes[imageBytes.Length - 6] << 8)
12 + (imageBytes[imageBytes.Length - 5]);
13
14 int rawStride = (imageBytes[imageBytes.Length - 4] << 24)
15 + (imageBytes[imageBytes.Length - 3] << 16)
16 + (imageBytes[imageBytes.Length - 2] << 8)
17 + (imageBytes[imageBytes.Length - 1]);
18
19
20 List<Byte> tempList = imageBytes.ToList();
21 tempList.RemoveRange(imageBytes.Length - 12, 12);
22 imageBytes = tempList.ToArray();
23 BitmapSource bmpImage = BitmapSource.Create(width, height,
24 96, 96, pf, null,
25 imageBytes, rawStride);
26 return bmpImage;
27 }

点击按钮开始测试,神了,久违的美女图片显示出来了,顿时感动的想要以身相许了。。(可惜没人要 = =)

感动了一会儿我就开始郁闷了,为什么我进行与运算来取值就取的不对呢,百思不得其解,还请高人指点。。

感谢下被我折腾了这么久的那位美女童鞋的照片,当然也要感谢她本人了。。

自始至终Button里的代码都是这句:

1  private void button1_Click(object sender, RoutedEventArgs e)
2 {
3 image2.Source = ArrayToBitmapSource(BitmapSourceToArray((BitmapSource)image1.Source));
4 }

到此,大功告成了,其中还有很多可优化的地方,还请高人指点,还有那个最重要的问题:

为什么我进行与运算来取值就取的不对呢,百思不得其解

希望知道原因的大侠给小弟点指点,感激不尽,临表涕零啊。。

(话说能上首页吗,搞到晚上一点多。。希望能和大家分享,更希望能有高人看到给我指点下那个问题。。)

原文地址:https://www.cnblogs.com/lipf/p/2364208.html