首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Windows 8 影像處理全攻略:顯示、九宮格、WriteableBitmap、屬性編輯與轉碼

     編輯:關於.NET

前言

影像是現代應用程式不可或缺的元素。Windows 8 提供豐富的影像 API:Image 控制項基礎顯示、九宮格 (NineGrid) 保護邊框不變形、WriteableBitmap 像素級操作、ImageProperties 讀寫中繼資料、BitmapDecoder/Encoder/Transform 進行縮放、旋轉、格式轉換。本文將逐一實作演示。

一、基礎影像顯示

支援三種 URI 配置:ms-appx:/// (應用程式封裝)、ms-appdata:///local|roaming|temp/ (應用程式資料)、http(s):// (網路)。程式碼可透過 BitmapImage 直接指定 URI,或開啟串流後 SetSourceAsync。

XAML

<Page x:Class="XamlDemo.Image.Display" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Image" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>

程式碼後置

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)
        {
            img.Source = new BitmapImage(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute));
            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;
        }
    }
}

二、九宮格

NineGrid 屬性接受 Thickness (左、上、右、下),定義四條分割線,保護邊框區域不被拉伸,類似 9-slice scaling。範例使用 16x16 的邊框圖片,設定 NineGrid="1 1 1 1" 後放大至 200x200 仍保持邊框銳利。

XAML

<Page x:Class="XamlDemo.Image.NineGrid" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Image" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<Grid Background="Transparent">
<StackPanel Margin="120 0 0 0" Orientation="Horizontal" VerticalAlignment="Top">
<Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200" />
<Image Source="/Assets/NineGrid/Demo.png" Width="200" Height="200" NineGrid="1 1 1 1" Margin="20 0 0 0" />
</StackPanel>
</Grid>
</Page>

三、WriteableBitmap 像素級操作

WriteableBitmap 使用 BGRA 格式 (每像素 4 位元組)。三大核心場景:

  1. 載入現有圖片:SetSourceAsync。
  2. 修改像素:解碼為 PixelDataProvider -> 取得位元組陣列 -> 修改 -> 寫入 PixelBuffer.AsStream() -> Invalidate() 重繪。
  3. 純建立像素:直接產生位元組陣列 -> 寫入緩衝區 -> Invalidate()。

XAML

<Page x:Class="XamlDemo.Image.WriteableBitmapDemo" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Image" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>

程式碼後置

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)
        {
            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))
            {
                await writeableBitmap.SetSourceAsync(fileStream);
            }
        }

        private async void btnChangePixel_Click_1(object sender, RoutedEventArgs e)
        {
            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 decoder = await BitmapDecoder.CreateAsync(fileStream);
                BitmapTransform transform = new BitmapTransform()
                {
                    ScaledWidth = Convert.ToUInt32(writeableBitmap.PixelWidth),
                    ScaledHeight = Convert.ToUInt32(writeableBitmap.PixelHeight)
                };
                PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
                    BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, transform,
                    ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
                byte[] sourcePixels = pixelData.DetachPixelData();
                for (int i = 0; i < sourcePixels.Length; i++)
                {
                    sourcePixels[i] -= 10;
                }
                using (Stream stream = writeableBitmap.PixelBuffer.AsStream())
                {
                    await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length);
                }
            }
            writeableBitmap.Invalidate();
        }

        private async void btnCreatePixel_Click_1(object sender, RoutedEventArgs e)
        {
            WriteableBitmap writeableBitmap = new WriteableBitmap(300, 300);
            img.Source = writeableBitmap;
            Random random = new Random();
            byte[] result = new byte[300 * 300 * 4];
            for (int i = 0; i < result.Length; )
            {
                result[i++] = (byte)random.Next(0, 256);
                result[i++] = (byte)random.Next(0, 256);
                result[i++] = (byte)random.Next(0, 256);
                result[i++] = 255;
            }
            using (Stream stream = writeableBitmap.PixelBuffer.AsStream())
            {
                await stream.WriteAsync(result, 0, result.Length);
            }
            writeableBitmap.Invalidate();
        }
    }
}

四、讀取與修改影像屬性

StorageFile.Properties.GetImagePropertiesAsync() 取得 ImageProperties,可讀寫標題、關鍵字、寬度、高度、拍攝時間、GPS、相機廠牌等 EXIF/XMP 資訊。修改後呼叫 SavePropertiesAsync() 持久化。

程式碼後置

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();
            }
        }
    }
}

五、影像縮放、旋轉、編碼轉檔

流程:BitmapDecoder.CreateAsync 解碼來源 -> BitmapTransform 設定目標寬高、旋轉角度 -> GetPixelDataAsync 取得轉換後像素 -> BitmapEncoder.CreateAsync 指定目標格式 (PNG/JPEG/JPEG-XR/GIF/TIFF) -> SetPixelData 寫入像素 -> FlushAsync 完成。範例將 JPG 縮放為 100x100、旋轉 180 度、轉存為 PNG。

XAML

<Page x:Class="XamlDemo.Image.ImageTransform" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Image" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>

程式碼後置

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())
            {
                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 decoder = await BitmapDecoder.CreateAsync(inputStream);
                        BitmapTransform transform = new BitmapTransform();
                        transform.ScaledWidth = 100;
                        transform.ScaledHeight = 100;
                        transform.Rotation = BitmapRotation.Clockwise180Degrees;
                        PixelDataProvider pixelProvider = await decoder.GetPixelDataAsync(
                            decoder.BitmapPixelFormat, decoder.BitmapAlphaMode, transform,
                            ExifOrientationMode.RespectExifOrientation, ColorManagementMode.ColorManageToSRgb);
                        byte[] pixels = pixelProvider.DetachPixelData();
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);
                        encoder.SetPixelData(
                            decoder.BitmapPixelFormat, decoder.BitmapAlphaMode,
                            100, 100, decoder.DpiX, decoder.DpiY, pixels);
                        await encoder.FlushAsync();
                    }
                    imgTransformed.Source = new BitmapImage(new Uri("ms-appdata:///temp/webabcdTest/imageTransformDemo.png", UriKind.Absolute));
                }
            }
        }
    }
}

總結

  • Image 控制項支援多種 URI 配置,靈活引用封裝、應用程式資料、網路圖片。
  • NineGrid 是 UI 邊框圖片不變形的利器。
  • WriteableBitmap 提供像素級完全控制,適合濾鏡、繪圖、動態生成圖片。
  • ImageProperties 讓應用程式能讀寫豐富的影像中繼資料。
  • BitmapDecoder/Transform/Encoder 管線化處理縮放、旋轉、格式轉換,效能高且保真度好。

[原始碼下載]:https://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved