C#画像処理の始め方|初心者がつまずく読み込み・加工・保存を実践コードで解決

はじめに

C#で画像処理を始めようとすると、「画像を読み込むだけなのにエラーになる」「加工した画像が保存できない」「Bitmap、Image、Matの違いがわからない」といった壁にぶつかりがちです。

C#画像処理では、画像の読み込み、リサイズ、トリミング、回転、グレースケール化、文字入れ、合成、保存など、アプリ開発でよく使う処理を実装できます。さらにライブラリを使えば、顔検出、物体認識、輪郭抽出、QRコード処理、画像解析などの高度な処理にも発展できます。

この記事では、初心者が最初につまずきやすい「読み込み・加工・保存」の流れを中心に、C#で画像処理を始めるための考え方と実践コードを解説します。

1. C#画像処理でできることと初心者が最初につまずくポイント

C#画像処理は、単に画像を表示するだけではありません。画像ファイルをプログラムで読み込み、サイズ変更や色変換を行い、加工後の画像を別ファイルとして保存する一連の処理を指します。

たとえば、以下のような処理ができます。

・アップロードされた画像を自動でリサイズする
・サムネイル画像を生成する
・画像の一部を切り抜く
・画像に文字やロゴを重ねる
・白黒画像やグレースケール画像に変換する
・複数画像を合成する
・画像から輪郭や特徴点を検出する

最初は難しく見えますが、基本は「読み込む」「加工する」「保存する」の3ステップです。

1-1. 「c# 画像処理」で検索する人の主な目的

「c# 画像処理」で検索する人の目的は、大きく分けると次の3つです。

1つ目は、画像をアプリ上に表示したいケースです。WinFormsのPictureBox、WPFのImageコントロール、ASP.NET CoreのWeb画面などに画像を表示する処理が該当します。

2つ目は、画像を加工したいケースです。リサイズ、トリミング、回転、反転、文字入れ、明るさ調整、グレースケール化など、実務でもよく使われる処理です。

3つ目は、画像を解析したいケースです。OpenCV系のライブラリを使って、顔検出、物体検出、輪郭抽出、テンプレートマッチングなどを行います。

初心者の場合は、いきなり画像解析から始めるよりも、まずは画像の読み込み、簡単な加工、保存までを確実に理解するのがおすすめです。

1-2. 読み込み・加工・保存の基本フロー

C#画像処理の基本フローは次の通りです。

C#
// 1. 画像を読み込む
using var image = Image.Load("input.jpg");

// 2. 画像を加工する
image.Mutate(x => x.Resize(300, 200));

// 3. 加工した画像を保存する
image.Save("output.jpg");

この例ではImageSharpを使っています。画像を読み込み、横300px・縦200pxにリサイズし、別名で保存しています。

画像処理では、元画像を直接変更するのではなく、加工後の画像を別ファイルとして保存するのが基本です。特に初心者のうちは、元画像を上書きせず、output.jpgのように別名保存する方が安全です。

1-3. WinForms・WPF・コンソール・Webアプリでの違い

C#画像処理は、どの種類のアプリでも実装できます。ただし、画像を「表示する方法」と「ファイルを扱う場所」が異なります。

WinFormsでは、PictureBoxに画像を表示することが多いです。画面アプリとして画像加工ツールを作る場合に向いています。

WPFでは、ImageコントロールにBitmapImageなどを設定して表示します。UIをきれいに作りたい場合やMVVM構成で作る場合に向いています。

コンソールアプリでは、画面表示よりも一括処理に向いています。フォルダ内の画像をまとめてリサイズする、画像を自動変換する、といったバッチ処理に便利です。

Webアプリでは、アップロードされた画像をサーバー側で加工し、保存または配信します。ASP.NET Coreでプロフィール画像や商品画像のサムネイルを作るケースなどが代表的です。

つまり、画像処理の本体は同じでも、アプリの種類によって入力元・表示方法・保存先が変わります。

1-4. 初心者が混乱しやすい画像形式・Bitmap・Image・Matの関係

C#画像処理で混乱しやすいのが、画像形式とクラス名の違いです。

PNG、JPEG、BMP、GIFなどは、画像ファイルの保存形式です。ファイルとして保存されるときの形式を表します。

一方で、BitmapImageMatなどは、プログラム上で画像を扱うための型です。

Bitmapは、主にSystem.Drawing系で使われる画像クラスです。昔から多くのサンプルコードで使われています。

Imageは、ライブラリによって意味が変わります。System.DrawingのImageもあれば、ImageSharpのImage<TPixel>もあります。名前が同じでも別物なので、使用している名前空間を確認することが重要です。

Matは、OpenCvSharpでよく使われる画像データの型です。OpenCVの画像処理では基本的にMatを使います。

初心者は、「JPEGだからBitmap」「PNGだからMat」と考えるのではなく、「ファイル形式」と「プログラム上の型」は別物だと理解しておくと混乱しにくくなります。

2. C#で画像処理を始める前に選ぶべきライブラリ

C#で画像処理をする場合、どのライブラリを使うかがとても重要です。昔のサンプルではSystem.Drawingを使ったコードが多く見つかりますが、現在の.NETでは用途や実行環境によって適した選択肢が変わります。

代表的な選択肢は次の4つです。

・System.Drawing.Common
・ImageSharp
・OpenCvSharp
・SkiaSharp

それぞれ得意分野が違うため、「何をしたいか」で選ぶのがポイントです。

2-1. System.Drawing.Commonは今から使ってよいのか

System.Drawing.Commonは、古くから使われてきた画像処理ライブラリです。BitmapGraphicsを使って、画像の読み込み、描画、保存などができます。

ただし、現在の.NETでは注意が必要です。System.Drawing.Commonは主にWindows向けの利用が前提です。Windowsデスクトップアプリで簡単な画像処理をする程度であれば使える場面もありますが、Linuxサーバーやクラウド環境、ASP.NET Coreでの本番利用では避けた方が無難です。

特にこれから新しくC#画像処理を学ぶなら、クロスプラットフォームで扱いやすいImageSharpやSkiaSharpを選ぶ方が安心です。

2-2. ImageSharpが初心者に向いているケース

ImageSharpは、C#だけで実装された画像処理ライブラリです。画像の読み込み、リサイズ、トリミング、回転、保存など、基本的な画像加工をわかりやすいコードで書けます。

初心者に向いている理由は、コードが直感的で、画像処理の基本フローを理解しやすいからです。

たとえば、画像をリサイズして保存するコードは次のように書けます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("input.jpg");

image.Mutate(x => x.Resize(400, 300));

image.Save("resized.jpg");

Loadで読み込み、Mutateで加工し、Saveで保存するという流れが明確です。

サムネイル作成、画像アップロード処理、Webアプリでの画像加工、基本的な写真加工を行いたい場合は、ImageSharpから始めると理解しやすいでしょう。

2-3. OpenCvSharpが本格的な画像解析に向いているケース

OpenCvSharpは、画像処理ライブラリOpenCVをC#から使えるようにしたラッパーです。リサイズやグレースケール化だけでなく、輪郭抽出、顔検出、テンプレートマッチング、カメラ映像処理など、本格的な画像解析に向いています。

OpenCvSharpでは、画像をMatとして扱います。

C#
using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg");
using var gray = new Mat();

Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);

Cv2.ImWrite("gray.jpg", gray);

このコードでは、画像を読み込み、グレースケール化して保存しています。

OpenCvSharpは高機能ですが、初心者には少し難しく感じることがあります。画像解析やコンピュータビジョンを目的にしている場合はOpenCvSharp、単純な画像加工が目的ならImageSharp、というように使い分けるのがおすすめです。

2-4. SkiaSharpが描画・高速処理に向いているケース

SkiaSharpは、2Dグラフィックス描画に強いライブラリです。Google ChromeやAndroidでも使われているSkiaを.NETから扱えるようにしたものです。

画像に文字や図形を描画したり、キャンバスに直接描いたりする処理に向いています。クロスプラットフォーム対応もしやすく、デスクトップ、モバイル、Web系の描画処理でも使われます。

たとえば、画像に文字を描く、図形を重ねる、独自の画像を生成する、といった用途ではSkiaSharpが候補になります。

ただし、初心者が「画像を読み込んでリサイズして保存したい」という目的であれば、まずはImageSharpの方が始めやすいです。描画処理を本格的に行いたくなった段階でSkiaSharpを検討するとよいでしょう。

2-5. 目的別おすすめライブラリ早見表

目的別に選ぶなら、次のようになります。

目的おすすめライブラリ
画像の読み込み・保存を学びたいImageSharp
リサイズ・トリミング・回転をしたいImageSharp
Webアプリでアップロード画像を加工したいImageSharp
顔検出・輪郭抽出・画像解析をしたいOpenCvSharp
カメラ映像や動画フレームを扱いたいOpenCvSharp
画像に文字や図形を描きたいSkiaSharp / ImageSharp.Drawing
Windowsデスクトップで簡単に扱いたいSystem.Drawing.Common
クロスプラットフォームで安全に使いたいImageSharp / SkiaSharp / OpenCvSharp

この記事では、初心者が扱いやすいImageSharpを中心に実践コードを紹介します。

3. 開発環境の準備とサンプル画像の用意

C#画像処理を始めるには、まずプロジェクトを作成し、画像処理ライブラリを追加し、サンプル画像を用意します。

ここでは、コンソールアプリを使って説明します。コンソールアプリは画面UIを作らなくても画像処理を試せるため、初心者の練習に向いています。

3-1. Visual StudioでC#プロジェクトを作成する

Visual Studioを開き、「新しいプロジェクトの作成」から「コンソールアプリ」を選択します。

プロジェクト名は、たとえばImageProcessingSampleとします。フレームワークは.NET 8以降を選ぶとよいでしょう。

作成後、Program.csにコードを書いて実行します。

コンソールアプリでは画像を画面に表示しませんが、加工後の画像ファイルを出力することで処理結果を確認できます。最初はこの方法が最もシンプルです。

3-2. NuGetで画像処理ライブラリを追加する

ImageSharpを使う場合は、NuGetからSixLabors.ImageSharpを追加します。

Visual Studioでは、プロジェクトを右クリックし、「NuGetパッケージの管理」を選択します。参照タブでSixLabors.ImageSharpを検索し、インストールします。

または、パッケージマネージャーコンソールで次のコマンドを実行します。

PowerShell
Install-Package SixLabors.ImageSharp

.NET CLIを使う場合は次の通りです。

Bash
dotnet add package SixLabors.ImageSharp

画像に文字や図形を描きたい場合は、追加でSixLabors.ImageSharp.Drawingを入れることもあります。

Bash
dotnet add package SixLabors.ImageSharp.Drawing

3-3. サンプル画像をプロジェクトに配置する

プロジェクト直下にimagesフォルダを作成し、その中にsample.jpgを配置します。

構成例は次の通りです。

ImageProcessingSample
├─ Program.cs
├─ ImageProcessingSample.csproj
└─ images
└─ sample.jpg

Visual Studioで画像ファイルを選択し、プロパティから「出力ディレクトリにコピー」を「新しい場合はコピーする」に設定しておくと、実行時に画像が見つからない問題を避けやすくなります。

3-4. 相対パス・絶対パスで画像が読めないときの確認ポイント

画像が読めない原因で最も多いのが、パスの指定ミスです。

たとえば、次のコードで読み込めない場合があります。

C#
using var image = Image.Load("images/sample.jpg");

このとき確認すべきなのは、「実行時のカレントディレクトリ」です。C#では、ソースコードがある場所ではなく、ビルド後の実行フォルダが基準になることがあります。

確認用に次のコードを実行してみましょう。

C#
Console.WriteLine(Directory.GetCurrentDirectory());

出力されたフォルダを見て、その場所からimages/sample.jpgが存在するか確認します。

確実に指定したい場合は、絶対パスを使います。

C#
var path = @"C:\Temp\sample.jpg";
using var image = Image.Load(path);

ただし、実務では環境が変わっても動くように、設定ファイルや相対パスを適切に使うのが一般的です。

4. C#で画像を読み込む基本コード

ここからは、実際にC#で画像を読み込むコードを見ていきます。まずはImageSharpを使った最小コードから始めます。

4-1. 画像ファイルを読み込む最小コード

ImageSharpで画像を読み込む最小コードは次の通りです。

C#
using SixLabors.ImageSharp;

using var image = Image.Load("images/sample.jpg");

Console.WriteLine("画像を読み込みました。");

Image.Loadに画像ファイルのパスを渡すだけで読み込めます。

using varを付けているのは、画像データがメモリを使うためです。処理が終わったら自動的に解放されるようにしています。

画像処理では、メモリ管理が意外と重要です。特に大きな画像や大量の画像を扱う場合、不要になった画像オブジェクトを解放しないとメモリ使用量が増えてしまいます。

4-2. 読み込んだ画像の幅・高さ・形式を取得する

画像を読み込んだら、幅や高さを取得できます。

C#
using SixLabors.ImageSharp;

using var image = Image.Load("images/sample.jpg");

Console.WriteLine($"幅: {image.Width}");
Console.WriteLine($"高さ: {image.Height}");

画像形式を判定したい場合は、Image.Identifyを使うと便利です。

C#
using SixLabors.ImageSharp;

var info = Image.Identify("images/sample.jpg");

if (info != null)
{
Console.WriteLine($"幅: {info.Width}");
Console.WriteLine($"高さ: {info.Height}");
Console.WriteLine($"形式: {info.Metadata.DecodedImageFormat?.Name}");
}

Identifyは画像全体を加工するのではなく、画像情報だけを取得したいときに使えます。アップロードされた画像のサイズ確認などに便利です。

4-3. PictureBoxや画面に画像を表示する

WinFormsで画像を表示する場合は、PictureBoxを使うのが一般的です。

System.Drawingを使う例は次の通りです。

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

ただし、この方法では画像ファイルがロックされることがあります。ファイルを後で上書き保存したい場合は、ストリームから読み込んでコピーする方法を使います。

C#
using var stream = new FileStream(@"C:\Temp\sample.jpg", FileMode.Open, FileAccess.Read);
using var tempImage = System.Drawing.Image.FromStream(stream);

pictureBox1.Image = new Bitmap(tempImage);

WPFの場合は、BitmapImageを使って表示します。

C#
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(@"C:\Temp\sample.jpg");
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();

imageControl.Source = bitmap;

CacheOption.OnLoadを指定すると、画像ファイルを読み込んだ後にロックを解放しやすくなります。

4-4. ファイルが存在しない・パスが違う場合のエラー対処

画像ファイルを読み込む前に、ファイルが存在するか確認しましょう。

C#
using SixLabors.ImageSharp;

var path = "images/sample.jpg";

if (!File.Exists(path))
{
Console.WriteLine($"ファイルが見つかりません: {path}");
return;
}

using var image = Image.Load(path);

Console.WriteLine("画像を読み込みました。");

例外処理を入れるなら次のようにします。

C#
using SixLabors.ImageSharp;

try
{
using var image = Image.Load("images/sample.jpg");
Console.WriteLine("画像を読み込みました。");
}
catch (FileNotFoundException)
{
Console.WriteLine("画像ファイルが見つかりません。");
}
catch (UnknownImageFormatException)
{
Console.WriteLine("対応していない画像形式です。");
}
catch (Exception ex)
{
Console.WriteLine($"エラーが発生しました: {ex.Message}");
}

初心者のうちは、エラーが出たらまずパスを確認するのが近道です。

4-5. 画像を読み込んだまま保存できないロック問題の対策

画像処理でよくあるトラブルが、読み込んだ画像ファイルを上書き保存しようとして失敗するケースです。

たとえば、System.DrawingのImage.FromFileで読み込むと、ファイルがロックされることがあります。その状態で同じファイル名に保存しようとするとエラーになります。

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

・元画像とは別名で保存する
・ストリームから読み込んでコピーする
・読み込んだ画像を解放してから保存する
・ImageSharpのようなライブラリを使い、処理後はusingで確実に破棄する

初心者には、まず「別名保存」をおすすめします。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(300, 200));

image.Save("images/sample_resized.jpg");

元画像sample.jpgを読み込み、加工後はsample_resized.jpgとして保存します。これなら上書きによるトラブルを避けやすくなります。

5. C#でよく使う画像加工を実践コードで解説

ここからは、C#画像処理でよく使う加工を実践コードで紹介します。基本的にはImageSharpを使います。

事前に次の名前空間を追加してください。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

5-1. 画像をリサイズする

画像リサイズは、サムネイル作成やアップロード画像の軽量化でよく使います。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(400, 300));

image.Save("images/resized.jpg");

このコードでは、画像を横400px、縦300pxにリサイズしています。

縦横比を保ちたい場合は、幅だけを指定し、高さを0にします。

C#
using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(400, 0));

image.Save("images/resized_keep_ratio.jpg");

高さを0にすると、元画像の比率に合わせて自動計算されます。

5-2. 画像をトリミングする

トリミングは、画像の一部を切り抜く処理です。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Crop(new Rectangle(50, 50, 300, 200)));

image.Save("images/cropped.jpg");

Rectangle(50, 50, 300, 200)は、左上から右に50px、下に50pxの位置を起点として、横300px、縦200pxを切り抜くという意味です。

トリミング範囲が画像サイズを超えるとエラーになるため、実務では幅や高さを確認してから切り抜くと安全です。

C#
var cropWidth = Math.Min(300, image.Width);
var cropHeight = Math.Min(200, image.Height);

image.Mutate(x => x.Crop(new Rectangle(0, 0, cropWidth, cropHeight)));

5-3. 画像を回転・反転する

画像を90度回転するコードは次の通りです。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Rotate(90));

image.Save("images/rotated.jpg");

左右反転する場合は、Flipを使います。

C#
using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Flip(FlipMode.Horizontal));

image.Save("images/flipped_horizontal.jpg");

上下反転する場合は、FlipMode.Verticalを指定します。

C#
image.Mutate(x => x.Flip(FlipMode.Vertical));

スマートフォンで撮影した画像では、Exifの向き情報が関係して表示が回転して見えることがあります。その場合は、保存前に向き情報を考慮する必要があります。

5-4. 画像をグレースケール化する

グレースケール化は、カラー画像を白黒に近い画像へ変換する処理です。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Grayscale());

image.Save("images/grayscale.jpg");

画像解析の前処理や、モノクロ風の加工でよく使います。

OpenCvSharpを使う場合は、次のように書けます。

C#
using OpenCvSharp;

using var src = Cv2.ImRead("images/sample.jpg");
using var gray = new Mat();

Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);

Cv2.ImWrite("images/grayscale_opencv.jpg", gray);

画像解析をしたい場合はOpenCvSharp、通常の画像加工ならImageSharpという使い分けができます。

5-5. 明るさ・コントラストを調整する

ImageSharpでは、明るさやコントラストの調整も簡単にできます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Brightness(1.2f));

image.Save("images/brightness.jpg");

1.2fは、元画像より少し明るくする指定です。暗くしたい場合は0.8fのように1より小さい値を指定します。

コントラストを調整する場合は次のようにします。

C#
using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Contrast(1.3f));

image.Save("images/contrast.jpg");

明るさやコントラストは、値を大きくしすぎると白飛びや黒つぶれが起きるため、少しずつ調整するのがポイントです。

5-6. 画像に文字や図形を重ねる

画像に文字を重ねるには、ImageSharp.Drawingを使います。

まず、NuGetで次のパッケージを追加します。

Bash
dotnet add package SixLabors.ImageSharp.Drawing

文字を描画する例は次の通りです。

C#
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load<Rgba32>("images/sample.jpg");

var font = SystemFonts.CreateFont("Arial", 36);

image.Mutate(x => x.DrawText(
"Sample Text",
font,
Color.White,
new PointF(30, 30)
));

image.Save("images/text.jpg");

図形を描画する例です。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load<Rgba32>("images/sample.jpg");

image.Mutate(x => x.Draw(
Color.Red,
5,
new RectangleF(20, 20, 200, 100)
));

image.Save("images/rectangle.jpg");

文字入れは、ウォーターマーク、商品画像のラベル、日付の埋め込みなどでよく使います。

5-7. 複数画像を合成する

複数画像を合成するには、ベース画像に別の画像を重ねます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var baseImage = Image.Load("images/background.jpg");
using var overlay = Image.Load("images/logo.png");

baseImage.Mutate(x => x.DrawImage(
overlay,
new Point(20, 20),
0.8f
));

baseImage.Save("images/combined.jpg");

new Point(20, 20)は、重ねる画像の左上位置です。0.8fは不透明度を表します。1.0に近いほどはっきり表示され、0に近いほど透明になります。

ロゴの合成、透かし画像の追加、複数画像の結合などに応用できます。

6. 加工した画像を保存する方法

画像処理では、加工した画像を正しい形式で保存することが重要です。拡張子だけでなく、実際の保存形式も意識しましょう。

6-1. PNG・JPEG・BMPで保存する基本コード

ImageSharpでは、保存先の拡張子に応じて形式を判断できます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(400, 300));

image.Save("images/output.png");
image.Save("images/output.jpg");
image.Save("images/output.bmp");

PNGは劣化しにくく、透過にも対応しています。JPEGは写真向きでファイルサイズを小さくしやすい形式です。BMPは非圧縮に近く、ファイルサイズが大きくなりがちです。

Webで使う画像なら、写真はJPEG、ロゴや透過画像はPNGを選ぶことが多いです。

6-2. 拡張子と実際の保存形式を一致させる

画像保存では、拡張子と実際の形式を一致させることが大切です。

たとえば、ファイル名は.jpgなのに中身はPNG形式、という状態になると、別のソフトやブラウザで正しく扱えないことがあります。

ImageSharpでは、エンコーダーを指定して保存することもできます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;

using var image = Image.Load("images/sample.jpg");

image.Save("images/output.png", new PngEncoder());

JPEGで保存する場合は次のようにします。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;

using var image = Image.Load("images/sample.jpg");

image.Save("images/output.jpg", new JpegEncoder());

拡張子とエンコーダーを一致させることで、予期しない保存ミスを防げます。

6-3. JPEGの画質を指定して保存する

JPEGは画質を下げることでファイルサイズを小さくできます。Webアプリでは、アップロード画像の容量削減によく使われます。

C#
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;

using var image = Image.Load("images/sample.jpg");

var encoder = new JpegEncoder
{
Quality = 80
};

image.Save("images/output_quality80.jpg", encoder);

QualityはJPEGの画質です。一般的には70〜90程度で調整します。値を低くするとファイルサイズは小さくなりますが、画像の劣化が目立つようになります。

写真なら80前後から試すとよいでしょう。

6-4. 上書き保存と別名保存の違い

画像を保存するときは、上書き保存と別名保存の違いを理解しておきましょう。

別名保存は、元画像を残したまま加工後の画像を別ファイルとして保存する方法です。

C#
using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(300, 200));

image.Save("images/sample_resized.jpg");

上書き保存は、元画像と同じパスに保存する方法です。

C#
using var image = Image.Load("images/sample.jpg");

image.Mutate(x => x.Resize(300, 200));

image.Save("images/sample.jpg");

ただし、読み込み中のファイルをそのまま上書きすると、ロックやアクセス権限の問題が起きることがあります。

安全に上書きしたい場合は、一度別ファイルに保存してから置き換える方法があります。

C#
var inputPath = "images/sample.jpg";
var tempPath = "images/sample_temp.jpg";

using (var image = Image.Load(inputPath))
{
image.Mutate(x => x.Resize(300, 200));
image.Save(tempPath);
}

File.Delete(inputPath);
File.Move(tempPath, inputPath);

実務では、元画像をバックアップするか、別名保存する設計にしておくと安心です。

6-5. 保存時に発生しやすいアクセス権限エラーの対処

画像保存時にエラーが出る場合、原因として多いのは次のようなものです。

・保存先フォルダが存在しない
・保存先に書き込み権限がない
・同じファイルが別プロセスで開かれている
・読み込んだ画像ファイルがロックされたままになっている
・ファイル名に使用できない文字が含まれている

保存前にフォルダの存在を確認し、なければ作成するコードを書いておくと安全です。

C#
var outputDir = "output";

if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}

using var image = Image.Load("images/sample.jpg");

image.Save(Path.Combine(outputDir, "result.jpg"));

ファイル名を安全にするには、使用できない文字を除去します。

C#
var fileName = "sample:result?.jpg";

foreach (var c in Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}

Console.WriteLine(fileName);

Webアプリでは、ユーザーがアップロードしたファイル名をそのまま保存せず、GUIDなどで新しいファイル名を作るのが安全です。

C#
var fileName = $"{Guid.NewGuid()}.jpg";
var outputPath = Path.Combine("uploads", fileName);

これにより、同名ファイルの上書きや不正なファイル名によるエラーを防げます。

まとめ

C#画像処理は、最初に「読み込み・加工・保存」の流れを理解すると一気にわかりやすくなります。

初心者がまず押さえるべきポイントは、画像ファイルの形式とプログラム上の型は別物であること、アプリの種類によって画像の表示方法が変わること、そしてライブラリ選びが重要であることです。

これからC#画像処理を始めるなら、基本的なリサイズ、トリミング、回転、グレースケール化、保存処理はImageSharpで学ぶのがおすすめです。画像解析やコンピュータビジョンに進みたい場合はOpenCvSharp、描画や高速な2Dグラフィックス処理を重視する場合はSkiaSharpを検討するとよいでしょう。

まずはサンプル画像を1枚用意し、読み込み、リサイズ、保存までを実行してみてください。その基本が理解できれば、文字入れ、合成、Webアプリでの画像アップロード処理、画像解析などへ自然にステップアップできます。