Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article explique comment charger et enregistrer des fichiers image à l’aide de BitmapDecoder et BitmapEncoder et comment utiliser l’objet SoftwareBitmap pour représenter des images bitmap.
La classe SoftwareBitmap est une API polyvalente qui peut être créée à partir de plusieurs sources, notamment des fichiers image, des objets WriteableBitmap , des surfaces Direct3D et du code. SoftwareBitmap vous permet de convertir facilement entre différents formats de pixels et modes alpha, et permet un accès de bas niveau aux données de pixels. En outre, SoftwareBitmap est une interface courante utilisée par plusieurs fonctionnalités de Windows, notamment :
CapturedFrame vous permet d’obtenir des images capturées par l’appareil photo en tant que SoftwareBitmap.
VideoFrame vous permet d’obtenir une représentation SoftwareBitmap d’une représentation VideoFrame.
FaceDetector vous permet de détecter des visages dans un SoftwareBitmap.
L’exemple de code de cet article utilise des API à partir des espaces de noms suivants.
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;
Créer un SoftwareBitmap à partir d’un fichier image avec BitmapDecoder
Pour créer un SoftwareBitmap à partir d’un fichier, obtenez une instance de StorageFile contenant les données d’image. Cet exemple utilise un FileOpenPicker pour permettre à l’utilisateur de sélectionner un fichier image.
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();
}
Appelez la méthode OpenAsync de l’objet StorageFile pour obtenir un flux d’accès aléatoire contenant les données d’image. Appelez la méthode statique BitmapDecoder.CreateAsync pour obtenir une instance de la classe BitmapDecoder pour le flux spécifié. Appelez GetSoftwareBitmapAsync pour obtenir un objet SoftwareBitmap contenant l’image.
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;
}
Enregistrer un SoftwareBitmap dans un fichier avec BitmapEncoder
Pour enregistrer un SoftwareBitmap dans un fichier, obtenez une instance de StorageFile dans laquelle l’image sera enregistrée. Cet exemple utilise un FileSavePicker pour permettre à l’utilisateur de sélectionner un fichier de sortie.
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();
}
Appelez la méthode OpenAsync de l’objet StorageFile pour obtenir un flux d’accès aléatoire auquel l’image sera écrite. Appelez la méthode statique BitmapEncoder.CreateAsync pour obtenir une instance de la classe BitmapEncoder pour le flux spécifié. Le premier paramètre de CreateAsync est un GUID représentant le codec qui doit être utilisé pour encoder l’image. La classe BitmapEncoder expose une propriété contenant l’ID de chaque codec pris en charge par l’encodeur, tel que JpegEncoderId.
Utilisez la méthode SetSoftwareBitmap pour définir l’image qui sera encodée. Vous pouvez définir des valeurs de la propriété BitmapTransform pour appliquer des transformations de base à l’image pendant son encodage. La propriété IsThumbnailGenerated détermine si une miniature est générée par l’encodeur. Notez que tous les formats de fichier ne prennent pas en charge les miniatures. Par conséquent, si vous utilisez cette fonctionnalité, vous devez intercepter l’erreur d’opération non prise en charge qui sera levée si les miniatures ne sont pas prises en charge.
Appelez FlushAsync pour que l’encodeur écrive les données d’image dans le fichier spécifié.
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();
}
}
Vous pouvez spécifier des options d’encodage supplémentaires lorsque vous créez le
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();
}
Utiliser SoftwareBitmap avec un contrôle Image XAML
Pour afficher une image dans une page XAML à l’aide du contrôle Image , commencez par définir un contrôle Image dans votre page XAML.
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
Actuellement, le contrôle Image prend uniquement en charge les images utilisant l’encodage BGRA8 et un canal alpha prémultiplié ou aucun canal alpha. Avant d’essayer d’afficher une image, testez-la pour vous assurer qu’elle a le format correct et, si ce n’est pas le cas, utilisez la méthode SoftwareBitmap static Convert pour convertir l’image au format pris en charge.
Créez un objet SoftwareBitmapSource . Définissez le contenu de l’objet source en appelant SetBitmapAsync, en passant un SoftwareBitmap. Vous pouvez ensuite définir la propriété Source du contrôle Image sur le logiciel SoftwareBitmapSource nouvellement créé.
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;
}
Vous pouvez également utiliser SoftwareBitmapSource pour définir un SoftwareBitmap comme ImageSource pour un ImageBrush.
Créer un SoftwareBitmap à partir d’un WriteableBitmap
Vous pouvez créer un SoftwareBitmap à partir d’un WriteableBitmap existant en appelant SoftwareBitmap.CreateCopyFromBuffer et en fournissant la propriété PixelBuffer de l’writeableBitmap pour définir les données de pixel. Le deuxième argument vous permet de spécifier le format de pixel pour le softwareBitmap nouvellement créé. Vous pouvez utiliser les propriétés PixelWidth et PixelHeight du WriteableBitmap pour spécifier les dimensions de la nouvelle image.
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;
}
Créer ou modifier un SoftwareBitmap par programmation
Jusqu’à présent, cette rubrique a abordé l’utilisation des fichiers image. Vous pouvez également créer un nouveau SoftwareBitmap par programmation dans le code et utiliser la même technique pour accéder aux données de pixels de SoftwareBitmap et les modifier.
Utilisez la méthode CopyFromBuffer pour remplir un SoftwareBitmap à partir d’un tableau d’octets et CopierToBuffer pour copier des données de pixels vers un tableau d’octets pour la lecture ou la modification. Pour utiliser la méthode d’extension AsBuffer pour encapsuler un tableau d’octets dans un IBuffer, incluez l’espace de noms System.Runtime.InteropServices.WindowsRuntime (celui-ci est inclus dans les directives SnippetNamespaces using au début de cet article).
Créez un SoftwareBitmap avec le format et la taille des pixels souhaités. Allouez un tableau d’octets suffisamment grand pour contenir les données de pixels, remplissez-les avec les valeurs souhaitées, puis appelez CopyFromBuffer pour écrire les données dans la bitmap.
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;
}
Créer un SoftwareBitmap à partir d’une surface Direct3D
Pour créer un objet SoftwareBitmap à partir d’une surface Direct3D, vous devez inclure le Windows. Graphics.DirectX.Direct3D11 espace de noms dans votre projet.
using Windows.Graphics.DirectX.Direct3D11;
Appelez CreateCopyFromSurfaceAsync pour créer un nouveau SoftwareBitmap à partir de la surface. Comme le nom l’indique, le nouveau SoftwareBitmap a une copie distincte des données d’image. Les modifications apportées à SoftwareBitmap n’ont aucun effet sur la surface Direct3D.
private async Task<SoftwareBitmap> CreateBitmapFromSurfaceAsync(IDirect3DSurface surface)
{
// Create a SoftwareBitmap from a Direct3D surface.
SoftwareBitmap softwareBitmap =
await SoftwareBitmap.CreateCopyFromSurfaceAsync(surface);
return softwareBitmap;
}
Convertir un SoftwareBitmap au format de pixel différent
La classe SoftwareBitmap fournit la méthode statique, Convert, qui vous permet de créer facilement un softwareBitmap qui utilise le format pixel et le mode alpha que vous spécifiez à partir d’un SoftwareBitmap existant. Notez que la bitmap nouvellement créée comporte une copie distincte des données d’image. Les modifications apportées à la nouvelle bitmap n’affectent pas la bitmap source.
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;
}
Transcoder un fichier image
Vous pouvez transcoder un fichier image directement à partir d’un fichier image BitmapDecoder vers un BitmapEncoder. Créez un IRandomAccessStream à partir du fichier à transcoder. Créez un BitmapDecoder à partir du flux d’entrée. Créez un nouveau InMemoryRandomAccessStream dans lequel l’encodeur pourra écrire, puis appelez BitmapEncoder.CreateForTranscodingAsync en transmettant le flux en mémoire et l’objet décodeur en arguments. Les options d’encodage ne sont pas prises en charge lors du transcodage ; Au lieu de cela, vous devez utiliser CreateAsync. Toutes les propriétés du fichier image d’entrée que vous ne définissez pas spécifiquement sur l’encodeur seront écrites dans le fichier de sortie inchangé. Appelez FlushAsync pour que l’encodeur s’encode dans le flux en mémoire. Enfin, recherchez le flux de fichiers et le flux en mémoire au début et appelez CopyAsync pour écrire le flux en mémoire dans le flux de fichiers.
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();
}
Rubriques connexes
Windows developer