重新想象 Windows 8 Store Apps 之 图片处理: 显示图片; 图片的 9 切片; WriteableBitmap; 获取和修改图片属性; 对图片文件做“缩放/旋转/编码”操作,并保存操作后的结果



重新想象 Windows 8 Store Apps (29) - 图片处理


作者:webabcd



介绍

重新想象 Windows 8 Store Apps 之 图片处理


  • 显示图片
  • 图片的 9 切片
  • WriteableBitmap
  • 获取和修改图片属性
  • 对图片文件做“缩放/旋转/编码”操作,并保存操作后的结果


示例

1、演示最基础的图片显示

Image/Display.xaml


<Page     x:Class="XamlDemo.Image.Display"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Image"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0" Orientation="Horizontal" VerticalAlignment="Top">              <Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">                 <Image Source="/Assets/Logo.png" Stretch="Uniform" Width="200" Height="100" />             </Border>              <Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">                 <Image Source="ms-appx:///Assets/Logo.png" Stretch="Uniform" Width="200" Height="100" />             </Border>              <Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">                 <Image x:Name="img" Stretch="Uniform" Width="200" Height="100" />             </Border>              <Border BorderBrush="Red" BorderThickness="1" Width="200" Height="100" Margin="20 0 0 0">                 <Image x:Name="img2" Stretch="Uniform" Width="200" Height="100" />             </Border>          </StackPanel>     </Grid> </Page>


Image/Display.xaml.cs


/*  * 演示最基础的图片显示  *   * 注:  * 1、引用 package 中的图片用:ms-appx:///  * 2、引用 ApplicationData 中的图片:  *    a) LocalFolder 对应 ms-appdata:///local/  *    b) RoamingFolder 对应 ms-appdata:///roaming/  *    c) TemporaryFolder 对应 ms-appdata:///temp/  */  using System; using Windows.Storage.Streams; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Navigation;  namespace XamlDemo.Image {     public sealed partial class Display : Page     {         public Display()         {             this.InitializeComponent();         }          protected async override void OnNavigatedTo(NavigationEventArgs e)         {             // code-behind 指定图片源             img.Source = new BitmapImage(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute));               // code-behind 指定图片源             RandomAccessStreamReference imageStreamRef = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute));             IRandomAccessStream imageStream = await imageStreamRef.OpenReadAsync();             BitmapImage bitmapImage = new BitmapImage();             bitmapImage.SetSource(imageStream);             img2.Source = bitmapImage;         }     } }


2、演示图片的 NineGrid

Image/NineGrid.xaml


<Page     x:Class="XamlDemo.Image.NineGrid"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Image"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0" Orientation="Horizontal" VerticalAlignment="Top">              <!--                 Image - 图片控件                     NineGrid - 指定9网格(相当于flash中的9切片)中的4条线,Thickness 类型                         Left - 左边的线相对于图片最左端的距离                         Top - 上边的线相对于图片最顶端的距离                         Right - 右边的线相对于图片最右端的距离                         Bottom - 下边的线相对于图片最底端的距离                              以下示例图片的原始大小为 16 * 16             -->              <Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200" />              <!--通过指定9切片,防止边框被放大或缩小-->             <Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200" NineGrid="1 1 1 1" Margin="20 0 0 0" />          </StackPanel>     </Grid> </Page>


3、演示 WriteableBitmap 的应用

Image/WriteableBitmapDemo.xaml


<Page     x:Class="XamlDemo.Image.WriteableBitmapDemo"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Image"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0">                          <Image x:Name="img" Width="300" Height="300" HorizontalAlignment="Left" />              <Button x:Name="btnLoadImage" Content="load image" Margin="0 10 0 0" Click="btnLoadImage_Click_1" />              <Button x:Name="btnChangePixel" Content="加载一个图片并修改其中的像素的颜色值" Margin="0 10 0 0" Click="btnChangePixel_Click_1" />              <Button x:Name="btnCreatePixel" Content="创建一个图片,设置其每个像素的颜色值" Margin="0 10 0 0" Click="btnCreatePixel_Click_1" />          </StackPanel>     </Grid> </Page>


Image/WriteableBitmapDemo.xaml.cs


/*  * 演示 WriteableBitmap 的应用  *   * 注:WriteableBitmap 使用的是 BGRA 格式  */  using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; using System; using System.IO; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Graphics.Imaging; using Windows.Storage; using Windows.Storage.Streams;  namespace XamlDemo.Image {     public sealed partial class WriteableBitmapDemo : Page     {         public WriteableBitmapDemo()         {             this.InitializeComponent();         }           // 加载一个图片         private async void btnLoadImage_Click_1(object sender, RoutedEventArgs e)         {             // 实例化一个 300*300 的 WriteableBitmap,并将其作为 Image 控件的图片源             WriteableBitmap writeableBitmap = new WriteableBitmap(300, 300);             img.Source = writeableBitmap;              StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Logo.png"));             using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))             {                 // 设置 WriteableBitmap 对象的图片流                 await writeableBitmap.SetSourceAsync(fileStream);             }         }           // 加载一个图片并修改其中的像素的颜色值         private async void btnChangePixel_Click_1(object sender, RoutedEventArgs e)         {             // 实例化一个 300*300 的 WriteableBitmap,并将其作为 Image 控件的图片源             WriteableBitmap writeableBitmap = new WriteableBitmap(300, 300);             img.Source = writeableBitmap;              StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Logo.png"));             using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))             {                 // 将指定的图片转换成 BitmapDecoder 对象                 BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);                  // 通过 BitmapTransform 缩放图片的尺寸                 BitmapTransform transform = new BitmapTransform()                 {                     ScaledWidth = Convert.ToUInt32(writeableBitmap.PixelWidth),                     ScaledHeight = Convert.ToUInt32(writeableBitmap.PixelHeight)                 };                  // 获取图片的 PixelDataProvider 对象                 PixelDataProvider pixelData = await decoder.GetPixelDataAsync(                     BitmapPixelFormat.Bgra8,                     BitmapAlphaMode.Straight,                     transform,                     ExifOrientationMode.IgnoreExifOrientation,                      ColorManagementMode.DoNotColorManage);                  // 获取图片的像素数据,由于之前指定的格式是 BitmapPixelFormat.Bgra8,所以每一个像素由 4 个字节组成,分别是 bgra                 byte[] sourcePixels = pixelData.DetachPixelData();                 for (int i = 0; i < sourcePixels.Length; i++)                 {                    sourcePixels[i] -= 10;                 }                  // 将修改后的像素数据写入 WriteableBitmap 对象的像素缓冲区(WriteableBitmap 使用的是 BGRA 格式)                 using (Stream stream = writeableBitmap.PixelBuffer.AsStream()) // IBuffer.AsStream() 为来自 System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions 中的扩展方法                 {                     await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length);                 }             }              // 用像素缓冲区的数据绘制图片             writeableBitmap.Invalidate();         }                   // 创建一个图片,设置其每个像素的颜色值         private async void btnCreatePixel_Click_1(object sender, RoutedEventArgs e)         {             // 实例化一个 300*300 的 WriteableBitmap,并将其作为 Image 控件的图片源             WriteableBitmap writeableBitmap = new WriteableBitmap(300, 300);             img.Source = writeableBitmap;              Random random = new Random();              // 设置需要绘制的图片的像素数据(每一个像素由 4 个字节组成,分别是 bgra)             byte[] result = new byte[300 * 300 * 4];             for (int i = 0; i < result.Length; )             {                 result[i++] = (byte)random.Next(0, 256); // Green                 result[i++] = (byte)random.Next(0, 256); // Blue                 result[i++] = (byte)random.Next(0, 256); // Red                 result[i++] = 255; // Alpha             }              // 将像素数据写入 WriteableBitmap 对象的像素缓冲区             using (Stream stream = writeableBitmap.PixelBuffer.AsStream())             {                 await stream.WriteAsync(result, 0, result.Length);             }              // 用像素缓冲区的数据绘制图片             writeableBitmap.Invalidate();         }     } }


4、演示如何获取、修改图片属性

Image/ImageProperty.xaml.cs


/*  * 演示如何获取、修改图片属性  */  using System; using System.Threading.Tasks; using Windows.Storage; using Windows.Storage.FileProperties; using Windows.Storage.Pickers; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; using XamlDemo.Common;  namespace XamlDemo.Image {     public sealed partial class ImageProperty : Page     {         public ImageProperty()         {             this.InitializeComponent();         }          protected async override void OnNavigatedTo(NavigationEventArgs e)         {             if (Helper.EnsureUnsnapped())             {                 // 选择一个图片文件                 FileOpenPicker picker = new FileOpenPicker();                 picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;                 picker.FileTypeFilter.Add(".jpg");                 picker.FileTypeFilter.Add(".png");                  StorageFile file = await picker.PickSingleFileAsync();                  if (file != null)                 {                     ImageProperties imageProperties = await GetImageProperty(file);                     UpdateImageProperty(imageProperties);                 }             }         }          // 获取图片属性         private async Task<ImageProperties> GetImageProperty(StorageFile file)         {             // 获取图片文件的图片属性信息             ImageProperties imageProperties = await file.Properties.GetImagePropertiesAsync();              // 显示图片文件的图片属性(以下试举几例,不全)             lblMsg.Text = "title: " + imageProperties.Title;             lblMsg.Text += Environment.NewLine;             lblMsg.Text += "keywords: " + string.Join(",", imageProperties.Keywords);             lblMsg.Text += Environment.NewLine;             lblMsg.Text += "width: " + imageProperties.Width;             lblMsg.Text += Environment.NewLine;             lblMsg.Text += "height: " + imageProperties.Height;             lblMsg.Text += Environment.NewLine;              return imageProperties;         }          // 更新图片属性         private async void UpdateImageProperty(ImageProperties imageProperties)         {             Random random = new Random();              // 设置图片文件的图片属性(以下试举几例,不全)             imageProperties.Title = random.Next(0, 1000).ToString();             imageProperties.Keywords.Clear();             imageProperties.Keywords.Add(random.Next(0, 1000).ToString());             imageProperties.Keywords.Add(random.Next(0, 1000).ToString());              try             {                 // 保存图片文件的图片属性信息                 await imageProperties.SavePropertiesAsync();                 lblMsg.Text += "title 和 keywords 已被修改,重新进来可看效果";             }             catch (Exception ex)             {                 lblMsg.Text = ex.ToString();             }         }     } }


5、演示如何对图片文件做“缩放/旋转/编码”操作,并保存操作后的结果

Image/ImageTransform.xaml


<Page     x:Class="XamlDemo.Image.ImageTransform"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Image"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0">              <Image x:Name="imgOriginal" Stretch="Uniform" Width="300" Height="200" HorizontalAlignment="Left" />              <Image x:Name="imgTransformed" Stretch="Uniform" Width="300" Height="200" HorizontalAlignment="Left" Margin="0 10 0 0" />          </StackPanel>     </Grid> </Page>


Image/ImageTransform.xaml.cs


/*  * 演示如何对图片文件做“缩放/旋转/编码”操作,并保存操作后的结果  */  using System; using Windows.Graphics.Imaging; using Windows.Storage; using Windows.Storage.Pickers; using Windows.Storage.Streams; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Navigation; using XamlDemo.Common;  namespace XamlDemo.Image {     public sealed partial class ImageTransform : Page     {         public ImageTransform()         {             this.InitializeComponent();         }          protected async override void OnNavigatedTo(NavigationEventArgs e)         {             if (Helper.EnsureUnsnapped())             {                 // 选择一个 .jpg 图片文件                 FileOpenPicker picker = new FileOpenPicker();                 picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;                 picker.FileTypeFilter.Add(".jpg");                  StorageFile fileRead = await picker.PickSingleFileAsync();                  if (fileRead != null)                 {                     // 显示用户选中的图片文件                     BitmapImage src = new BitmapImage();                     src.SetSource(await fileRead.OpenAsync(FileAccessMode.Read));                     imgOriginal.Source = src;                       // 定义一个转换后的图片文件                     StorageFile fileWrite = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(@"webabcdTest\imageTransformDemo.png", CreationCollisionOption.ReplaceExisting);                       using (IRandomAccessStream inputStream = await fileRead.OpenAsync(FileAccessMode.Read), outputStream = await fileWrite.OpenAsync(FileAccessMode.ReadWrite))                     {                         // 将用户选择的图片文件转换为一个 BitmapDecoder 对象                         BitmapDecoder decoder = await BitmapDecoder.CreateAsync(inputStream);                          // 通过 BitmapTransform 来配置图片的宽度、高度和顺时针旋转角度                         BitmapTransform transform = new BitmapTransform();                         transform.ScaledWidth = 100;                         transform.ScaledHeight = 100;                         transform.Rotation = BitmapRotation.Clockwise180Degrees;                          // 获取图片的 PixelDataProvider 对象                         PixelDataProvider pixelProvider = await decoder.GetPixelDataAsync(                             decoder.BitmapPixelFormat,                             decoder.BitmapAlphaMode,                             transform,                             ExifOrientationMode.RespectExifOrientation,                             ColorManagementMode.ColorManageToSRgb                         );                          // 获取经过了 BitmapTransform 转换后的图片的像素数据                         byte[] pixels = pixelProvider.DetachPixelData();                          // 创建一个 BitmapEncoder 对象,可以指定图片的编码格式(PngEncoderId, JpegEncoderId, JpegXREncoderId, GifEncoderId, TiffEncoderId)                         BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);                          // 转码像素数据到指定的图片编码格式(本例会转吗为 png 格式),并将转码后的数据写入 stream 缓冲区                         encoder.SetPixelData(                             decoder.BitmapPixelFormat,                             decoder.BitmapAlphaMode,                             100,                             100,                             decoder.DpiX,                             decoder.DpiY,                             pixels                         );                          // 提交 stream 缓冲区中的所有内容                         await encoder.FlushAsync();                     }                      // 显示经过“缩放/旋转/编码”操作后的图片文件                     imgTransformed.Source = new BitmapImage(new Uri("ms-appdata:///temp/webabcdTest/imageTransformDemo.png", UriKind.Absolute));                 }             }         }     } }



OK