C# PictureBoxの使い方を徹底解説|画像表示・サイズ調整・保存・よくあるエラー対策

はじめに

C#のWindowsフォームアプリで画像を表示したいとき、最もよく使われるコントロールがPictureBoxです。PictureBoxを使えば、JPEG、PNG、BMPなどの画像をフォーム上に表示したり、サイズを調整したり、画像を差し替えたり、保存したりできます。

一方で、C# PictureBoxは簡単に使える反面、「画像が表示されない」「ファイルが使用中になる」「保存時にGDI+のエラーが出る」「画像がぼやける」「Disposeのタイミングが分からない」といったトラブルも起きやすい部品です。

この記事では、C# PictureBoxの基本的な使い方から、画像表示、サイズ調整、画像選択、保存、描画、イベント処理、よくあるエラー対策、実用的な画像ビューアのサンプルまでをまとめて解説します。

1. C# PictureBoxとは?Windowsフォームで画像を表示する基本

1-1. PictureBoxの役割とできること

PictureBoxは、Windowsフォーム上に画像を表示するためのコントロールです。Microsoft公式ドキュメントでも、PictureBoxはビットマップ、メタファイル、アイコン、JPEG、GIF、PNGなどのグラフィックを表示するために使われるコントロールとして説明されています。

代表的には、次のような処理に使います。

  • ローカル画像ファイルをフォームに表示する

  • アプリのロゴやアイコンを表示する

  • ユーザーが選択した画像をプレビューする

  • カメラ画像やスクリーンショットを表示する

  • 画像に線や文字を描画して再表示する

  • 簡易的な画像ビューアを作る

C# PictureBoxは、画像を「表示する」ためのコントロールですが、BitmapGraphicsと組み合わせることで、簡単な画像加工や描画にも利用できます。

1-2. PictureBoxが使われる代表的な場面

PictureBoxは、Windowsフォームアプリの中で幅広く使われます。

たとえば、商品管理アプリなら商品画像の表示、社員管理アプリなら顔写真の表示、画像編集ツールなら編集対象画像のプレビュー、検査システムなら撮影画像や解析結果の表示に使えます。

また、画像を開くボタン、保存ボタン、拡大・縮小ボタンなどと組み合わせれば、簡単な画像ビューアも作成できます。

1-3. PictureBoxとImageクラス・Bitmapクラスの関係

PictureBox自体は画像データを直接編集するクラスではありません。画像を表示するには、主にImageクラスまたはBitmapクラスのオブジェクトをPictureBox.Imageプロパティに設定します。

C#
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");

Imageは画像全般を表す抽象的なクラスで、JPEG、PNG、BMPなどを扱えます。BitmapImageを継承したクラスで、ピクセル単位の編集やGraphicsによる描画によく使われます。

C#
Bitmap bitmap = new Bitmap(400, 300);
pictureBox1.Image = bitmap;

つまり、C# PictureBoxの基本は「ImageまたはBitmapを用意して、PictureBox.Imageに設定する」という考え方です。

1-4. PictureBoxを使う前に知っておきたい前提知識

PictureBoxを正しく使うには、次の点を理解しておくとスムーズです。

まず、PictureBoxはWindowsフォーム用のコントロールなので、通常はSystem.Windows.Forms名前空間を使います。画像データを扱うためにはSystem.Drawing名前空間もよく使います。

C#
using System;
using System.Drawing;
using System.Windows.Forms;

また、画像ファイルはメモリ上に読み込まれるため、大きな画像を何度も読み込む場合は、古い画像をDispose()して解放することが重要です。特に、画像の差し替え、保存、削除、再読み込みを行うアプリでは、リソース管理が重要になります。

2. PictureBoxをフォームに配置する方法

2-1. Visual StudioのデザイナーでPictureBoxを追加する手順

最も簡単な方法は、Visual StudioのWindowsフォームデザイナーを使う方法です。

  1. Windowsフォームアプリを作成する

  2. ツールボックスを開く

  3. PictureBoxをフォームにドラッグ&ドロップする

  4. プロパティウィンドウでNameSizeLocationSizeModeなどを設定する

  5. 必要に応じてImageプロパティから画像を指定する

デザイナーで配置した場合、通常はpictureBox1のような名前が自動で付けられます。実務では、用途が分かるようにpictureBoxPreviewpictureBoxPhotoのような名前に変更すると管理しやすくなります。

2-2. コードからPictureBoxを生成して配置する方法

PictureBoxはコードから動的に作成することもできます。

C#
PictureBox pictureBox = new PictureBox();

pictureBox.Name = "pictureBoxPreview";
pictureBox.Location = new Point(20, 20);
pictureBox.Size = new Size(400, 300);
pictureBox.BorderStyle = BorderStyle.FixedSingle;
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;

this.Controls.Add(pictureBox);

動的に画面を作るアプリや、画像の数に応じてPictureBoxを増やしたい場合は、コードから生成する方法が便利です。

2-3. Name・Size・Locationなど基本プロパティの設定

PictureBoxでよく使う基本プロパティは次のとおりです。

プロパティ役割
Nameコードから参照する名前
SizePictureBox全体のサイズ
Locationフォーム上の表示位置
Image表示する画像
ImageLocation読み込む画像ファイルやURLの場所
SizeMode画像の表示方法
BorderStyle枠線の表示
BackColor背景色
Dock親コンテナへの固定
Anchorフォームサイズ変更時の追従

たとえば、フォームサイズに合わせてPictureBoxも広げたい場合は、AnchorまたはDockを使います。

C#
pictureBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

2-4. PictureBoxが表示されないときに確認するポイント

PictureBox自体が表示されない場合は、次の点を確認します。

  • Controls.Add(pictureBox)を呼んでいるか

  • Visiblefalseになっていないか

  • Size0, 0になっていないか

  • 他のコントロールの背面に隠れていないか

  • Locationがフォームの外に出ていないか

  • 親コントロールに正しく追加されているか

  • DockAnchorの設定で意図しないサイズになっていないか

フォームに配置したつもりでも、Panel内に追加すべきところをFormに追加していた、またはその逆になっているケースもよくあります。

3. PictureBoxに画像を表示する基本的な使い方

3-1. Imageプロパティで画像を表示する方法

最も基本的な表示方法は、Imageプロパティに画像オブジェクトを設定する方法です。

C#
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");

Image.FromFileは指定したファイルからImageを作成するメソッドです。無効な画像形式の場合はOutOfMemoryException、ファイルが存在しない場合はFileNotFoundExceptionなどが発生する可能性があります。

安全に書くなら、次のように例外処理を入れます。

C#
try
{
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");
}
catch (FileNotFoundException)
{
MessageBox.Show("画像ファイルが見つかりません。");
}
catch (OutOfMemoryException)
{
MessageBox.Show("有効な画像ファイルではない可能性があります。");
}

3-2. ImageLocationプロパティで画像ファイルを読み込む方法

ImageLocationプロパティにファイルパスやURLを指定し、Load()またはLoadAsync()で画像を読み込む方法もあります。Microsoft公式ドキュメントでは、Imageプロパティに画像を設定する方法に加えて、ImageLocationを指定して同期読み込みのLoad()または非同期読み込みのLoadAsync()を使う方法が説明されています。

C#
pictureBox1.ImageLocation = @"C:\Images\sample.png";
pictureBox1.Load();

URL画像を読み込む場合にも使えます。

C#
pictureBox1.ImageLocation = "https://example.com/sample.jpg";
pictureBox1.LoadAsync();

ただし、ネットワーク画像は通信エラーやタイムアウトが起きる可能性があるため、実務ではエラー処理も考慮します。

3-3. ローカル画像を表示するサンプルコード

ローカル画像を表示する基本コードは次のとおりです。

C#
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");
}

SizeModeZoomにすると、画像の縦横比を維持したままPictureBox内に収まるように表示できます。

ファイルパスを直接書く場合は、\をエスケープする必要があります。

C#
pictureBox1.Image = Image.FromFile("C:\\Images\\sample.jpg");

または、逐語的文字列リテラルを使います。

C#
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");

3-4. リソース画像をPictureBoxに表示する方法

アプリに画像を埋め込む場合は、プロジェクトのリソースを使う方法があります。

Visual Studioでプロジェクトのプロパティを開き、Resources.resxに画像を追加すると、次のように参照できます。

C#
pictureBox1.Image = Properties.Resources.SampleImage;

リソース画像はアプリ内に埋め込まれるため、外部ファイルがなくても表示できます。ロゴや固定アイコンの表示に向いています。

ただし、リソース画像を直接Dispose()すると、再利用時に問題が起きることがあります。加工したい場合は、次のようにコピーを作って使うと安全です。

C#
pictureBox1.Image = new Bitmap(Properties.Resources.SampleImage);

3-5. URL画像をPictureBoxに表示する方法

URL画像を表示する場合は、ImageLocationLoadAsync()を使うと簡単です。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.ImageLocation = "https://example.com/image.jpg";
pictureBox1.LoadAsync();

より細かく制御したい場合は、HttpClientで画像を取得してImage.FromStreamで読み込む方法もあります。

C#
using System.Net.Http;

private async void buttonLoadUrl_Click(object sender, EventArgs e)
{
string url = "https://example.com/image.jpg";

using HttpClient client = new HttpClient();
byte[] bytes = await client.GetByteArrayAsync(url);

using MemoryStream ms = new MemoryStream(bytes);
Image image = Image.FromStream(ms);

pictureBox1.Image?.Dispose();
pictureBox1.Image = new Bitmap(image);
}

この方法なら、HTTPエラーや認証、ヘッダー設定なども制御しやすくなります。

3-6. 画像をクリア・差し替えする方法

画像をクリアするだけなら、Imagenullを設定します。

C#
pictureBox1.Image = null;

ただし、すでに読み込んでいた画像を解放したい場合は、古い画像をDispose()します。

C#
Image oldImage = pictureBox1.Image;
pictureBox1.Image = null;
oldImage?.Dispose();

画像を差し替える場合も、古い画像を解放してから新しい画像を設定すると、メモリリークを防ぎやすくなります。

C#
private void SetPicture(Image newImage)
{
Image oldImage = pictureBox1.Image;
pictureBox1.Image = newImage;
oldImage?.Dispose();
}

ただし、Properties.Resourcesの画像など、他でも使い回している共有画像を直接解放しないように注意してください。

4. PictureBoxの画像サイズを調整する方法

4-1. SizeModeプロパティの種類と違い

PictureBoxの画像サイズ調整で重要なのがSizeModeプロパティです。PictureBoxSizeModeには、NormalStretchImageAutoSizeCenterImageZoomがあります。Microsoft公式ドキュメントでは、PictureBoxSizeModeは画像をPictureBox内でどのように配置するかを指定する列挙体として説明されています。

SizeMode表示方法
Normal左上に原寸表示。大きい画像は切れる
StretchImagePictureBoxのサイズに合わせて伸縮。縦横比は維持されない
AutoSizePictureBox自体を画像サイズに合わせる
CenterImage中央に表示。大きい画像は切れる
Zoom縦横比を維持して全体を収める

4-2. Normal・StretchImage・AutoSize・CenterImage・Zoomの使い分け

最もよく使うのはZoomです。画像の縦横比を維持しながら、PictureBoxの枠内に収めて表示できます。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

StretchImageは、PictureBoxのサイズにぴったり合わせたい場合に使います。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

ただし、縦横比が変わるため、人物写真や商品画像では不自然に見える場合があります。

AutoSizeは、画像のサイズに合わせてPictureBox自体のサイズを変えたい場合に使います。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;

CenterImageは、画像を中央に置きたい場合に便利です。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;

4-3. 画像の縦横比を維持して表示する方法

縦横比を維持して表示したい場合は、基本的にZoomを使います。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

Zoomは、画像全体がPictureBox内に収まるように拡大・縮小します。余白が出る場合はありますが、画像が歪みません。

画像ビューア、写真プレビュー、証明写真表示、商品画像表示などでは、StretchImageよりもZoomの方が自然に見えることが多いです。

4-4. PictureBoxの枠に合わせて画像を拡大・縮小する方法

枠いっぱいに画像を表示したい場合はStretchImageを使います。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

縦横比を維持したい場合はZoom、枠いっぱいに強制的に合わせたい場合はStretchImageと覚えると分かりやすいです。

また、表示だけでなく画像データ自体をリサイズしたい場合は、新しいBitmapを作成します。

C#
private Bitmap ResizeImage(Image source, int width, int height)
{
Bitmap resized = new Bitmap(width, height);

using (Graphics g = Graphics.FromImage(resized))
{
g.DrawImage(source, 0, 0, width, height);
}

return resized;
}

このコードは、表示サイズだけでなく画像そのもののピクセルサイズを変更したい場合に使います。

4-5. 画像がぼやける・切れる場合の対処法

画像がぼやける場合は、主に拡大表示が原因です。元画像の解像度が小さい状態で大きく表示すると、どうしてもぼやけます。

対策としては、次の方法があります。

  • できるだけ高解像度の元画像を使う

  • StretchImageではなくZoomを使う

  • 拡大率を上げすぎない

  • 描画時に補間モードを設定する

  • サムネイル用と原寸表示用の画像を分ける

高品質にリサイズしたい場合は、Graphicsの設定を調整します。

C#
using System.Drawing.Drawing2D;

private Bitmap ResizeHighQuality(Image source, int width, int height)
{
Bitmap result = new Bitmap(width, height);

using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(source, 0, 0, width, height);
}

return result;
}

画像が切れる場合は、NormalCenterImageではなくZoomを試してください。

5. PictureBoxで画像を読み込み・選択・保存する方法

5-1. OpenFileDialogで画像を選択して表示する方法

ユーザーに画像ファイルを選んでもらうには、OpenFileDialogを使います。OpenFileDialogは、ユーザーにファイルを開くよう求める標準ダイアログボックスを表示するクラスです。

C#
private void buttonOpen_Click(object sender, EventArgs e)
{
using OpenFileDialog dialog = new OpenFileDialog();

dialog.Title = "画像ファイルを選択してください";
dialog.Filter = "画像ファイル|*.jpg;*.jpeg;*.png;*.bmp;*.gif|すべてのファイル|*.*";

if (dialog.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = new Bitmap(dialog.FileName);
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
}
}

Filterを設定すると、画像ファイルだけを選択しやすくなります。

5-2. SaveFileDialogでPictureBoxの画像を保存する方法

表示中の画像を保存するには、SaveFileDialogを使います。SaveFileDialogは、ファイルを保存する場所をユーザーに選択させるための標準ダイアログです。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
if (pictureBox1.Image == null)
{
MessageBox.Show("保存する画像がありません。");
return;
}

using SaveFileDialog dialog = new SaveFileDialog();

dialog.Title = "画像を保存";
dialog.Filter = "PNG画像|*.png|JPEG画像|*.jpg|BMP画像|*.bmp";
dialog.FileName = "image.png";

if (dialog.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image.Save(dialog.FileName);
}
}

ただし、拡張子に応じて形式を明示した方が安全です。

5-3. JPEG・PNG・BMPなど形式を指定して保存する方法

Image.Saveでは、保存形式を指定できます。Microsoft公式ドキュメントでも、Save(String, ImageFormat)は指定した形式でファイルに保存するオーバーロードとして説明されています。

C#
using System.Drawing.Imaging;

private void SaveImage(string filePath)
{
if (pictureBox1.Image == null) return;

string ext = Path.GetExtension(filePath).ToLower();

ImageFormat format = ext switch
{
".jpg" or ".jpeg" => ImageFormat.Jpeg,
".png" => ImageFormat.Png,
".bmp" => ImageFormat.Bmp,
".gif" => ImageFormat.Gif,
_ => ImageFormat.Png
};

pictureBox1.Image.Save(filePath, format);
}

JPEGは写真向き、PNGは透過や劣化なし保存向き、BMPは非圧縮に近くファイルサイズが大きくなりやすい形式です。

5-4. 読み込んだ画像ファイルをロックしない書き方

Image.FromFilenew Bitmap(filePath)で画像を読み込むと、画像オブジェクトが解放されるまで元ファイルを削除・上書きできないことがあります。これを避けたい場合は、ファイルを一度ストリームで読み込み、Bitmapとしてコピーを作成します。

C#
private Bitmap LoadImageWithoutLock(string filePath)
{
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using Image temp = Image.FromStream(fs);
return new Bitmap(temp);
}

使い方は次のとおりです。

C#
pictureBox1.Image?.Dispose();
pictureBox1.Image = LoadImageWithoutLock(@"C:\Images\sample.jpg");

この方法なら、読み込み後に元ファイルを削除・リネーム・上書きしやすくなります。

5-5. 保存時に発生しやすいエラーと対策

画像保存時によくあるエラーは次のとおりです。

エラー主な原因対策
GDI+の一般的なエラー読み込んだ同じファイルへ上書き保存している別名保存、コピー保存、元画像を解放してから保存
UnauthorizedAccessException書き込み権限がない保存先を変更する
DirectoryNotFoundException保存先フォルダが存在しないフォルダ存在確認をする
ExternalException形式や保存先に問題があるImageFormatを明示する
NullReferenceExceptionpictureBox1.Imageがnull保存前にnullチェックする

特に多いのが、読み込んだ画像と同じパスへそのまま上書き保存しようとするケースです。Image.Saveでは、画像が作成された同じファイルへ保存しようとした場合に例外が発生する可能性があります。

安全に上書きしたい場合は、一時ファイルに保存してから置き換える方法が有効です。

C#
private void SafeOverwrite(Image image, string path, ImageFormat format)
{
string tempPath = path + ".tmp";

image.Save(tempPath, format);

File.Delete(path);
File.Move(tempPath, path);
}

6. PictureBoxで画像を加工・描画する方法

6-1. Bitmapを使って画像を編集する基本

画像を編集したい場合は、Bitmapを使います。Bitmapは画像をピクセル単位で扱えるため、加工や描画に向いています。

C#
Bitmap bitmap = new Bitmap(pictureBox1.Image);

表示中の画像をコピーして編集する場合は、次のようにします。

C#
if (pictureBox1.Image != null)
{
Bitmap bitmap = new Bitmap(pictureBox1.Image);

// ここでbitmapを加工する

pictureBox1.Image?.Dispose();
pictureBox1.Image = bitmap;
}

元画像を直接加工したくない場合は、必ずコピーを作ってから編集しましょう。

6-2. Graphicsで線・文字・図形を描画する方法

Graphicsクラスを使うと、画像に線、文字、四角形、円などを描画できます。Microsoft公式ドキュメントでは、GraphicsはGDI+描画サーフェイスをカプセル化するクラスとして説明されています。

C#
Bitmap bitmap = new Bitmap(500, 300);

using (Graphics g = Graphics.FromImage(bitmap))
{
g.Clear(Color.White);

using Pen pen = new Pen(Color.Red, 3);
g.DrawLine(pen, 20, 20, 300, 200);

using Font font = new Font("Meiryo", 20);
using Brush brush = new SolidBrush(Color.Blue);
g.DrawString("Hello PictureBox", font, brush, 50, 100);

g.DrawRectangle(Pens.Green, 50, 150, 200, 80);
}

pictureBox1.Image?.Dispose();
pictureBox1.Image = bitmap;

この方法を使えば、画像に注釈や枠線を付けることができます。

6-3. PictureBox上にマウスで描画する方法

PictureBox上にマウスで線を描くには、MouseDownMouseMoveMouseUpを使います。

C#
private bool isDrawing = false;
private Point lastPoint;
private Bitmap canvas;

private void Form1_Load(object sender, EventArgs e)
{
canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);

using (Graphics g = Graphics.FromImage(canvas))
{
g.Clear(Color.White);
}

pictureBox1.Image = canvas;
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isDrawing = true;
lastPoint = e.Location;
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (!isDrawing) return;

using (Graphics g = Graphics.FromImage(canvas))
using (Pen pen = new Pen(Color.Black, 3))
{
g.DrawLine(pen, lastPoint, e.Location);
}

lastPoint = e.Location;
pictureBox1.Invalidate();
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
isDrawing = false;
}

このコードでは、Bitmapに直接線を描画し、PictureBoxに再表示しています。

6-4. 画像を回転・反転・リサイズする方法

画像を回転・反転するには、RotateFlipメソッドを使います。Image.RotateFlipは、指定したRotateFlipTypeに従って画像を回転または反転するメソッドです。

C#
if (pictureBox1.Image != null)
{
pictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
pictureBox1.Refresh();
}

左右反転は次のようにします。

C#
pictureBox1.Image.RotateFlip(RotateFlipType.RotateNoneFlipX);
pictureBox1.Refresh();

リサイズする場合は、新しいBitmapを作ります。

C#
Bitmap resized = new Bitmap(pictureBox1.Image, new Size(300, 200));

pictureBox1.Image?.Dispose();
pictureBox1.Image = resized;

高品質にリサイズしたい場合は、先ほど紹介したGraphicsを使ったリサイズ処理を使います。

6-5. 加工後の画像をPictureBoxに再表示する方法

加工後の画像を再表示するには、PictureBox.Imageを差し替えます。

C#
Bitmap edited = new Bitmap(pictureBox1.Image);

using (Graphics g = Graphics.FromImage(edited))
{
g.DrawEllipse(Pens.Red, 50, 50, 100, 100);
}

Image old = pictureBox1.Image;
pictureBox1.Image = edited;
old?.Dispose();

ポイントは、古い画像を適切に解放することです。大量の画像を扱うアプリでは、古いImageBitmapを解放しないとメモリ使用量が増え続けます。

7. PictureBoxのイベント処理を活用する方法

7-1. Clickイベントで画像クリックを検知する方法

PictureBoxは通常のWindowsフォームコントロールなので、Clickイベントを使えます。

C#
private void pictureBox1_Click(object sender, EventArgs e)
{
MessageBox.Show("画像がクリックされました。");
}

デザイナーでイベントを設定するか、コードで次のように登録します。

C#
pictureBox1.Click += pictureBox1_Click;

画像選択、詳細表示、拡大表示などの操作に使えます。

7-2. MouseMove・MouseDown・MouseUpで座標を取得する方法

画像上のマウス座標を取得するには、MouseEventArgsLocationXYを使います。

C#
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
label1.Text = $"X: {e.X}, Y: {e.Y}";
}

クリック位置を取得する場合は、MouseDownを使います。

C#
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
MessageBox.Show($"クリック位置: X={e.X}, Y={e.Y}");
}

ただし、SizeModeZoomの場合、PictureBox上の座標と実際の画像ピクセル座標は一致しないことがあります。画像解析や座標取得を正確に行う場合は、表示倍率と余白を考慮して変換する必要があります。

7-3. Paintイベントで画像上に描画する方法

一時的な枠線や選択範囲を表示したい場合は、Paintイベントが便利です。

C#
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using Pen pen = new Pen(Color.Red, 2);
e.Graphics.DrawRectangle(pen, 20, 20, 100, 80);
}

Paintイベントで描いた内容は、画像データそのものには保存されません。画面上に一時的に描画されるだけです。

画像そのものに保存したい場合は、Graphics.FromImage(bitmap)Bitmapに描画します。

7-4. Drag&Dropで画像を読み込む方法

PictureBoxに画像ファイルをドラッグ&ドロップして表示することもできます。

C#
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.AllowDrop = true;
pictureBox1.DragEnter += pictureBox1_DragEnter;
pictureBox1.DragDrop += pictureBox1_DragDrop;
}

private void pictureBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
}

private void pictureBox1_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

if (files.Length > 0)
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = LoadImageWithoutLock(files[0]);
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
}
}

画像ビューアやファイルプレビュー機能を作るときに便利です。

7-5. 画像ビューア風の操作を実装する方法

画像ビューア風にするなら、次の機能を組み合わせます。

  • OpenFileDialogで画像を開く

  • PictureBox.SizeModeで表示倍率を切り替える

  • MouseWheelで拡大・縮小する

  • PanelにPictureBoxを入れてスクロールする

  • SaveFileDialogで保存する

  • DragDropで画像を開く

簡単な表示切り替えなら、ボタンでSizeModeを変えるだけでも十分です。

C#
private void buttonZoom_Click(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
}

private void buttonStretch_Click(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}

private void buttonNormal_Click(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
}

8. PictureBoxでよくあるエラーと原因・解決策

8-1. 画像が表示されない原因と確認項目

画像が表示されない場合は、次の点を確認します。

原因確認ポイント
ファイルパスが間違っているFile.Exists(path)で確認する
画像形式が不正別の画像ビューアで開けるか確認する
PictureBoxのサイズが小さいSizeを確認する
Imageがnullデバッグで確認する
例外が握りつぶされているcatchで内容を表示する
SizeModeの影響Zoomに変更して確認する
UIスレッド以外から操作しているInvokeを使う

まずは次のように確認すると原因を絞り込みやすいです。

C#
string path = @"C:\Images\sample.jpg";

if (!File.Exists(path))
{
MessageBox.Show("ファイルが存在しません。");
return;
}

pictureBox1.Image = Image.FromFile(path);

8-2. 「ファイルが使用中です」と表示される原因

画像ファイルを読み込んだ後に、その画像を削除・上書きしようとすると「ファイルが使用中です」と表示されることがあります。

原因は、画像オブジェクトが元ファイルを参照したままになっていることです。

対策は次のいずれかです。

  • 画像を使い終わったらDispose()する

  • ファイルをロックしない読み込み方を使う

  • 上書き保存ではなく別名保存する

  • 一時ファイルに保存してから置き換える

おすすめは、次のような読み込み関数を使う方法です。

C#
private Bitmap LoadImageWithoutLock(string filePath)
{
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using Image temp = Image.FromStream(fs);
return new Bitmap(temp);
}

8-3. OutOfMemoryExceptionが発生する原因

OutOfMemoryExceptionは、単純なメモリ不足だけでなく、画像ファイルとして無効なファイルを読み込もうとした場合にも発生することがあります。Image.FromFileの公式ドキュメントでも、有効な画像形式でない場合やGDI+がピクセル形式をサポートしていない場合にOutOfMemoryExceptionが発生すると説明されています。

対策は次のとおりです。

  • ファイル拡張子だけで判断しない

  • try-catchで例外処理する

  • 大きすぎる画像は縮小してから扱う

  • 使い終わった画像をDispose()する

  • 画像形式を確認する

C#
try
{
pictureBox1.Image = LoadImageWithoutLock(path);
}
catch (OutOfMemoryException)
{
MessageBox.Show("画像形式が不正、またはサイズが大きすぎる可能性があります。");
}

8-4. ObjectDisposedExceptionが発生する原因

ObjectDisposedExceptionは、すでにDispose()した画像を再利用しようとしたときに発生します。

たとえば、次のようなコードは危険です。

C#
Image img = Image.FromFile(path);
pictureBox1.Image = img;
img.Dispose(); // この時点でPictureBoxの画像も使えなくなる

PictureBox.Imageに設定した画像は、表示中は破棄しないようにします。破棄するのは、画像を差し替える直前やフォームを閉じるときです。

C#
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
pictureBox1.Image?.Dispose();
}

8-5. 画像保存時にGDI+の一般的なエラーが出る原因

「GDI+で一般的なエラーが発生しました」というエラーは、原因が分かりにくい代表的なトラブルです。

主な原因は次のとおりです。

  • 読み込んだ元ファイルと同じパスに保存している

  • 保存先フォルダが存在しない

  • 書き込み権限がない

  • 画像オブジェクトが破棄済み

  • ファイルが別プロセスで使用中

  • 拡張子と保存形式が合っていない

対策として、保存形式を明示します。

C#
pictureBox1.Image.Save(path, ImageFormat.Png);

また、上書き保存では一時ファイルを使うと安全です。

8-6. Dispose忘れによるメモリリーク対策

画像を何度も読み込むアプリでは、古い画像を解放しないとメモリ使用量が増え続けます。

悪い例です。

C#
pictureBox1.Image = Image.FromFile(path);

この処理を何度も繰り返すと、以前の画像が解放されない場合があります。

良い例です。

C#
Image old = pictureBox1.Image;
pictureBox1.Image = LoadImageWithoutLock(path);
old?.Dispose();

フォーム終了時にも解放します。

C#
protected override void OnFormClosed(FormClosedEventArgs e)
{
pictureBox1.Image?.Dispose();
base.OnFormClosed(e);
}

9. PictureBoxを使うときの注意点とベストプラクティス

9-1. ImageとBitmapの解放タイミング

PictureBoxで画像を扱うときは、Dispose()のタイミングが重要です。

基本方針は次のとおりです。

  • PictureBoxに表示中の画像は破棄しない

  • 画像を差し替えるときに古い画像を破棄する

  • フォームを閉じるときに表示中の画像を破棄する

  • 一時的に作ったBitmapGraphicsPenBrushFontusingで破棄する

  • リソース画像を直接破棄しない

安全な差し替え処理は次の形です。

C#
private void ReplaceImage(Image newImage)
{
Image oldImage = pictureBox1.Image;
pictureBox1.Image = newImage;
oldImage?.Dispose();
}

9-2. 大きな画像を扱うときのパフォーマンス対策

高解像度画像をそのままPictureBoxに表示すると、メモリ使用量が大きくなります。

たとえば、4000×3000ピクセルの画像は、圧縮されたJPEGファイルとしては数MBでも、展開後はかなり大きなメモリを使います。

対策は次のとおりです。

  • 表示用には縮小画像を使う

  • 原寸画像とプレビュー画像を分ける

  • 不要になった画像をすぐにDispose()する

  • 一覧表示ではサムネイルを使う

  • 何度もリサイズしない

  • 大量画像を同時にPictureBoxへ載せない

サムネイルを作る例です。

C#
private Bitmap CreateThumbnail(Image source, int maxWidth, int maxHeight)
{
double ratioX = (double)maxWidth / source.Width;
double ratioY = (double)maxHeight / source.Height;
double ratio = Math.Min(ratioX, ratioY);

int width = (int)(source.Width * ratio);
int height = (int)(source.Height * ratio);

return ResizeHighQuality(source, width, height);
}

9-3. ファイルパス指定で失敗しない書き方

C#でファイルパスを書くときは、\の扱いに注意します。

悪い例です。

C#
pictureBox1.Image = Image.FromFile("C:\Images\sample.jpg");

\Iなどがエスケープとして解釈される可能性があります。

良い例です。

C#
pictureBox1.Image = Image.FromFile(@"C:\Images\sample.jpg");

または、Path.Combineを使います。

C#
string path = Path.Combine(Application.StartupPath, "Images", "sample.jpg");
pictureBox1.Image = Image.FromFile(path);

実務では、固定パスよりもApplication.StartupPathEnvironment.GetFolderPath、設定ファイルなどを使う方が安全です。

9-4. UIスレッド以外からPictureBoxを操作する際の注意

Windowsフォームのコントロールは、基本的に作成されたUIスレッドから操作します。別スレッドからPictureBoxのImageを直接変更すると、例外や不安定な動作の原因になります。Control.Invokeは、コントロールのウィンドウハンドルを所有するスレッド上でデリゲートを実行するメソッドです。

別スレッドからPictureBoxを更新する場合は、次のようにします。

C#
private void SetImageThreadSafe(Image image)
{
if (pictureBox1.InvokeRequired)
{
pictureBox1.Invoke(new Action(() => SetImageThreadSafe(image)));
return;
}

pictureBox1.Image?.Dispose();
pictureBox1.Image = image;
}

非同期処理で画像をダウンロードし、完了後にPictureBoxへ表示するようなケースでは特に注意してください。

9-5. PictureBoxに向いている処理・向いていない処理

PictureBoxに向いている処理は次のとおりです。

  • 画像の表示

  • 簡単な画像プレビュー

  • 簡易画像ビューア

  • クリック位置の取得

  • 簡単な描画

  • ロゴやアイコンの表示

一方、次のような処理にはあまり向いていません。

  • 本格的な画像編集ソフト

  • 大量画像の高速表示

  • 複雑なレイヤー描画

  • 高度なズーム・パン操作

  • GPUを使った高速描画

  • アニメーションの多いUI

本格的な画像編集や高性能な描画が必要な場合は、専用の画像処理ライブラリやWPF、Direct2D、OpenGLなども検討します。

10. 実用サンプル:PictureBoxを使った画像ビューアの作成

10-1. 画像を開くボタンを作成する

ここでは、PictureBoxを使った簡単な画像ビューアを作ります。

必要な機能は次のとおりです。

  • 画像を開く

  • PictureBoxに表示する

  • 表示モードを切り替える

  • 表示中の画像を保存する

フォームには、次のコントロールを配置します。

コントロールNameText
PictureBoxpictureBoxPreviewなし
ButtonbuttonOpen開く
ButtonbuttonSave保存
ButtonbuttonZoomZoom
ButtonbuttonStretchStretch
ButtonbuttonNormalNormal

10-2. 選択した画像をPictureBoxに表示する

画像を選択して表示する処理です。

C#
private void buttonOpen_Click(object sender, EventArgs e)
{
using OpenFileDialog dialog = new OpenFileDialog();

dialog.Title = "画像を開く";
dialog.Filter = "画像ファイル|*.jpg;*.jpeg;*.png;*.bmp;*.gif|すべてのファイル|*.*";

if (dialog.ShowDialog() == DialogResult.OK)
{
Image oldImage = pictureBoxPreview.Image;
pictureBoxPreview.Image = LoadImageWithoutLock(dialog.FileName);
oldImage?.Dispose();

pictureBoxPreview.SizeMode = PictureBoxSizeMode.Zoom;
}
}

ファイルロックを避けるため、LoadImageWithoutLockを使っています。

10-3. 拡大・縮小表示を切り替える

表示モードの切り替えはSizeModeを変更するだけです。

C#
private void buttonZoom_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.Zoom;
}

private void buttonStretch_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.StretchImage;
}

private void buttonNormal_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.Normal;
}

通常の画像ビューアでは、まずZoomを基本にすると使いやすくなります。

10-4. 表示中の画像を保存する

保存処理では、保存形式を拡張子に応じて切り替えます。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
if (pictureBoxPreview.Image == null)
{
MessageBox.Show("保存する画像がありません。");
return;
}

using SaveFileDialog dialog = new SaveFileDialog();

dialog.Title = "画像を保存";
dialog.Filter = "PNG画像|*.png|JPEG画像|*.jpg|BMP画像|*.bmp";
dialog.FileName = "image.png";

if (dialog.ShowDialog() == DialogResult.OK)
{
SaveImageByExtension(pictureBoxPreview.Image, dialog.FileName);
}
}

10-5. サンプルコード全体

以下は、PictureBoxを使った簡易画像ビューアのサンプルコードです。

C#
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;

namespace PictureBoxViewerSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

pictureBoxPreview.BorderStyle = BorderStyle.FixedSingle;
pictureBoxPreview.BackColor = Color.White;
pictureBoxPreview.SizeMode = PictureBoxSizeMode.Zoom;

buttonOpen.Click += buttonOpen_Click;
buttonSave.Click += buttonSave_Click;
buttonZoom.Click += buttonZoom_Click;
buttonStretch.Click += buttonStretch_Click;
buttonNormal.Click += buttonNormal_Click;
}

private void buttonOpen_Click(object sender, EventArgs e)
{
using OpenFileDialog dialog = new OpenFileDialog();

dialog.Title = "画像を開く";
dialog.Filter = "画像ファイル|*.jpg;*.jpeg;*.png;*.bmp;*.gif|すべてのファイル|*.*";

if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
Image oldImage = pictureBoxPreview.Image;
pictureBoxPreview.Image = LoadImageWithoutLock(dialog.FileName);
oldImage?.Dispose();

pictureBoxPreview.SizeMode = PictureBoxSizeMode.Zoom;
}
catch (Exception ex)
{
MessageBox.Show("画像を開けませんでした。\n" + ex.Message);
}
}
}

private void buttonSave_Click(object sender, EventArgs e)
{
if (pictureBoxPreview.Image == null)
{
MessageBox.Show("保存する画像がありません。");
return;
}

using SaveFileDialog dialog = new SaveFileDialog();

dialog.Title = "画像を保存";
dialog.Filter = "PNG画像|*.png|JPEG画像|*.jpg|BMP画像|*.bmp";
dialog.FileName = "image.png";

if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
SaveImageByExtension(pictureBoxPreview.Image, dialog.FileName);
MessageBox.Show("保存しました。");
}
catch (Exception ex)
{
MessageBox.Show("保存に失敗しました。\n" + ex.Message);
}
}
}

private void buttonZoom_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.Zoom;
}

private void buttonStretch_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.StretchImage;
}

private void buttonNormal_Click(object sender, EventArgs e)
{
pictureBoxPreview.SizeMode = PictureBoxSizeMode.Normal;
}

private Bitmap LoadImageWithoutLock(string filePath)
{
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using Image temp = Image.FromStream(fs);
return new Bitmap(temp);
}

private void SaveImageByExtension(Image image, string filePath)
{
string ext = Path.GetExtension(filePath).ToLower();

ImageFormat format = ext switch
{
".jpg" or ".jpeg" => ImageFormat.Jpeg,
".png" => ImageFormat.Png,
".bmp" => ImageFormat.Bmp,
_ => ImageFormat.Png
};

image.Save(filePath, format);
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
pictureBoxPreview.Image?.Dispose();
base.OnFormClosed(e);
}
}
}

このサンプルでは、画像の読み込み、表示モード切り替え、保存、Disposeまでを一通り実装しています。

11. C# PictureBoxに関するよくある質問

11-1. PictureBoxに複数画像を表示できますか?

1つのPictureBoxに直接設定できる画像は基本的に1つです。

複数画像を表示したい場合は、次の方法があります。

  • 複数のPictureBoxを使う

  • 1枚のBitmapに複数画像を描画して表示する

  • FlowLayoutPanelにPictureBoxを複数追加する

  • ListViewやDataGridViewでサムネイル表示する

複数画像を1枚にまとめて表示する例です。

C#
Bitmap canvas = new Bitmap(600, 300);

using (Graphics g = Graphics.FromImage(canvas))
{
g.Clear(Color.White);
g.DrawImage(image1, 0, 0, 300, 300);
g.DrawImage(image2, 300, 0, 300, 300);
}

pictureBox1.Image = canvas;

11-2. PictureBoxの画像を中央に表示するには?

画像を中央に表示するには、SizeModeCenterImageを設定します。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;

画像全体を表示しつつ中央配置したい場合は、Zoomの方が向いています。

C#
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

11-3. PictureBoxの画像をクリックして座標を取得するには?

MouseDownイベントを使います。

C#
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
int x = e.X;
int y = e.Y;

MessageBox.Show($"X={x}, Y={y}");
}

ただし、SizeModeZoomの場合は、取得できるのはPictureBox上の座標です。実際の画像ピクセル座標が必要な場合は、表示倍率と余白を考慮して変換します。

11-4. PictureBoxの画像を高画質で拡大できますか?

表示だけならZoomStretchImageで拡大できますが、元画像の解像度以上にきれいになるわけではありません。

高画質にリサイズしたい場合は、GraphicsInterpolationMode.HighQualityBicubicを指定します。

C#
using System.Drawing.Drawing2D;

Bitmap result = new Bitmap(800, 600);

using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(pictureBox1.Image, 0, 0, 800, 600);
}

pictureBox1.Image = result;

ただし、どれだけ補間しても、元画像に存在しない細部を完全に復元することはできません。

11-5. PictureBoxとPanel・Label・Canvasの違いは?

PictureBoxは画像表示に特化したWindowsフォームコントロールです。

Panelは複数のコントロールをまとめるコンテナで、スクロール領域やレイアウト管理に向いています。画像を表示することもできますが、PictureBoxほど画像表示用のプロパティはそろっていません。

Labelは文字表示用のコントロールです。背景画像を設定することはできますが、画像ビューア用途には向いていません。

CanvasはWPFで使われるレイアウト要素です。WindowsフォームのPictureBoxとは別物です。WPFで自由な描画やレイアウトをしたい場合は、CanvasImageDrawingVisualなどを使います。

Windowsフォームで単純に画像を表示したいなら、まずはPictureBoxを使うのが分かりやすいです。

まとめ

C# PictureBoxは、Windowsフォームアプリで画像を表示するための基本的なコントロールです。Imageプロパティに画像を設定するだけで簡単に表示でき、SizeModeを使えば画像の表示方法も調整できます。

画像をきれいに表示したい場合はZoom、枠いっぱいに合わせたい場合はStretchImage、中央に表示したい場合はCenterImageを使います。画像を選択するならOpenFileDialog、保存するならSaveFileDialogを組み合わせると実用的なアプリを作れます。

一方で、PictureBoxを使うときは、画像ファイルのロック、Dispose()忘れ、GDI+の保存エラー、OutOfMemoryException、UIスレッド以外からの操作に注意が必要です。特に画像を何度も差し替えるアプリでは、古い画像を適切に解放することが重要です。

C# PictureBoxの基本を押さえれば、画像プレビュー、写真表示、簡易画像ビューア、画像加工ツールなど、さまざまなWindowsフォームアプリに応用できます。