从 Zip 存档中读取 BitmapImage
Read BitmapImage from Zip archive
对于 WPF 项目,我需要从 Zip 文件中读取 BitmapImage。原始文件格式是 .png 我知道如何直接从文件系统执行此操作并且工作正常。来自 Zip 文件,遗憾的是图像未显示,但图像似乎已被读取。
我创建了一个简单的测试项目:
public partial class MainWindow : Window
{
public BitmapImage RouteImage { get; set; }
public MainWindow()
{
InitializeComponent();
LoadBitmap();
DataContext = RouteImage;
}
public void LoadBitmap()
{
RouteImage = new BitmapImage();
var PackedFile = @"D:\Temp\MainContent.ap";
try
{
{
using (ZipArchive archive = ZipFile.OpenRead(PackedFile))
{
var file = archive.GetEntry("RouteInformation/image.png");
if (file != null)
{
using (var zipEntryStream = file.Open())
{
RouteImage.BeginInit();
RouteImage.CacheOption = BitmapCacheOption.OnLoad;
RouteImage.StreamSource = zipEntryStream;
RouteImage.EndInit();
return;
}
}
}
}
}
catch (Exception e)
{
var s = "Exception: " + e.Message;
}
}
}
}
XAML 代码如下所示:
<Image Height="128" Width="256" Source="{Binding BitmapImage}"/>
在调试器中,流似乎已创建并绑定到 BitmapImage,但宽度和高度设置为 1。所以我认为读取 zip 文件中的数据有问题。
不确定确切原因,但似乎有必要将 zip 流复制到中间 MemoryStream 并从那里读取 BitmapImage。
您还应该编写一个带有 属性 更改通知的视图模型 class:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private BitmapImage routeImage;
public BitmapImage RouteImage
{
get { return routeImage; }
set
{
routeImage = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(RouteImage)));
}
}
public void LoadImage(string archiveName, string entryName)
{
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream); // here
memoryStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
RouteImage = bitmap;
}
}
}
}
}
将视图模型的实例分配给您的 Window:
的 DataContext
public MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
DataContext = viewModel;
viewModel.LoadImage(
@"D:\Games\steamapps\common\RailWorks\Content\Routes[=11=]000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");
}
并像这样绑定 RouteImage
属性:
<Image Source="{Binding RouteImage}"/>
如果您打算从 zip 存档加载大图像文件,我建议在异步方法中调用视图模型代码:
public async Task LoadImageAsync(string archiveName, string entryName)
{
RouteImage = await Task.Run(() => LoadImage(archiveName, entryName));
}
private BitmapImage LoadImage(string archiveName, string entryName)
{
BitmapImage bitmap = null;
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream);
memoryStream.Position = 0;
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
bitmap.Freeze(); // necessary when loaded in non-UI thread
}
}
}
return bitmap;
}
从 MainWindow 中的异步 Loaded 事件处理程序调用方法:
Loaded += async (s, e) => await viewModel.LoadImageAsync
@"D:\Games\steamapps\common\RailWorks\Content\Routes[=14=]000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");
在我从 zip 容器中删除图像的工作中,根据 Clemens 的回答使用中间线程 仅创建了一个例外 并且是站不住脚的。
最终我能够使用这段代码提取 BitmapImage
:
public static class StreamExtensions
{
public static BitmapImage ToImage(this Stream stream)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
return bitmap;
}
}
用法
var image = zipEntry.Open().ToImage();
对于 WPF 项目,我需要从 Zip 文件中读取 BitmapImage。原始文件格式是 .png 我知道如何直接从文件系统执行此操作并且工作正常。来自 Zip 文件,遗憾的是图像未显示,但图像似乎已被读取。
我创建了一个简单的测试项目:
public partial class MainWindow : Window
{
public BitmapImage RouteImage { get; set; }
public MainWindow()
{
InitializeComponent();
LoadBitmap();
DataContext = RouteImage;
}
public void LoadBitmap()
{
RouteImage = new BitmapImage();
var PackedFile = @"D:\Temp\MainContent.ap";
try
{
{
using (ZipArchive archive = ZipFile.OpenRead(PackedFile))
{
var file = archive.GetEntry("RouteInformation/image.png");
if (file != null)
{
using (var zipEntryStream = file.Open())
{
RouteImage.BeginInit();
RouteImage.CacheOption = BitmapCacheOption.OnLoad;
RouteImage.StreamSource = zipEntryStream;
RouteImage.EndInit();
return;
}
}
}
}
}
catch (Exception e)
{
var s = "Exception: " + e.Message;
}
}
}
}
XAML 代码如下所示:
<Image Height="128" Width="256" Source="{Binding BitmapImage}"/>
在调试器中,流似乎已创建并绑定到 BitmapImage,但宽度和高度设置为 1。所以我认为读取 zip 文件中的数据有问题。
不确定确切原因,但似乎有必要将 zip 流复制到中间 MemoryStream 并从那里读取 BitmapImage。
您还应该编写一个带有 属性 更改通知的视图模型 class:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private BitmapImage routeImage;
public BitmapImage RouteImage
{
get { return routeImage; }
set
{
routeImage = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(RouteImage)));
}
}
public void LoadImage(string archiveName, string entryName)
{
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream); // here
memoryStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
RouteImage = bitmap;
}
}
}
}
}
将视图模型的实例分配给您的 Window:
的 DataContextpublic MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
DataContext = viewModel;
viewModel.LoadImage(
@"D:\Games\steamapps\common\RailWorks\Content\Routes[=11=]000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");
}
并像这样绑定 RouteImage
属性:
<Image Source="{Binding RouteImage}"/>
如果您打算从 zip 存档加载大图像文件,我建议在异步方法中调用视图模型代码:
public async Task LoadImageAsync(string archiveName, string entryName)
{
RouteImage = await Task.Run(() => LoadImage(archiveName, entryName));
}
private BitmapImage LoadImage(string archiveName, string entryName)
{
BitmapImage bitmap = null;
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream);
memoryStream.Position = 0;
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
bitmap.Freeze(); // necessary when loaded in non-UI thread
}
}
}
return bitmap;
}
从 MainWindow 中的异步 Loaded 事件处理程序调用方法:
Loaded += async (s, e) => await viewModel.LoadImageAsync
@"D:\Games\steamapps\common\RailWorks\Content\Routes[=14=]000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");
在我从 zip 容器中删除图像的工作中,根据 Clemens 的回答使用中间线程 仅创建了一个例外 并且是站不住脚的。
最终我能够使用这段代码提取 BitmapImage
:
public static class StreamExtensions
{
public static BitmapImage ToImage(this Stream stream)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
return bitmap;
}
}
用法
var image = zipEntry.Open().ToImage();