zoukankan      html  css  js  c++  java
  • win10 uwp 读取保存WriteableBitmap 、BitmapImage

    我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap。关于 BitmapImage 和 WriteableBitmap 区别,我就不在这里说。主要说的是 BitmapImage 和 WriteableBitmap 、二进制 byte 的互转。


    我们先写一个简单的xaml

           <Image x:Name="Img" Height="200" Width="200" 
                  HorizontalAlignment="Center" Source="Assets/SplashScreen.png" ></Image>
    
            <Button Margin="10,300,10,10" Content="确定" Click="Button_OnClick" ></Button>
    

    用到的图片是我新建自带的。

    保存 WriteableBitmap 到文件

        private static async Task SaveWriteableBitmapImageFile(WriteableBitmap image, StorageFile file)
        {
            //BitmapEncoder 存放格式
            Guid bitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
            string filename = file.Name;
            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;
            }
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
            {
                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);
                //Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(imgstream);
                //Windows.Graphics.Imaging.PixelDataProvider pxprd = await decoder.GetPixelDataAsync(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8, Windows.Graphics.Imaging.BitmapAlphaMode.Straight, new Windows.Graphics.Imaging.BitmapTransform(), Windows.Graphics.Imaging.ExifOrientationMode.RespectExifOrientation, Windows.Graphics.Imaging.ColorManagementMode.DoNotColorManage);
    
                await encoder.FlushAsync();
            }
        }
    

    从文件读 WriteableBitmap

            private static async Task<WriteableBitmap> OpenWriteableBitmapFile(StorageFile file)
            {
                using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
                {
                    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
                    WriteableBitmap image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
                    image.SetSource(stream);
    
                    return image;
                }
            }

    ImageSource 转byte[]

    ImageSource可以是 BitmapImage 、WriteableBitmap,如果是WriteableBitmap ,那么直接转换

    WriteableBitmap 转byte[]

    bitmap.PixelBuffer.ToArray();

    Image 转byte[]

    如果我们的 ImageSource 是 BitmapImage ,那么我们不能使用上面的办法,直接保存 WriteableBitmap ,我们可以使用截图

    private async Task<string> ToBase64(Image control)
    {
        var bitmap = new RenderTargetBitmap();
        await bitmap.RenderAsync(control);
        return await ToBase64(bitmap);
    }
    
    

    如果 ImageSource 是 WriteableBitmap ,直接保存

    我们使用 byte[] 在传输时不好,不能用在 http 传输上(不是一定的不能),所以我们就把它转为base64,我提供了很多方法把数组转 base64 ,把文件转为 base64 。代码是 https://codepaste.net/ijx28i 抄的。

    
    //WriteableBitmap 转 byte[]
    private async Task<string> ToBase64(WriteableBitmap bitmap)
    {
        var bytes = bitmap.PixelBuffer.ToArray();
        return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
    }
    
    private async Task<string> ToBase64(StorageFile bitmap)
    {
        var stream = await bitmap.OpenAsync(Windows.Storage.FileAccessMode.Read);
        var decoder = await BitmapDecoder.CreateAsync(stream);
        var pixels = await decoder.GetPixelDataAsync();
        var bytes = pixels.DetachPixelData();
        return await ToBase64(bytes, (uint)decoder.PixelWidth, (uint)decoder.PixelHeight, decoder.DpiX, decoder.DpiY);
    }
    
    private async Task<string> ToBase64(RenderTargetBitmap bitmap)
    {
        var bytes = (await bitmap.GetPixelsAsync()).ToArray();
        return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
    }
    
    private async Task<string> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
    {
        // encode image
        var encoded = new InMemoryRandomAccessStream();
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
        await encoder.FlushAsync();
        encoded.Seek(0);
    
        // read bytes
        var bytes = new byte[encoded.Size];
        await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
    
        // create base64
        return Convert.ToBase64String(bytes);
    }
    
    private async Task<ImageSource> FromBase64(string base64)
    {
        // read stream
        var bytes = Convert.FromBase64String(base64);
        var image = bytes.AsBuffer().AsStream().AsRandomAccessStream();
    
        // decode image
        var decoder = await BitmapDecoder.CreateAsync(image);
        image.Seek(0);
    
        // create bitmap
        var output = new WriteableBitmap((int)decoder.PixelHeight, (int)decoder.PixelWidth);
        await output.SetSourceAsync(image);
        return output;
    }

    上面代码出处:https://codepaste.net/ijx28i

    从文件读 BitmapImage

            private async Task<BitmapImage> OpenBitmapImageFile(StorageFile file)
            {
                var fileStream = await file.OpenReadAsync();
                var bitmap = new BitmapImage();
                await bitmap.SetSourceAsync(fileStream);
                return bitmap;
            }

    BitmapImage 转 WriteableBitmap

    我使用http://www.cnblogs.com/cjw1115/p/5164327.html 大神的,直接转WriteableBitmap bitmap = imageSource as WriteableBitmap;bitmap为null,于是我在网上继续找,好像没看到 UWP 的可以转,只有win7的

    其实大神有说,Image的 Source是 WriteableBitmap ,于是他就能转。

    UWP的 BitmapImage 不能转换为 byte[] 或 WriteableBitmap 。这句话是错的。


    2017年1月4日21:45:37


    我后来过了几个月,发现我们的 BitmapImage 可以转 byte[]

    我们可以通过拿 BitmapImage 的 UriSource 把它转为 WriteableBitmap ,可以使用截图获得 BitmapImage。

    如果想要使用 BitmapImage 的 UriSource 转为 WriteableBitmap,需要 WriteableBitmapEx 。他是在 WPF 就被大家喜欢的库。如何安装 WriteableBitmapEx ,其实有了Nuget 基本没问题。

    搜索 WriteableBitmapEx Nuget

    然后搜索到了,我们要什么,好像我也不知道。

    我就知道可以使用 WriteableBitmap image = await BitmapFactory.New(1, 1).FromContent((BitmapImage).UriSource);

    那么转 byte[] 如何做,有了 WriteableBitmap ,下面的我也不知道,不要问我。

    如果使用 BitmapImage 图片是 SetSource,那么我也不会。

    获取图片中鼠标点击的颜色

    获取鼠标点击的那个点,图片的颜色。那么图片之外,界面呢?其实我们还可以把界面截图,然后获取。

    那么我们需要首先在 Image 使用 Tap ,假如图片 source 是 BitmapImage

    前提安装 WriteableBitmapEx ,假如我们的 ViewModel有一个 BitmapImage 的图片 Image ,于是我们可以使用

                var position = e.GetPosition(sender as UIElement); //鼠标点击的在哪
    
                WriteableBitmap image = await BitmapFactory.New(1, 1).FromContent((View.Image).UriSource); //我上面说的如何把 BitmapImage 转 WriteableBitmapEx
    
                var temp = image.GetPixel((int) position.X, (int) position.Y);
    
                string str = $"R: {temp.R} G: {temp.G} B: {temp.B} ";
    

    获得图片中鼠标点击的颜色。这个方法有时炸了,都是 255 。

    代码:https://github.com/lindexi/UWP/tree/master/uwp/src/ImageMoseClick

    获取Dpi

    可以使用下面代码获取图片DPI。

    我的图片从解决方案获得,大家可以从任意的位置获取,只要可以转换为 IRandomAccessStream

    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/lindexi.png"));
     using (IRandomAccessStream stream = await file.OpenReadAsync())
     {                
         BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, stream); 
         var DpiX = decoder.DpiX;
         var DpiY = decoder.DpiY;                 
     }
    

    如果需要保存网络图片到本地,请到win10 uwp 存放网络图片到本地

    参见:http://www.cnblogs.com/cjw1115/p/5164327.html

    http://www.cnblogs.com/yuanforprogram/p/4819307.html

    http://stackoverflow.com/questions/41439543/how-can-i-get-the-pixel-color-of-an-image-at-the-current-pointer-position-in-a-u

    http://lindexi.oschina.io/lindexi/post/win10-uwp-%E8%AF%BB%E5%8F%96%E4%BF%9D%E5%AD%98WriteableBitmap-BitmapImage/

    http://www.cnblogs.com/mqxs/p/5707620.html

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/lindexi/p/7694403.html
Copyright © 2011-2022 走看看