42、XAML Images
1、Displaying images :
在 xaml 中引用程序包中的图片的方法 :
<Image Source="Assets/image1.jpg" Height="200" />
2、Images from a file stream:
本实例演示用户通过 File Picker 选择图片,并且进行编码解析。
操作截图:
原始图片:
经过解析:
页面的 XAML :
<!--高度--> <TextBox x:Name="Scenario2DecodePixelHeight" Width="100" Text="100" HorizontalAlignment="Left" /> <!--宽度--> <TextBox x:Name="Scenario2DecodePixelWidth" Width="100" Text="100" HorizontalAlignment="Left" /> <!-- 点击打开 FileOpenPicker. --> <Button x:Name="Scenario2Button1" Content="Select image..." Click = “Scenario2Button1_Click”/>
<!--显示结果--> <Image x:Name="Scenario2Image" Stretch="None" />
相应的 C# :
按钮的单击事件:
async void Scenario2Button1_Click(object sender, RoutedEventArgs e) { int decodePixelHeight; int decodePixelWidth; if (!int.TryParse(Scenario2DecodePixelHeight.Text, out decodePixelHeight)) { Scenario2DecodePixelHeight.Text = "100"; decodePixelHeight = 100; } if (!int.TryParse(Scenario2DecodePixelWidth.Text, out decodePixelWidth)) { Scenario2DecodePixelWidth.Text = "100"; decodePixelWidth = 100; } FileOpenPicker open = new FileOpenPicker(); open.SuggestedStartLocation = PickerLocationId.PicturesLibrary; open.ViewMode = PickerViewMode.Thumbnail; // Filter to include a sample subset of file types open.FileTypeFilter.Clear(); open.FileTypeFilter.Add(".bmp"); open.FileTypeFilter.Add(".png"); open.FileTypeFilter.Add(".jpeg"); open.FileTypeFilter.Add(".jpg"); StorageFile file = await open.PickSingleFileAsync(); if (file != null) { using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) { BitmapImage bitmapImage = new BitmapImage(); //获取或设置要用于图像编码操作的高度。 bitmapImage.DecodePixelHeight = decodePixelHeight; bitmapImage.DecodePixelWidth = decodePixelWidth; await bitmapImage.SetSourceAsync(fileStream); Scenario2Image.Source = bitmapImage; } } }
3、Displaying a NineGrid image :
下面的实例展示了怎样使用 NineGrid margins 显示一个图片。
第一张图片是原始图片(8x7 像素)。第二张是把原图片放大到 100x200 的图片。第三张图片是放大到 100x200 并且指定
了 3 像素的 NineGrid margins 。这些控件使用拉伸边缘和边角的行为。
NineGrid 属性: 获取或设置控制图像大小调整方式的九格形式的值。
显示截图 :
相应的 xaml :
<Image Source="Assets/NineGridSource.png" Stretch="None" /> <Image Source="Assets/NineGridSource.png"/> <!--NineGrid : 获取或设置控制图像大小调整方式的九格形式的值。--> <Image Source="Assets/NineGridSource.png" NineGrid="3,3,3,3"/>
4、Using a WriteableBitmap :
下面的演示展示了如何直接操作 WriteableBitmap 对象的像素点。
首先在 XAML 页面中,放置三个按钮 和 一个显示图片操作结果的容器 :
<!--异步绘制曼德尔勃特集合,并且将结果显示在下面的 WriteableBitmap 中。--> <Button Content="Draw Mandelbrot set" Click="DrawMandelbrotSet_Click" /> <!--加载一个选取的图片,并使用 SetSource 方法将其显示在 WriteableBitmap 中--> <Button x:Name="Scenario4SetSourceButton" Content="Load image using SetSource" Click="LoadImageUsingSetSource_Click" /> <!--加载一个选择的图片,并使用 BitmapDecoder 解码像素并复制到 WriteableBitmap 中。--> <Button x:Name="Scenario4LoadImageButton" Content="Load image using PixelBuffer" Click="LoadImageUsingPixelBuffer_Click" />
显示结果的容器:
<Viewbox Width="400" Height="300" x:Name="Scenario4ImageContainer"> <Image x:Name="Scenario4Image" /> </Viewbox>
在相应的 C# 中,定义一个全局的 WriteableBitmap:
//下面的操作都是用这个对象 private WriteableBitmap Scenario4WriteableBitmap;
在页面的构造函数中,使用 Image 控件的容器 Scenario4ImageContainer 控件的尺寸初始化这个对象:
Scenario4WriteableBitmap = new WriteableBitmap((int)Scenario4ImageContainer.Width, (int)Scenario4ImageContainer.Height); Scenario4Image.Source = Scenario4WriteableBitmap;
第一个按钮的单击事件:
private async void DrawMandelbrotSet_Click(object sender, RoutedEventArgs e) { int pixelWidth = Scenario4WriteableBitmap.PixelWidth; int pixelHeight = Scenario4WriteableBitmap.PixelHeight; // 在一个后台线程中异步绘制 曼德尔勃特集 byte[] result = null; await ThreadPool.RunAsync(new WorkItemHandler( (IAsyncAction action) => { result = DrawMandelbrotGraph(pixelWidth, pixelHeight); } )); // 打开一个流,用来复制图片到 WriteableBitmap的 像素缓冲区 using (Stream stream = Scenario4WriteableBitmap.PixelBuffer.AsStream()) { await stream.WriteAsync(result, 0, result.Length); } // 绘制 WriteableBitmap Scenario4WriteableBitmap.Invalidate(); //请求绘制或重绘整个位图。 } private byte[] DrawMandelbrotGraph(int width, int height) { //每个像素需要 4 字节 byte[] result = new byte[width * height * 4]; int resultIndex = 0; // 当测试时,最大次数的迭代,来判断一个点是否在这个集中 int maxIterationCount = 50; // 选择间隔 //Complex : 表示一个复数。 Complex minimum = new Complex(-2.5, -1.0); Complex maximum = new Complex(1.0, 1); // Normalize x and y values based on chosen interval and size of WriteableBitmap double xScaleFactor = (maximum.Real - minimum.Real) / width; double yScaleFactor = (maximum.Imaginary - minimum.Imaginary) / height; //在 xy 平面绘制 曼德尔勃特集 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Complex c = new Complex(minimum.Real + x * xScaleFactor, maximum.Imaginary - y * yScaleFactor); Complex z = new Complex(c.Real, c.Imaginary); //用简单的逃逸时间算法进行迭代 int iteration = 0; while (z.Magnitude < 2 && iteration < maxIterationCount) { z = (z * z) + c; iteration++; } // 基于概率的设置像素的阴影 byte grayScaleValue = Convert.ToByte(255 - 255.0 * iteration / maxIterationCount); result[resultIndex++] = grayScaleValue; // Green value of pixel result[resultIndex++] = grayScaleValue; // Blue value of pixel result[resultIndex++] = grayScaleValue; // Red value of pixel result[resultIndex++] = 255; // Alpha value of pixel } } return result; }
显示结果 :
第二个按钮的 单击事件:
//用户选取文件后,通过 SetSource() 方法进行赋值 private async void LoadImageUsingSetSource_Click(object sender, RoutedEventArgs e) { FileOpenPicker picker = new FileOpenPicker(); picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; picker.FileTypeFilter.Add(".png"); picker.FileTypeFilter.Add(".jpeg"); picker.FileTypeFilter.Add(".jpg"); picker.FileTypeFilter.Add(".bmp"); StorageFile file = await picker.PickSingleFileAsync(); if (file != null) { using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) { try { await Scenario4WriteableBitmap.SetSourceAsync(fileStream); } catch (TaskCanceledException) { // 如果用户重复点击按钮,从而设置 WriteableBitmap 对象的 Source 属性的操作失败 } } } }
显示截图:
第三个按钮的 单击事件:
private async void LoadImageUsingPixelBuffer_Click(object sender, RoutedEventArgs e) { //这个方法通过把一张图片编码到一个 byte 流中,然后加载到 //WriteableBitmap 中,并且把结果复制到一个 WriteableBitmap 的 //像素的 buffer(缓冲区) 中 FileOpenPicker picker = new FileOpenPicker(); picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; picker.FileTypeFilter.Add(".png"); picker.FileTypeFilter.Add(".jpeg"); picker.FileTypeFilter.Add(".jpg"); picker.FileTypeFilter.Add(".bmp"); StorageFile file = await picker.PickSingleFileAsync(); if (file != null) { using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) { // 异步创建新的 BitmapDecoder 并使用流将其初始化。 BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// 缩放图像到大小适当的尺寸 // 包含可应用于像素或位图数据的转换集。 BitmapTransform transform = new BitmapTransform() {
//指定任何转换缩略图的高度(以像素为单位)。 ScaledWidth = Convert.ToUInt32(Scenario4WriteableBitmap.PixelWidth), ScaledHeight = Convert.ToUInt32(Scenario4WriteableBitmap.PixelHeight)}; //使用指定参数异步请求帧的像素数据。 PixelDataProvider pixelData = await decoder.GetPixelDataAsync( BitmapPixelFormat.Bgra8, // WriteableBitmap 使用 BGRA 格式 BitmapAlphaMode.Straight, transform, // EXIF 方向标志被忽略。未执行旋转或翻转操作。 //This sample ignores Exif orientation ExifOrientationMode.IgnoreExifOrientation, // 未执行颜色管理 ColorManagementMode.DoNotColorManage); // 一个包含图像解码数据的数组,可以在显示之前修改 //返回内部存储的像素数据。 byte[] sourcePixels = pixelData.DetachPixelData(); // 打开一个流,并将图像的内容复制到 WriteableBitmap 的像素缓冲区中 using (Stream stream = Scenario4WriteableBitmap.PixelBuffer.AsStream()) { //将字节序列异步写入当前流,并将流的当前位置向前移动写入的字节数。 await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length); } } // 重新绘制这个 WriteableBitmap 对象 //请求绘制或重绘整个位图。 Scenario4WriteableBitmap.Invalidate(); } }
显示结果和 上一个方法的结果相同。