源项目地址:https://github.com/Microsoft/...
以下是把样例转换为简要说明,同时给出实际运行效果及关键代码剖析:
PhotoViewerDemo图片信息查询器
主要实现功能:
1 根据选定目录自动加载图片或缩略图,并显示选中图片的元素据信息
2 选中图片进行编辑、缩放、旋转、黑白变
3 对图片容器大小进行自动缩放
- 数据模型类
图片类
/// <summary>
/// This class describes a single photo - its location, the image and
/// the metadata extracted from the image.
/// </summary>
public class Photo
{
private readonly Uri _source;
public Photo(string path)
{
Source = path;
_source = new Uri(path);
Image = BitmapFrame.Create(_source);
Metadata = new ExifMetadata(_source);
}
public string Source { get; }
public BitmapFrame Image { get; set; }
public ExifMetadata Metadata { get; }
public override string ToString() => _source.ToString();
}
- 视图模型类
重新选择目录就更新图片集Update(),
/// <summary>
/// This class represents a collection of photos in a directory.
/// </summary>
public class PhotoCollection : ObservableCollection<Photo>
{
private DirectoryInfo _directory;
public PhotoCollection()
{
}
public PhotoCollection(string path) : this(new DirectoryInfo(path))
{
}
public PhotoCollection(DirectoryInfo directory)
{
_directory = directory;
Update();
}
public string Path
{
set
{
_directory = new DirectoryInfo(value);
Update();
}
get { return _directory.FullName; }
}
public DirectoryInfo Directory
{
set
{
_directory = value;
Update();
}
get { return _directory; }
}
private void Update()
{
Clear();
try
{
foreach (var f in _directory.GetFiles("*.jpg"))
Add(new Photo(f.FullName));
}
catch (DirectoryNotFoundException)
{
MessageBox.Show("No Such Directory");
}
}
}
- 视图界面xaml
ListBox缩略图阴影由一个Border的错位及阴影来制成效果
<!-- Drop Shadow -->
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="4"
Background="#44000000">
<Border.RenderTransform>
<TranslateTransform X="5" Y="5" />
</Border.RenderTransform>
<Border.BitmapEffect>
<BlurBitmapEffect Radius="8" />
</Border.BitmapEffect>
</Border>
缩略图绑定到BitmapFrame 关联的缩略图图像
缩略图绑定为位图元素据生成日期
<Image Source="{Binding Image.Thumbnail}" />
<Label Content="{Binding Metadata.DateImageTaken}">
ListBox的容器模板改为WrapPanel,缩放时自动排列其中内容,容器大小绑定到滑动条
<!-- Main photo catalog view -->
<Style TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle">
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<WrapPanel Margin="5" IsItemsHost="True" Orientation="Horizontal"
ItemHeight="{Binding ElementName=ZoomSlider, Path='Value'}"
ItemWidth="{Binding ElementName=ZoomSlider, Path='Value'}"
VerticalAlignment="Top" HorizontalAlignment="Stretch" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
- 后端代码逻辑
初始化主界面时查找资源,进行类型ObjectDataProvider可空转换为PhotoCollection的图片集数据,得到引用。并设置其目录路径
<Application.Resources>
<ObjectDataProvider x:Key="Photos" ObjectType="{x:Type local:PhotoCollection}" />
</Application.Resources>
public PhotoCollection Photos;
public MainWindow()
{
InitializeComponent();
Photos = (PhotoCollection) (Application.Current.Resources["Photos"] as ObjectDataProvider)?.Data;
Photos.Path = Environment.CurrentDirectory + "\\images";
}
双击图片显示编辑窗口,同时传递选择项这个参数
private void OnPhotoClick(object sender, RoutedEventArgs e)
{
var pvWindow = new PhotoViewer {SelectedPhoto = (Photo) PhotosListBox.SelectedItem};
pvWindow.Show();
}
图片编辑窗口的初始化,过程直接简单有效
public PhotoViewer()
{
InitializeComponent();
}
public Photo SelectedPhoto { get; set; }
private void WindowLoaded(object sender, RoutedEventArgs e)
{
ViewedPhoto.Source = SelectedPhoto.Image;
ViewedCaption.Content = SelectedPhoto.Source;
}
旋转图片实现代码
新建一个CachedBitmap的新实例,TransformedBitmap旋转后再赋值SelectedPhoto的图像类型BitmapFrame,最后重新绑定
private void Rotate(object sender, RoutedEventArgs e)
{
BitmapSource img = SelectedPhoto.Image;
var cache = new CachedBitmap(img, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
SelectedPhoto.Image = BitmapFrame.Create(new TransformedBitmap(cache, new RotateTransform(90.0)));
ViewedPhoto.Source = SelectedPhoto.Image;
}
裁剪放大实现代码
根据裁剪尺寸实例化一个新位图进行更新绑定
private void Crop(object sender, RoutedEventArgs e)
{
BitmapSource img = SelectedPhoto.Image;
var halfWidth = img.PixelWidth/2;
var halfHeight = img.PixelHeight/2;
SelectedPhoto.Image =
BitmapFrame.Create(new CroppedBitmap(img,
new Int32Rect((halfWidth - (halfWidth/2)), (halfHeight - (halfHeight/2)), halfWidth, halfHeight)));
ViewedPhoto.Source = SelectedPhoto.Image;
}
黑白图片实现代码
通过像素格式转换FormatConvertedBitmap对 位图的像素格式化:调色板、alpha通道阈值
private void BlackAndWhite(object sender, RoutedEventArgs e)
{
BitmapSource img = SelectedPhoto.Image;
SelectedPhoto.Image =
BitmapFrame.Create(new FormatConvertedBitmap(img, PixelFormats.Gray8, BitmapPalettes.Gray256, 1.0));
ViewedPhoto.Source = SelectedPhoto.Image;
}
以上----
PS:元素据BitmapMetadata 类:
与图像关联的元数据是描述图像(但不一定会显示图像)的数据。 每种支持的位图图像格式都采用不同的方式处理元数据,但读取和写入元数据的功能相同。
Windows Presentation Foundation (WPF) 支持以下图像元数据架构:可交换图像文件 (Exif)、tEXt(PNG 文本数据)、图像文件目录 (IFD)、国际新闻通信委员会 (IPTC) 以及可扩展元数据平台 (XMP)。
如果 BitmapMetadata 是由通过使用 BitmapDecoder 获取的 BitmapFrame 公开的,则默认情况下它是只读的,并且可变操作将引发异常。 如果它是由包装另一个 BitmapSource 的 BitmapFrame 公开的,则它在构造上是可变的。
可以使用 SetQuery 和 GetQuery 方法来构造和读取元数据查询。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。