この記事では、BitmapDecoder および BitmapEncoder を使用してイメージ ファイルを読み込み、保存する方法と、SoftwareBitmap オブジェクトを使用してビットマップ イメージを表現する方法について説明します。
SoftwareBitmap クラスは、画像ファイル、WriteableBitmap オブジェクト、Direct3D サーフェス、コードなど、複数のソースから作成できる汎用 API です。 SoftwareBitmap を使用すると、さまざまなピクセル形式とアルファ モード間で簡単に変換でき、ピクセル データへの低レベルのアクセスが可能になります。 また、SoftwareBitmap は、次のようなWindowsの複数の機能で使用される一般的なインターフェイスです。
CapturedFrame では、カメラによってキャプチャされたフレームを SoftwareBitmap として取得できます。
VideoFrame を使用すると、VideoFrame を SoftwareBitmap として取得できます。
FaceDetector では、SoftwareBitmap で顔を検出できます。
この記事のサンプル コードでは、次の名前空間の API を使用します。
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.Graphics.Imaging;
using Microsoft.UI.Xaml.Media.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;
BitmapDecoder を使用してイメージ ファイルから SoftwareBitmap を作成する
ファイルから SoftwareBitmap を作成するには、イメージ データを含む StorageFile のインスタンスを取得します。 この例では、FileOpenPicker を使用して、ユーザーがイメージ ファイルを選択できるようにします。
private async Task<StorageFile?> PickInputFileAsync()
{
var picker = new FileOpenPicker();
// Initialize the picker with the window handle (required for WinUI 3).
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".bmp");
return await picker.PickSingleFileAsync();
}
StorageFile オブジェクトの OpenAsync メソッドを呼び出して、イメージ データを含むランダム アクセス ストリームを取得します。 静的メソッド BitmapDecoder.CreateAsync を呼び出して、指定されたストリームの BitmapDecoder クラスのインスタンスを取得します。 GetSoftwareBitmapAsync を呼び出して、イメージを含む SoftwareBitmap オブジェクトを取得します。
private async Task<SoftwareBitmap> CreateSoftwareBitmapFromFileAsync(StorageFile file)
{
using IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
// Create a decoder from the image file.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
// Get the SoftwareBitmap representation of the file.
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
return softwareBitmap;
}
BitmapEncoder を使用して SoftwareBitmap をファイルに保存する
SoftwareBitmap をファイルに保存するには、イメージを保存する StorageFile のインスタンスを取得します。 この例では、FileSavePicker を使用して、ユーザーが出力ファイルを選択できるようにします。
private async Task<StorageFile?> PickOutputFileAsync()
{
var picker = new FileSavePicker();
// Initialize the picker with the window handle (required for WinUI 3).
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.SuggestedFileName = "output";
picker.FileTypeChoices.Add("JPEG Image", new List<string> { ".jpg" });
picker.FileTypeChoices.Add("PNG Image", new List<string> { ".png" });
return await picker.PickSaveFileAsync();
}
StorageFile オブジェクトの OpenAsync メソッドを呼び出して、イメージの書き込み先となるランダム アクセス ストリームを取得します。 静的メソッド BitmapEncoder.CreateAsync を呼び出して、指定されたストリームの BitmapEncoder クラスのインスタンスを取得します。 CreateAsync の最初のパラメーターは、イメージのエンコードに使用するコーデックを表す GUID です。 BitmapEncoder クラスは、 JpegEncoderId など、エンコーダーでサポートされている各コーデックの ID を含むプロパティを公開します。
SetSoftwareBitmap メソッドを使用して、エンコードされるイメージを設定します。 BitmapTransform プロパティの値を設定して、エンコード中にイメージに基本的な変換を適用できます。 IsThumbnailGenerated プロパティは、エンコーダーによってサムネイルが生成されるかどうかを決定します。 すべてのファイル形式でサムネイルがサポートされているわけではないため、この機能を使用する場合は、サムネイルがサポートされていない場合にスローされるサポートされていない操作エラーをキャッチする必要があります。
FlushAsync を呼び出して、エンコーダーが指定したファイルにイメージ データを書き込みます。
private async Task SaveSoftwareBitmapToFileAsync(SoftwareBitmap softwareBitmap, StorageFile outputFile)
{
using IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create an encoder with the desired format.
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
// Set the software bitmap.
encoder.SetSoftwareBitmap(softwareBitmap);
// Set additional encoding parameters (optional).
encoder.BitmapTransform.ScaledWidth = (uint)softwareBitmap.PixelWidth;
encoder.BitmapTransform.ScaledHeight = (uint)softwareBitmap.PixelHeight;
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.IsThumbnailGenerated = true;
try
{
await encoder.FlushAsync();
}
catch (Exception ex)
{
const int WINCODEC_ERR_UNSUPPORTEDOPERATION = unchecked((int)0x88982F81);
switch (ex.HResult)
{
case WINCODEC_ERR_UNSUPPORTEDOPERATION:
// If the encoder does not support thumbnail generation,
// disable it and try again.
encoder.IsThumbnailGenerated = false;
break;
default:
throw;
}
}
if (!encoder.IsThumbnailGenerated)
{
await encoder.FlushAsync();
}
}
新しい BitmapPropertySet オブジェクトを作成し、エンコーダーの設定を表す 1 つ以上の BitmapTypedValue オブジェクトをそれに格納することで、BitmapEncoder の作成時に追加のエンコード オプションを指定できます。 サポートされているエンコーダー オプションの一覧については、「 BitmapEncoder オプションリファレンス」を参照してください。
private async Task SaveWithEncodingOptionsAsync(SoftwareBitmap softwareBitmap, StorageFile outputFile)
{
using IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create encoding options with a specific image quality.
var propertySet = new BitmapPropertySet();
var qualityValue = new BitmapTypedValue(0.9, Windows.Foundation.PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
// Create the encoder with the encoding options.
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId, stream, propertySet);
encoder.SetSoftwareBitmap(softwareBitmap);
await encoder.FlushAsync();
}
XAML イメージ コントロールで SoftwareBitmap を使用する
イメージ コントロールを使用して XAML ページ内に 画像 を表示するには、まず XAML ページで Image コントロールを定義します。
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
現時点では、 Image コントロールでは、BGRA8 エンコードと事前乗算またはアルファ チャネルを使用しないイメージのみがサポートされています。 画像を表示する前に、正しい形式であることをテストし、正しくない場合は SoftwareBitmap static Convert メソッドを使用して、イメージをサポートされている形式に変換します。
新しい SoftwareBitmapSource オブジェクトを作成します。 ソース オブジェクトの内容を設定するには、 SetBitmapAsync を呼び出し、 SoftwareBitmap を渡します。 その後、Image コントロールの Source プロパティを、新しく作成した SoftwareBitmapSource に設定できます。
private async Task DisplaySoftwareBitmapAsync(SoftwareBitmap softwareBitmap)
{
// SoftwareBitmap must be Bgra8 with premultiplied or no alpha
// to display in a XAML Image control.
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 ||
softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
softwareBitmap = SoftwareBitmap.Convert(
softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
// In WinUI 3, SoftwareBitmapSource is in Microsoft.UI.Xaml.Media.Imaging.
var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(softwareBitmap);
// Set the source of the Image control.
imageControl.Source = source;
}
SoftwareBitmapSource を使用して、SoftwareBitmap を ImageBrush の ImageSource として設定することもできます。
WriteableBitmap から SoftwareBitmap を作成する
既存の WriteableBitmap から SoftwareBitmap を作成するには、SoftwareBitmap.CreateCopyFromBuffer を呼び出し、WriteableBitmap の PixelBuffer プロパティを指定してピクセル データを設定します。 2 番目の引数では、新しく作成された SoftwareBitmap のピクセル形式を指定できます。 WriteableBitmap の PixelWidth プロパティと PixelHeight プロパティを使用して、新しいイメージのサイズを指定できます。
private SoftwareBitmap ConvertWriteableBitmapToSoftwareBitmap(WriteableBitmap writeableBitmap)
{
// Create a SoftwareBitmap from the WriteableBitmap's pixel buffer.
SoftwareBitmap softwareBitmap = SoftwareBitmap.CreateCopyFromBuffer(
writeableBitmap.PixelBuffer,
BitmapPixelFormat.Bgra8,
writeableBitmap.PixelWidth,
writeableBitmap.PixelHeight);
return softwareBitmap;
}
SoftwareBitmap をプログラムで作成または編集する
ここまで、このトピックではイメージ ファイルの操作について説明しました。 また、コードでプログラムによって新しい SoftwareBitmap を作成し、同じ手法を使用して SoftwareBitmap のピクセル データにアクセスして変更することもできます。
CopyFromBuffer メソッドを使用してバイト配列から SoftwareBitmap を設定し、CopyToBuffer を使用してピクセル データを読み取りまたは変更のためにバイト配列にコピーします。
AsBuffer 拡張メソッドを使用してバイト配列を IBuffer としてラップするには、 System.Runtime.InteropServices.WindowsRuntime 名前空間を含めます (これは、この記事の上部にある SnippetNamespaces using ステートメントに含まれています)。
目的のピクセル形式とサイズで新しい SoftwareBitmap を作成します。 ピクセル データを保持するのに十分な大きさのバイト配列を割り当て、目的の値を入力した後、 CopyFromBuffer を呼び出してデータをビットマップに書き込みます。
private SoftwareBitmap CreateGradientBitmap(int width, int height)
{
// Create a new SoftwareBitmap programmatically.
var softwareBitmap = new SoftwareBitmap(
BitmapPixelFormat.Bgra8, width, height, BitmapAlphaMode.Premultiplied);
// Allocate a byte array for the pixel data.
int bytesPerPixel = 4; // BGRA8
byte[] pixelData = new byte[width * height * bytesPerPixel];
// Fill the bitmap with a gradient pattern.
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int pixelIndex = (row * width + col) * bytesPerPixel;
// Blue channel: gradient left to right.
pixelData[pixelIndex + 0] = (byte)((double)col / width * 255);
// Green channel: gradient top to bottom.
pixelData[pixelIndex + 1] = (byte)((double)row / height * 255);
// Red channel: inverse diagonal gradient.
pixelData[pixelIndex + 2] = (byte)(255 - (((double)(col + row)
/ (width + height)) * 255));
// Alpha channel: fully opaque.
pixelData[pixelIndex + 3] = 255;
}
}
// Copy the pixel data into the SoftwareBitmap.
softwareBitmap.CopyFromBuffer(pixelData.AsBuffer());
return softwareBitmap;
}
Direct3D サーフェスから SoftwareBitmap を作成する
Direct3D サーフェスから SoftwareBitmap オブジェクトを作成するには、プロジェクトに Windows.Graphics.DirectX.Direct3D11 名前空間を含める必要があります。
using Windows.Graphics.DirectX.Direct3D11;
CreateCopyFromSurfaceAsync を呼び出して、サーフェスから新しい SoftwareBitmap を作成します。 名前が示すように、新しい SoftwareBitmap にはイメージ データの個別のコピーがあります。 SoftwareBitmap に対する変更は、Direct3D サーフェスには影響しません。
private async Task<SoftwareBitmap> CreateBitmapFromSurfaceAsync(IDirect3DSurface surface)
{
// Create a SoftwareBitmap from a Direct3D surface.
SoftwareBitmap softwareBitmap =
await SoftwareBitmap.CreateCopyFromSurfaceAsync(surface);
return softwareBitmap;
}
SoftwareBitmap を別のピクセル形式に変換する
SoftwareBitmap クラスは静的メソッド Convert を提供します。これにより、既存の SoftwareBitmap から指定したピクセル形式とアルファ モードを使用する新しい SoftwareBitmap を簡単に作成できます。 新しく作成されたビットマップには、イメージ データの個別のコピーがあることに注意してください。 新しいビットマップに対する変更は、ソース ビットマップには影響しません。
private SoftwareBitmap ConvertBitmapPixelFormat(SoftwareBitmap softwareBitmap)
{
// Convert the pixel format and alpha mode of the SoftwareBitmap.
SoftwareBitmap convertedBitmap = SoftwareBitmap.Convert(
softwareBitmap,
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied);
return convertedBitmap;
}
イメージ ファイルをトランスコードする
イメージ ファイルは、BitmapDecoder から BitmapEncoder に直接トランスコードできます。 トランスコードするファイルから IRandomAccessStream を作成します。 入力ストリームから新しい BitmapDecoder を作成します。 エンコーダーが書き込むための新しい InMemoryRandomAccessStream を作成し、インメモリ ストリームとデコーダー オブジェクトを渡して BitmapEncoder.CreateForTranscodingAsync を呼び出します。 エンコード オプションは、コード変換時にはサポートされません。代わりに 、CreateAsync を使用する必要があります。 エンコーダーで特に設定していない入力イメージ ファイル内のプロパティはすべて、変更せずに出力ファイルに書き込まれます。 FlushAsync を呼び出して、エンコーダーをメモリ内ストリームにエンコードします。 最後に、ファイル ストリームとメモリ内ストリームを先頭にシークし、 CopyAsync を呼び出してメモリ内ストリームをファイル ストリームに書き込みます。
private async Task TranscodeImageFileAsync(StorageFile inputFile, StorageFile outputFile)
{
using IRandomAccessStream inputStream =
await inputFile.OpenAsync(FileAccessMode.Read);
using IRandomAccessStream outputStream =
await outputFile.OpenAsync(FileAccessMode.ReadWrite);
// Create a decoder for the input file.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(inputStream);
// Create an encoder for transcoding to the output file.
BitmapEncoder encoder =
await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
// Optionally apply transforms during transcoding.
encoder.BitmapTransform.ScaledWidth = decoder.PixelWidth / 2;
encoder.BitmapTransform.ScaledHeight = decoder.PixelHeight / 2;
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
await encoder.FlushAsync();
}
関連トピック
Windows developer