zoukankan      html  css  js  c++  java
  • [uwp]ImageSource和byte[]相互转换

    最近做一个小app遇到一个问题,到目前还没有比较好的解决方法(可能是我查的资料不够多)

    需求如下:

    1.把一个Image中的图像保存到字节数组;

    2.把字节数组转换为ImageSource,通过Image控件展示图像.

    上面两个需求恰恰是相反的过程,为了实现这个,我倒网上找了好多,但基本都是wp7,wp8,wpf的方案,在win10上没法用。。纠结。

    后来在知乎日报uwp的源码中发现了一个把ImageSource存储为文件的方法。(github:https://github.com/sherlockchou86/ZhiHuDaily.UWP),感谢作者为win10生态圈的贡献。

    代码如下:

    public async Task SaveImageAsync(WriteableBitmap image, string filename)
            {
                try
                {
                    if (image == null)
                    {
                        return;
                    }
                    Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
                    if(filename.EndsWith("jpg"))
                            BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
                    else if(filename.EndsWith("png"))
                            BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
                    else if(filename.EndsWith("bmp"))
                            BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
                    else if(filename.EndsWith("tiff"))
                            BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
                    else if(filename.EndsWith("gif"))
                            BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
                    var folder = await _local_folder.CreateFolderAsync("images_cache", CreationCollisionOption.OpenIfExists);
                    var file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
    
                    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
                        Stream pixelStream = image.PixelBuffer.AsStream();
                        byte[] pixels = new byte[pixelStream.Length];
                        await pixelStream.ReadAsync(pixels, 0, pixels.Length);
                        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
                                  (uint)image.PixelWidth,
                                  (uint)image.PixelHeight,
                                  96.0,
                                  96.0,
                                  pixels);
                        await encoder.FlushAsync();
                    }
                }
                catch
                {
    
                }
            }
    SaveImageAsync

    有了这个,我的需求就能解决了,因为在上面的代码中,有一个随机访问流ras,所以我们可以把ras利用拓展方法AsStream()转化为普通的流,然后用Read()或者ReadAsync()读取到字节数组即可。

    于是需求一的代码如下:

    public static async Task<byte[]> SaveToBytesAsync(this ImageSource imageSource)
            {
                byte[] imageBuffer;
                var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
                var file = await localFolder.CreateFileAsync("temp.jpg", CreationCollisionOption.ReplaceExisting);
                using (var ras = await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
                {
                    WriteableBitmap bitmap = imageSource as WriteableBitmap;
                    var stream = bitmap.PixelBuffer.AsStream();
                    byte[] buffer = new byte[stream.Length];
                    await stream.ReadAsync(buffer, 0, buffer.Length);
                    BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras);
                    encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buffer);
                    await encoder.FlushAsync();
    
                    var imageStream = ras.AsStream();
                    imageStream.Seek(0, SeekOrigin.Begin);
                    imageBuffer = new byte[imageStream.Length];
                    var re = await imageStream.ReadAsync(imageBuffer, 0, imageBuffer.Length);
                    
                }
                await file.DeleteAsync(StorageDeleteOption.Default);
                return imageBuffer; 
            }

    值得注意的几点:

      1.用了拓展方法;

      2.ImageSource一般可以通过BitmapImage和WriteableImage来设置,但这儿只能用WriteableImage,因为要用到接口IWriteableBitmap;

      3.ras随机访问流转为普通FCL普通流后,用Seek将Positon设置到0,读出的数据出错;

      4.注意图像编码的设置,这儿只针对jpeg格式;

      5.这是一个投机的办法,先存储为文件,再存储为字节数组,但核心还是一个ras(IRandomAccessSteam).

    需求二代码如下:

    public static async Task<ImageSource> SaveToImageSource(this byte[] imageBuffer)
            {
                ImageSource imageSource = null;
                using (MemoryStream stream = new MemoryStream(imageBuffer))
                {
                    var ras = stream.AsRandomAccessStream();
                    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, ras);
                    var provider = await decoder.GetPixelDataAsync();
                    byte[] buffer = provider.DetachPixelData();
                    WriteableBitmap bitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
                    await bitmap.PixelBuffer.AsStream().WriteAsync(buffer, 0, buffer.Length);
                    imageSource = bitmap;
                }
                return imageSource;
            }

    注意点如下:

      1.解码用的还是jpeg;

      2.还是用的WriteableBitmap,主要还是他的接口决定的;

    tips:如果照的上面的代码写,某些方法或属性下面还是有红色波浪线的话,记着选中它,然后按Shift+alt+F10,Visual Studio帮你解决。

  • 相关阅读:
    关于hibernate的缓存使用(转)
    Webservice 实践
    三大电商注册登录表单分析
    网上好文搜集
    git简介
    Python程序中的进程操作--—--开启多进程
    进程的创建和结束
    同步异步阻塞和非阻塞
    进程的并行和并发
    进程调度
  • 原文地址:https://www.cnblogs.com/cjw1115/p/5164327.html
Copyright © 2011-2022 走看看