• [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帮你解决。

  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/cjw1115/p/5164327.html
Copyright © 2020-2023  润新知