高像素的图片,比如分辨率为 7712x4352 的照片,当加载到一个 bitmap 中时会占用相当大的内存。
每个像素会占用 4个字节的内存,所以当没有被压缩时,全部的图片会占用 12800万字节(约122MB)。高像素
图片的另一个问题就是渲染,因为图片不适合windows phone 8 的最大纹理尺寸为 4096x4096 像素,所以
它会被裁切。无论怎样,因为有很多方法来处理高像素图片,所以没有什么好担心的。
显示捕获的照片
首先,把一个 Image 控件放到页面中,用来显示预览:
<!-- 取景框 --> <phone:PhoneApplicationPage x:Class="PreviewPage" ... > <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid x:Name="ContentPanel"> <Image x:Name="PreviewImage"/> </Grid> </Grid> </phone:PhoneApplicationPage>
然后,在 C# 页面我们可以用 BitmapImage 的 intDecodePixelWidth和 int DecodePixelHeight 属性来初始化
通过void BitmapImage.SetSource(Stream streamSource) 方法调用加载的 JPEG 的数据流 bitmap 的尺寸。
为了知道 stream 中时一个横向的 或者 纵向的照片,你可以使用 Nokia Imaging SDK 中的ImageProviderInfo。
using Nokia.Graphics.Imaging; using System.Runtime.InteropServices.WindowsRuntime; ... public partial class PreviewPage : PhoneApplicationPage { ... private BitmapImage _bitmap = new BitmapImage(); public PreviewPage() { InitializeComponent(); PreviewImage.Source = _bitmap; ... } ... private void InitializePreview(Stream stream) { // 使用 Nokia Imaging SDK 找出 image 的 orientation 属性,
//并且相应地设置 BitmapImage 解码选项 stream.Position = 0; using (StreamImageSource source = new StreamImageSource(stream)) { ImageProviderInfo info = null; Task.Run(async () => { info = await source.GetInfoAsync(); }).Wait(); if (info.ImageSize.Width >= info.ImageSize.Height) { _bitmap.DecodePixelWidth = 1536; _bitmap.DecodePixelHeight = 0; } else { _bitmap.DecodePixelWidth = 0; _bitmap.DecodePixelHeight = 1536; } // 把 stream 设置为 bitmap 的源 stream.Position = 0; _bitmap.SetSource(stream); } } ... }
可以注意到通常你从平台 APIs 中得到的照片数据是一个 Stream,然后在 Nokia Imaging SDK 中通常采用 IBuffers.
通过下面的方法你可以进行方便的类型转换:
using System.Runtime.InteropServices.WindowsRuntime; // MemoryStream 的扩展方法命名空间 ... public class Utilities { ... /// <summary> /// 把 Stream 转换为 IBuffer 对象
/// <param name="stream">stream源</param> /// <returns>包含stream数据的IBuffer 对象</returns> /// </summary> public static IBuffer StreamToBuffer(Stream stream) { var memoryStream = stream as MemoryStream; if (memoryStream == null) { using (memoryStream = new MemoryStream()) { stream.Position = 0; stream.CopyTo(memoryStream); try { // 一些流类型不支持 stream.Flush(); } catch (Exception ex) { } return memoryStream.GetWindowsRuntimeBuffer(); } } else { return memoryStream.GetWindowsRuntimeBuffer(); } } /// <summary> /// 把 IBuffer 对象转换为 stream /// <param name="stream">buffer源</param> /// <returns>stream</returns> /// </summary> public static Stream BufferToStream(IBuffer buffer) { return buffer.AsStream(); } ... }
手动缩小图片的尺寸
实现的方式除了使用 BitmapImage 外,你也可以使用 Nokia Imaging SDK 方便的实现图片的缩小。Nokia Imaging SDK
可以让你指定比如 buffer 的最大的 size(bytes) 和 图片的最大 size(pixels) 来进行操作,并且为你提供了一个新的 data stream
从而你也可以用于其他的目的,而不仅仅把缩小的图片显示到屏幕中——比如保存和分享。
using Nokia.Graphics.Imaging; ... public class Utilities { ... /// <summary> /// 异步压缩一个 image 并且最终 JPEG 数据在字节上不会超过 maxBytes,并且在尺寸上不会超过指定的 maxSize. /// <param name="image">压缩的 Image</param> /// <param name="maxBytes">缓冲区最大字节大小</param> /// <param name="maxSize">压缩的最大图片的像素</param> /// <returns>返回压缩后的 JPEG数据缓冲区 </returns> /// </summary> private static async Task<IBuffer> ScaleAsync(IBuffer image, uint maxBytes, Size maxSize) { using (var source = new BufferImageSource(image)) { var info = await source.GetInfoAsync(); if (info.ImageSize.Width * info.ImageSize.Height > maxSize) { var resizeConfiguration = new AutoResizeConfiguration(maxBytes, maxSize, new Size(0, 0), AutoResizeMode.Automatic, 0, ColorSpace.Yuv420); return await Nokia.Graphics.Imaging.JpegTools.AutoResizeAsync(buffer, resizeConfiguration); } else { return image; } } } ... }
裁切高像素图片
显示高像素图片你可以创建各种 bitmaps 对象,更小或者等于 4096x4096 像素的最大纹理尺寸。
使用 Nokia Imaging SDK 去裁切高像素原图的各个部分是很容易的。
using Nokia.Graphics.Imaging; using Windows.Foundation; ... public class Utilities { ... /// <summary> /// 异步重构(裁切)照片,并且返回一个 JPEG data buffer
/// <param name="image">将要重构的照片</param> /// <param name="area">裁切的区域</param> /// <returns>处理后的 JPEG data buffer </returns> /// </summary> public static async Task<IBuffer> Reframe(IBuffer image, Rect area) { using (var source = new BufferImageSource(image)) using (var effect = new FilterEffect(source)) { effect.Filters = new List<IFilter>() { new ReframingFilter() { ReframingArea = area } }; using (var renderer = new JpegRenderer(effect)) { return await renderer.RenderAsync(); } } } /// <summary> /// 异步重构(裁切)照片并且把结果输出到指定的 bitmap 对象
/// <param name="image">将要重构的照片</param> /// <param name="area">重构的区域</param> /// <param name="bitmap">输出结果到 bitmap 对象</param> /// </summary> public static async Task Reframe(IBuffer image, Rect area, WriteableBitmap bitmap) { using (var source = new BufferImageSource(image)) using (var effect = new FilterEffect(source)) { effect.Filters = new List<IFilter>() { new ReframingFilter() { ReframingArea = area } }; using (var renderer = new WriteableBitmapRenderer(effect, bitmap)) { await renderer.RenderAsync(); } } } ... }
Nokia Wiki 原文链接:http://developer.nokia.com/Resources/Library/Lumia/#!imaging/working-with-high-resolution-photos/processing-photos.html