WPF 標準コントロールデモアプリ › Image
Image Graphics
Image は、ビットマップのファイルなどの ImageSource から画像を表示し、与えられた領域に合わせて拡大・縮小する要素です。
Stretch と StretchDirection ごとの大きさ
Image は Control ではなく FrameworkElement から派生し、既定ではフォーカスを受け取りません(Focusable が False)。Stretch は領域に合わせた拡大・縮小の仕方で、既定値は縦横比を保つ Uniform です。300 × 200 の領域で、600 × 300 の画像は None で 600 × 300、Fill で 300 × 200、Uniform で 300 × 150、UniformToFill で 400 × 200 でした。
StretchDirection は、拡大だけ・縮小だけ・両方のどれを許すかで、既定値は Both です。UpOnly では、600 × 300 の画像はどの Stretch でも 600 × 300 のままで、DownOnly では 100 × 50 の画像が 100 × 50 のままでした。原寸より大きくしたくないアイコンには DownOnly を使います。
| Stretch | 画像 | UpOnly | DownOnly | Both |
|---|---|---|---|---|
| None | 100 x 50 | 100.01 x 50.01 | 100.01 x 50.01 | 100.01 x 50.01 |
| None | 600 x 300 | 600.08 x 300.04 | 600.08 x 300.04 | 600.08 x 300.04 |
| Fill | 100 x 50 | 300 x 200 | 100.01 x 50.01 | 300 x 200 |
| Fill | 600 x 300 | 600.08 x 300.04 | 300 x 200 | 300 x 200 |
| Uniform | 100 x 50 | 300 x 150 | 100.01 x 50.01 | 300 x 150 |
| Uniform | 600 x 300 | 600.08 x 300.04 | 300 x 150 | 300 x 150 |
| UniformToFill | 100 x 50 | 400 x 200 | 100.01 x 50.01 | 400 x 200 |
| UniformToFill | 600 x 300 | 600.08 x 300.04 | 400 x 200 | 400 x 200 |
Stretch と StretchDirection ごとの表示の大きさ。.NET 10 / Windows 11 で計測。
UniformToFill と None で切れる場所
領域からはみ出した部分は切れ、切れるのは右と下です。UniformToFill の 400 × 200 の画像は、領域の左上から始まっていました。HorizontalAlignment と VerticalAlignment を Center にすると -50 から始まり、左右が均等に切れました。サムネイルのように同じ大きさの枠を UniformToFill で埋めるときは、Image を中央に揃えます。そうしないと、切り取りで画像の左上が残ります。
DPI とデコードの大きさ
拡大・縮小しないときの大きさはデバイス非依存の単位で、ピクセル数 × 96 / DPI です。72 DPI の 100 × 50 ピクセルは計算では 133.33 × 66.67 ですが、測った 72 DPI の画像は 133.36 × 66.68 でした。同じピクセル数でも DPI が低いほど大きく表示されるので、Stretch="None" ではファイルの DPI を確かめます。ここで使った PNG は解像度を pHYs チャンクに 1 メートルあたりのピクセル数の整数で保存しているため、実際に効く DPI は公称値よりわずかに低くなります。測った大きさは、72 DPI で 2834 ピクセル/メートル(71.98 DPI)、96 DPI で 3779 ピクセル/メートル(95.99 DPI)と一致し、そのため 96 DPI の画像でも幅は 100.01 になりました。
サムネイルには DecodePixelWidth を設定します。100 にすると、600 × 300 の画像は 100 × 50 ピクセルにデコードされました。画像自体の大きさも変わり、拡大・縮小しないときの幅は 600 ではなく 100 でした。
ファイルのパスのバインドと、ファイルのロック
Source にバインドしたパスの文字は画像に変換され、Source は BitmapFrameDecode になりました。存在しないファイルや SVG ファイルのパスでは、Source は null、Image は 0 × 0 のままで、例外は起きませんでした。WPF はインストールされている Windows Imaging Component のコーデックで画像をデコードし、計測したマシンには SVG のコーデックがありませんでした。SVG は変換してから表示します。
パスで表示したファイルはロックされます。そうしてバインドした PNG を表示している間、ファイルの削除は IOException で失敗し、Source を null にした後も失敗しました。削除できたのはガベージコレクションの後でした。CacheOption を OnLoad にした BitmapImage はファイルをすぐに読み込み、表示している間でもファイルを削除できました。変わる可能性のあるファイルは、この方法で読み込みます。
| 条件 | 計測値 |
|---|---|
| 基底クラス、Focusable、Stretch と StretchDirection の既定値 | FrameworkElement, False; Uniform, Both |
| 大きい画像、UniformToFill / Both、300 x 200 の中: 大きさ、左上の位置、クリップ | 400 x 200、0, 0、300 x 200 |
| 大きい画像、UniformToFill / Both、Center に配置、300 x 200 の中: 大きさ、左上の位置、クリップ | 400 x 200、-50, 0、300 x 200 |
| 大きい画像、None / UpOnly、300 x 200 の中: 大きさ、左上の位置、クリップ | 600.08 x 300.04、0, 0、300 x 200 |
| 72 DPI の 100 x 50 ピクセル、Stretch None: 大きさ | 133.36 x 66.68 |
| Source にパスをバインド、PNG ファイル: Source の型、大きさ | BitmapFrameDecode, 100.01 x 50.01 |
| ファイルを削除: 表示中 / Source = null の後 / GC の後 | ロックされている(IOException) / ロックされている(IOException) / 削除できる |
| Source にパスをバインド、存在しないファイル: Source の型、大きさ | null, 0 x 0 |
| Source にパスをバインド、SVG ファイル: Source の型、大きさ | null, 0 x 0 |
| CacheOption OnLoad の BitmapImage を表示中: ファイルを削除 | 削除できる |
| 600 x 300 を DecodePixelWidth 100 で: ピクセル数、DIP での大きさ、Stretch None の大きさ | 100 x 50; 100.01 x 50.01; 100.01 x 50.01 |
| デモの最初のパス img0.jpg: 存在するか、ピクセル数、DPI | True; 3840 x 2400; 96 |
型、切り取り、DPI、パス、ファイルのロック、デコード。.NET 10 / Windows 11 で計測。
デモアプリで試す

デモアプリの Image のページは、Source をファイルのパスを入れた TextBox の文字にバインドし、Stretch と StretchDirection を 2 つのコンボボックスで選びます。パス C:\Windows\Web\Wallpaper\Windows\img0.jpg で始まり、計測したマシン(Windows 11)には、3840 × 2400 ピクセル・96 DPI の画像としてありました。コンボボックスは先頭の値の None と UpOnly で始まるので、画像は原寸で表示され、見えるのは左上の部分だけです。欄の下の「Show Code」リンクで、その欄の XAML を表示できます。次の XAML は、その欄(ImageUsageControl.xaml)から、スタイルと周囲の GroupBox を省き、名前空間の宣言を加えたものです。デモアプリでは Image はウィンドウの結果の領域いっぱいに置かれますが、このページの計測では大きさを固定した領域(300 × 200)に配置しました。markupextensions はデモアプリ独自のマークアップ拡張の接頭辞です。
<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markupextensions="clr-namespace:WPFStandardControlDemoApp.Common.MarkupExtensions">
<TextBox x:Name="SourceTextBox" Text="C:\Windows\Web\Wallpaper\Windows\img0.jpg" />
<ComboBox x:Name="StretchComboBox"
DisplayMemberPath="Name"
ItemsSource="{markupextensions:EnumBindingSource EnumType=Stretch}"
SelectedValuePath="Value"
SelectedIndex="0" />
<ComboBox x:Name="StretchDirectionComboBox"
DisplayMemberPath="Name"
ItemsSource="{markupextensions:EnumBindingSource EnumType=StretchDirection}"
SelectedValuePath="Value"
SelectedIndex="0" />
<Grid Background="#F0F0F0">
<Image x:Name="DemoImage"
Source="{Binding Text, ElementName=SourceTextBox}"
Stretch="{Binding SelectedValue, ElementName=StretchComboBox}"
StretchDirection="{Binding SelectedValue, ElementName=StretchDirectionComboBox}" />
</Grid>
</StackPanel>
関連するコントロールと記事
ソースコードと計測の方法
このページの挙動の記述は、すべて .NET 10 / Windows 11 で実際に動かして確かめたものです。計測には、このサイトのスクリーンショット生成ツールの ImageDemoScene を使いました。画像はツールが書き出した 100 × 50 ピクセルと 600 × 300 ピクセルの PNG ファイルで、300 × 200 の領域に配置しました。パスはデモアプリと同じく TextBox からバインドし、ロックはファイルの削除を試して調べました。