WPF学習中「BitmapImageのソースをFileStreamで読み込む – zipファイル編」

C# コンピュータ
C#

BitmapImageのStreamSourceにZipファイル内にある画像ファイルのFileStreamを割り当てて画像を表示します。

プロジェクトの作成

mkdir プロジェクト名
cd プロジェクト名
dotnet new wpf
code .

ソースコード

ファイル名:MainWindow.xaml

<Window x:Class="Sample53ReadZipImageFile.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Sample53ReadZipImageFile"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <Image Name="Image1">
            </Image>
        </StackPanel>
    </Grid>
</Window>

ファイル名:MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.IO;
using System.IO.Compression;

namespace Sample53ReadZipImageFile
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var location = @"C:\Users\asagao\Pictures\202104081936.zip";
            var filename = @"202104081936.PNG";

            // ビットマップイメージを作成
            var bi = new BitmapImage();

            // zipファイルを開く
            using (var zip = ZipFile.OpenRead(location))
            {
                // zipファイル内のファイルのストリームを取得
                var entry = zip.GetEntry(filename);
                using(Stream fs = entry.Open())
                {
                    // メモリストリームを開く
                    using (var ms = new MemoryStream())
                    {
                        // ファイルストリームをメモリストリームにコピー
                        fs.CopyTo(ms);

                        // メモリストリームの先頭へ読み込み位置を移動
                        ms.Seek(0, SeekOrigin.Begin);

                        // 初期化開始
                        bi.BeginInit();

                        // 読み込み時にイメージ全体をメモリにキャッシュ
                        bi.CacheOption = BitmapCacheOption.OnLoad;

                        // ビットマップのソースにファイルストリームを割り当て
                        bi.StreamSource = ms;

                        // 初期化終了
                        bi.EndInit();
                    }                        
                }
            }
            bi.Freeze();

            // イメージコントロールのソースにビットマップイメージを割り当て
            Image1.Source = bi;
        }
    }
}

感想

成功すると画像が表示されます。

ZipArchiveEntry.Open()の戻り値の型がSystem.IO.StreamでBitmapImage.StreamSourceの型もSystem.IO.Streamなのでそのまま割り当てれば動きそうな気がしますが、それだとなぜか画像が表示されません。
特別例外なども発生していないので、自分の情報収集能力では解決方法を見つけることが出来ませんでした。
ただ、出来上がったBitmapImageはWidthとHeightが1となっており、なんとなくソースに割り当てたStreamから読み込みがされていないように感じました。強制的に読み込む方法も見当たらないので、とりあえずStreamをMemoryStreamにコピーしMemoryStreamをBitmapImageに割り当てたところ画像が表示されました。
なんとなく目的が達成されたのでこれで良しとします。
あと、なぜかPNG形式のファイルはうまく表示されるのにJPEG形式のファイルだと例外が発生していましたが、MemoryStreamの位置を先頭にSeekしたところ解消されました。
これも原因をつかめていませんが、解決したので良しとします。

 

コメント