Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird erläutert, wie Sie Bilddateien mit BitmapDecoder und BitmapEncoder laden und speichern und wie das SoftwareBitmap-Objekt zur Darstellung von Bitmapbildern verwendet wird.
Die SoftwareBitmap-Klasse ist eine vielseitige API, die aus mehreren Quellen erstellt werden kann, darunter Bilddateien, WriteableBitmap-Objekte , Direct3D-Oberflächen und Code. Mit SoftwareBitmap können Sie problemlos zwischen verschiedenen Pixelformaten und Alphamodi konvertieren und den Zugriff auf Pixeldaten auf niedriger Ebene ermöglichen. Darüber hinaus ist SoftwareBitmap eine gemeinsame Schnittstelle, die von mehreren Features von Windows verwendet wird, darunter:
mit CapturedFrame können Sie Frames abrufen, die von der Kamera als SoftwareBitmap aufgenommen werden.
mit VideoFrame können Sie eine SoftwareBitmapDarstellung eines VideoFrame abrufen.
mit FaceDetector können Sie Gesichter in einer SoftwareBitmap erkennen.
Der Beispielcode in diesem Artikel verwendet APIs aus den folgenden Namespaces.
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;
Erstellen einer SoftwareBitmap aus einer Bilddatei mit BitmapDecoder
Rufen Sie zum Erstellen eines SoftwareBitmap aus einer Datei eine Instanz von StorageFile mit den Bilddaten ab. In diesem Beispiel wird ein FileOpenPicker verwendet, damit der Benutzer eine Bilddatei auswählen kann.
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();
}
Rufen Sie die OpenAsync-Methode des StorageFile-Objekts auf, um einen Datenstrom mit wahllosem Zugriff abzurufen, der die Bilddaten enthält. Rufen Sie die statische Methode BitmapDecoder.CreateAsync auf, um eine Instanz der BitmapDecoderKlasse für den angegebenen Datenstrom abzurufen. Rufen Sie GetSoftwareBitmapAsync auf, um ein SoftwareBitmapObjekt abzurufen, das das Bild enthält.
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;
}
Speichern einer SoftwareBitmap in einer Datei mit BitmapEncoder
Um eine SoftwareBitmap in einer Datei zu speichern, rufen Sie eine Instanz von StorageFile ab, in der das Bild gespeichert wird. In diesem Beispiel wird ein FileSavePicker verwendet, damit der Benutzer eine Ausgabedatei auswählen kann.
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();
}
Rufen Sie die OpenAsync-Methode des StorageFile-Objekts auf, um einen Datenstrom mit zufälligem Zugriff abzurufen, in den das Bild geschrieben wird. Rufen Sie die statische Methode BitmapEncoder.CreateAsync auf, um eine Instanz der BitmapEncoderklasse für den angegebenen Datenstrom abzurufen. Der erste Parameter für CreateAsync ist eine GUID, die den Codec darstellt, der zum Codieren des Bilds verwendet werden soll. BitmapEncoder-Klasse macht eine Eigenschaft verfügbar, die die ID für jeden codec enthält, der vom Encoder unterstützt wird, z. B. JpegEncoderId.
Verwenden Sie die SetSoftwareBitmap-Methode , um das Bild festzulegen, das codiert wird. Sie können Werte der BitmapTransform-Eigenschaft festlegen, um grundlegende Transformationen auf das Bild anzuwenden, während es codiert wird. Die IsThumbnailGenerated-Eigenschaft bestimmt, ob eine Miniaturansicht vom Encoder generiert wird. Beachten Sie, dass nicht alle Dateiformate Miniaturansichten unterstützen. Wenn Sie dieses Feature verwenden, sollten Sie daher den Fehler beim nicht unterstützten Vorgang abfangen, der ausgelöst wird, wenn Miniaturansichten nicht unterstützt werden.
Rufen Sie FlushAsync auf, damit der Encoder die Bilddaten in die angegebene Datei schreibt.
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();
}
}
Sie können beim Erstellen des BitmapEncoder zusätzliche Codierungsoptionen angeben, indem Sie ein neues BitmapPropertySet-Objekt erstellen und es mit einem oder mehreren BitmapTypedValue-Objekten füllen, die die Encodereinstellungen darstellen. Eine Liste der unterstützten Encoderoptionen finden Sie in der Referenz zu BitmapEncoder-Optionen.
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();
}
Verwenden von SoftwareBitmap mit einem XAML-Bildsteuerelement
Wenn Sie ein Bild in einer XAML-Seite mithilfe des Bildsteuerelements anzeigen möchten, definieren Sie zuerst ein Bildsteuerelement auf Der XAML-Seite.
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
Derzeit unterstützt das Image-Steuerelement nur Bilder mit BGRA8-Kodierung und einem vormultiplizierten oder keinem Alphakanal. Bevor Sie versuchen, ein Bild anzuzeigen, testen Sie, ob es über das richtige Format verfügt, und verwenden Sie andernfalls die statische Convert-MethodeSoftwareBitmap, um das Bild in das unterstützte Format zu konvertieren.
Erstellen Sie ein neues SoftwareBitmapSource-Objekt . Legen Sie den Inhalt des Quellobjekts fest, indem Sie SetBitmapAsync aufrufen und eine SoftwareBitmap übergeben. Anschließend können Sie die Eigenschaft Source des Image-Steuerelements auf die neu erstellte SoftwareBitmapSource festlegen.
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;
}
Sie können softwareBitmapSource auch verwenden, um eine SoftwareBitmap als ImageSource für einen ImageBrush festzulegen.
Eine SoftwareBitmap aus einer WriteableBitmap erstellen
Sie können eine SoftwareBitmap aus einer vorhandenen WriteableBitmap erstellen, indem Sie SoftwareBitmap.CreateCopyFromBuffer aufrufen und die PixelBuffer-Eigenschaft der WriteableBitmap bereitstellen, um die Pixeldaten festzulegen. Mit dem zweiten Argument können Sie das Pixelformat für die neu erstellte SoftwareBitmap angeben. Mit den PixelWidth- und PixelHeight-Eigenschaften der WriteableBitmap können Sie die Abmessungen des neuen Bilds angeben.
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;
}
Programmgesteuertes Erstellen oder Bearbeiten einer SoftwareBitmap
Bisher wurde in diesem Thema die Arbeit mit Bilddateien behandelt. Sie können auch programmgesteuert eine neue SoftwareBitmap im Code erstellen und dieselbe Technik verwenden, um auf die Pixeldaten von SoftwareBitmap zuzugreifen und sie zu ändern.
Verwenden Sie die CopyFromBuffer-Methode , um eine SoftwareBitmap aus einem Bytearray aufzufüllen, und CopyToBuffer , um Pixeldaten zum Lesen oder Ändern in ein Bytearray zu kopieren. Um die Erweiterungsmethode AsBuffer zu verwenden, um ein Bytearray als IBuffer zu kapseln, schließen Sie den Namespace System.Runtime.InteropServices.WindowsRuntime ein (dieser ist in den SnippetNamespaces-using-Anweisungen zu Beginn dieses Artikels enthalten).
Erstellen Sie eine neue SoftwareBitmap mit dem gewünschten Pixelformat und der gewünschten Größe. Weisen Sie ein Bytearray groß genug zu, um die Pixeldaten zu enthalten, füllen Sie es mit den gewünschten Werten aus, und rufen Sie dann CopyFromBuffer auf, um die Daten in die Bitmap zu schreiben.
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;
}
Erstellen einer SoftwareBitmap auf einer Direct3D-Oberfläche
Um ein SoftwareBitmap-Objekt aus einer Direct3D-Oberfläche zu erstellen, müssen Sie den Windows.Graphics.DirectX.Direct3D11-Namespace in Ihr Projekt einbinden.
using Windows.Graphics.DirectX.Direct3D11;
Rufen Sie CreateCopyFromSurfaceAsync auf, um eine neue SoftwareBitmap aus der Oberfläche zu erstellen. Wie der Name angibt, verfügt die neue SoftwareBitmap über eine separate Kopie der Bilddaten. Änderungen an der SoftwareBitmap wirken sich nicht auf die Direct3D-Oberfläche aus.
private async Task<SoftwareBitmap> CreateBitmapFromSurfaceAsync(IDirect3DSurface surface)
{
// Create a SoftwareBitmap from a Direct3D surface.
SoftwareBitmap softwareBitmap =
await SoftwareBitmap.CreateCopyFromSurfaceAsync(surface);
return softwareBitmap;
}
Konvertieren einer SoftwareBitmap in ein anderes Pixelformat
Die SoftwareBitmap-Klasse stellt die statische Methode Convert bereit, mit der Sie problemlos eine neue SoftwareBitmap erstellen können, die das pixelformat und den Alphamodus verwendet, den Sie aus einer vorhandenen SoftwareBitmap angeben. Beachten Sie, dass die neu erstellte Bitmap über eine separate Kopie der Bilddaten verfügt. Änderungen an der neuen Bitmap wirken sich nicht auf die Quellbitmap aus.
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;
}
Transcodieren einer Bilddatei
Sie können eine Bilddatei direkt von einer BitmapDecoder in eine BitmapEncoder transcodieren. Erstellen Sie aus der zu transcodierenden Datei einen IRandomAccessStream. Erstellen Sie einen neuen BitmapDecoder aus dem Eingabedatenstrom. Erstellen Sie einen neuen InMemoryRandomAccessStream, in den der Encoder schreibt, und rufen Sie BitmapEncoder.CreateForTranscodingAsync auf, wobei Sie den In-Memory-Datenstrom und das Decoderobjekt übergeben. Kodierungsoptionen werden beim Transcodieren nicht unterstützt; stattdessen sollten Sie CreateAsync verwenden. Alle Eigenschaften in der Eingabebilddatei, die Sie nicht speziell für den Encoder festlegen, werden unverändert in die Ausgabedatei geschrieben. Rufen Sie FlushAsync auf, um den Encoder zum Codieren in den In-Memory-Stream zu veranlassen. Setzen Sie schließlich den Dateistream und den In-Memory-Datenstrom an den Anfang zurück und rufen Sie CopyAsync auf, um den In-Memory-Datenstrom in den Dateistream zu schreiben.
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();
}
Zugehörige Themen
Windows developer