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]); ListtempList = 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 ListtempList = 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 }
顿时我就内牛满面,太不给面子了吧,这什么个情况嘛 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 ListtempList = 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 }
到此,大功告成了,其中还有很多可优化的地方,还请高人指点,还有那个最重要的问题:
为什么我进行与运算来取值就取的不对呢,百思不得其解
希望知道原因的大侠给小弟点指点,感激不尽,临表涕零啊。。
(话说能上首页吗,搞到晚上一点多。。希望能和大家分享,更希望能有高人看到给我指点下那个问题。。)