MetroApp保存UIEment为图片

  写本文的起因是想截取Metro App画面作为图片来使用Win8的共享。

  话说自从大MS的客户端UI技术进入XAML时代之后,每次截屏的代码都不太一样,无论silverlight、WPF还是Windows Phone都不完全一样,搞得我头昏脑胀,每次都要搜索一下才写的出来。反观Winform许久未写,如何截屏我还记得一清二楚……真是尴尬……顺带吐槽Metro的各种奇葩Stream类,那跟.NET的Stream类互转那叫一个惨烈和别扭啊。

  花开两头,各表一枝。接下来我们进入今天的正题——如何在Metro下截屏,我再吐槽一下MS,这个截屏用的API似乎Win8.1才开放,还在用Win8的话还是撸撸睡吧……

  首先我们要用到一个奇葩类,这次真的不是WriteableBitmap了,这次的主角是叫做RenderTargetBitmap。

            var bitmap = new RenderTargetBitmap();
            await bitmap.RenderAsync(this.rootGrid);
            IBuffer buffer = await bitmap.GetPixelsAsync();
            var stream = buffer.AsStream();

  要想转换UIElement到Stream,通过以上几步就可以了,this.rootGrid是一个UIElement控件,也就是我想保存的图像。值得一提的是AsStream是一个扩展方法,记得要添加namespace System.Runtime.InteropServices.WindowsRuntime哟!

  如果是WPF应用,得到Stream之后存为图片文件是很容易的事情了,分分钟秒杀的程度,问题Metro下面还需要再折腾折腾……

  首先你需要创建一个StorageFile来存放这个图片,一个比较容易的方式是使用FileSavePicker。

            FileSavePicker savePicker = new FileSavePicker();
            savePicker.SuggestedStartLocation = PickerLocationId.Desktop;
            savePicker.FileTypeChoices.Add("Bitmap", new List<string>() { ".png" });
            savePicker.SuggestedFileName = "New Bitmap";

            StorageFile savedItem = await savePicker.PickSaveFileAsync();

  接下来你可能会想StorageFile也有了,Stream也有了,应该往StorageFile里写Stream就行了。

  可惜不是,直接使用FileIO.WriteBufferAsync的方法来写入图片文件是不行的。文件会无法作为图片正常显示。

  我们需要使用BitmapEncoder来写入Stream,而WinRT下的这个BitmapEncoder,又需要WinRT的IRandomAccessStream才能使用。

                Guid encoderId = BitmapEncoder.PngEncoderId;
                IRandomAccessStream fileStream = await savedItem.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
                BitmapEncoder encoder = await BitmapEncoder.CreateAsync(encoderId, fileStream);
                byte[] pixels = new byte[pixelStream.Length];
                pixelStream.Read(pixels, 0, pixels.Length);

                //pixal format shouldconvert to rgba8
                for (int i = 0; i < pixels.Length; i += 4)
                {
                    byte temp = pixels[i];
                    pixels[i] = pixels[i + 2];
                    pixels[i + 2] = temp;
                }

                encoder.SetPixelData(
                 BitmapPixelFormat.Rgba8,
                 BitmapAlphaMode.Straight,
                 (uint)bitmap.PixelWidth,
                 (uint)bitmap.PixelHeight,
                 96, // Horizontal DPI
                 96, // Vertical DPI
                 pixels);

                await encoder.FlushAsync();

  本篇我们简单讨论了如何在MetroApp下截屏保存图片,下篇会根据本篇的成果来讨论一下Win8.1如何共享截屏的图片。同时会简单的提到.NET的Stream和WinRT的Stream的转换。

代码下载

本篇的参考资料:

Windows 8.1 Apps with XAML and C# Unleashed

  这本书是Google搜索出了某个章节正好提到了RenderTargetBitmap,这会貌似又打不开了,感谢方校长八辈祖宗!这书出中文版了可以买一本!

Win8 Metro(C#) 数字图像处理--图像打开,保存 

  图片文件BitmapEncoder是学习自这位仁兄的文章!

韦恩卑鄙

  该参考资料明确指出了直接FileIO.WriteBufferAsync写入是不行的。

 

posted @ 2014-02-19 22:24  楼上那个蜀黍  阅读(1670)  评论(3编辑  收藏  举报