zoukankan      html  css  js  c++  java
  • 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 }

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

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

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

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

  • 相关阅读:
    大文件上传实现总结
    JDK线程池异常处理方式
    packageinfo.java 作用
    VBA 发送邮件代码
    TCP/IP协议、DoD模型、OSI模型
    3D空间基础概念之三:几何变换
    IP寻址
    IP地址排错命令
    WIN7用户文件夹迁移
    IP报头包含的协议
  • 原文地址:https://www.cnblogs.com/lipf/p/2364208.html
Copyright © 2011-2022 走看看