Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här artikeln beskrivs hur du läser in och sparar bildfiler med hjälp av BitmapDecoder och BitmapEncode och hur du använder objektet SoftwareBitmap för att representera bitmappsbilder.
Klassen SoftwareBitmap är ett mångsidigt API som kan skapas från flera källor, inklusive bildfiler, WriteableBitmap-objekt, Direct3D-ytor och kod. Med SoftwareBitmap kan du enkelt konvertera mellan olika pixelformat och alfalägen och ge åtkomst på låg nivå till pixeldata. Dessutom är SoftwareBitmap ett vanligt gränssnitt som används av flera funktioner i Windows, inklusive:
Med CapturedFrame kan du hämta bildrutor som kameran har tagit som SoftwareBitmap.
VideoFrame kan du få en SoftwareBitmap representation av en VideoFrame.
Med FaceDetector kan du upptäcka ansikten i en SoftwareBitmap.
Exempelkoden i den här artikeln använder API:er från följande namnområden.
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;
Skapa en SoftwareBitmap från en bildfil med BitmapDecoder
Om du vill skapa en SoftwareBitmap från en fil hämtar du en instans av StorageFile som innehåller bilddata. I det här exemplet används en FileOpenPicker så att användaren kan välja en bildfil.
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();
}
Anropa OpenAsync-metoden för StorageFile-objektet för att hämta en slumpmässig åtkomstström som innehåller bilddata. Anropa den statiska metoden BitmapDecoder.CreateAsync för att hämta en instans av klassen BitmapDecoder för den angivna strömmen. Anropa GetSoftwareBitmapAsync för att hämta ett SoftwareBitmap objekt som innehåller bilden.
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;
}
Spara en SoftwareBitmap till en fil med BitmapEncoder
Om du vill spara en SoftwareBitmap i en fil hämtar du en instans av StorageFile som avbildningen ska sparas till. I det här exemplet används en FileSavePicker så att användaren kan välja en utdatafil.
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();
}
Anropa OpenAsync-metoden för StorageFile-objektet för att hämta en slumpmässig åtkomstström som avbildningen ska skrivas till. Anropa den statiska metoden BitmapEncoder.CreateAsync för att hämta en instans av klassen BitmapEncoder för den angivna strömmen. Den första parametern för CreateAsync är ett GUID som representerar den codec som ska användas för att koda avbildningen. BitmapEncoder-klassen exponerar en egenskap som innehåller ID:t för varje codec som stöds av kodaren, till exempel JpegEncoderId.
Använd metoden SetSoftwareBitmap för att ange den avbildning som ska kodas. Du kan ange värden för egenskapen BitmapTransform för att tillämpa grundläggande transformeringar på bilden medan den kodas. Egenskapen IsThumbnailGenerated avgör om en miniatyrbild genereras av kodaren. Observera att inte alla filformat har stöd för miniatyrbilder, så om du använder den här funktionen bör du fånga upp det åtgärdsfel som inte stöds om miniatyrbilder inte stöds.
Anropa FlushAsync för att få kodaren att skriva bilddata till den angivna filen.
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();
}
}
Du kan ange ytterligare kodningsalternativ när du skapar
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();
}
Använda SoftwareBitmap med en XAML-avbildningskontroll
Om du vill visa en bild på en XAML-sida med hjälp av bildkontrollen definierar du först en bildkontroll på XAML-sidan.
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
För närvarande stöder kontrollen Image endast bilder som använder BGRA8-kodning och en premultiplicerad alfakanal eller ingen alfakanal. Innan du försöker visa en bild testar du för att kontrollera att den har rätt format, och om inte använder du metoden SoftwareBitmap static Convert för att konvertera bilden till formatet som stöds.
Skapa ett nytt SoftwareBitmapSource-objekt . Ange innehållet i källobjektet genom att anropa SetBitmapAsync och skicka in en SoftwareBitmap. Sedan kan du ange källegenskapen för avbildningskontrollen till den nyligen skapade 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;
}
Du kan också använda SoftwareBitmapSource för att ange en SoftwareBitmap som ImageSource för en ImageBrush.
Skapa en SoftwareBitmap från en WriteableBitmap
Du kan skapa en SoftwareBitmap från en befintlig WriteableBitmap genom att anropa SoftwareBitmap.CreateCopyFromBuffer och ange egenskapen PixelBuffer för WriteableBitmap för att ange pixeldata. Med det andra argumentet kan du ange pixelformatet för den nyligen skapade SoftwareBitmap. Du kan använda egenskaperna PixelWidth och PixelHeight för WriteableBitmap för att ange dimensionerna för den nya bilden.
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;
}
Skapa eller redigera en SoftwareBitmap programmatiskt
Hittills har det här avsnittet tagit upp arbetet med bildfiler. Du kan också skapa en ny SoftwareBitmap programmatiskt i kod och använda samma teknik för att komma åt och ändra SoftwareBitmaps pixeldata.
Använd metoden CopyFromBuffer för att fylla i en SoftwareBitmap från en bytematris och CopyToBuffer för att kopiera pixeldata till en bytematris för läsning eller ändring. Om du vill använda tilläggsmetoden AsBuffer för att omsluta en bytematris som en IBuffer, inkludera namnområdet System.Runtime.InteropServices.WindowsRuntime (detta ingår i SnippetNamespaces med hjälp av instruktioner överst i den här artikeln).
Skapa en ny SoftwareBitmap med det pixelformat och den storlek du vill använda. Allokera en bytematris som är tillräckligt stor för att lagra pixeldata, fylla den med önskade värden och anropa sedan CopyFromBuffer för att skriva data i bitmappen.
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;
}
Skapa en SoftwareBitmap från en Direct3D-yta
Om du vill skapa ett SoftwareBitmap-objekt från en Direct3D-yta måste du inkludera Windows. Graphics.DirectX.Direct3D11 namnområde i projektet.
using Windows.Graphics.DirectX.Direct3D11;
Anropa CreateCopyFromSurfaceAsync för att skapa en ny SoftwareBitmap från ytan. Som namnet anger har den nya SoftwareBitmap en separat kopia av bilddata. Ändringar av SoftwareBitmap påverkar inte Direct3D-ytan.
private async Task<SoftwareBitmap> CreateBitmapFromSurfaceAsync(IDirect3DSurface surface)
{
// Create a SoftwareBitmap from a Direct3D surface.
SoftwareBitmap softwareBitmap =
await SoftwareBitmap.CreateCopyFromSurfaceAsync(surface);
return softwareBitmap;
}
Konvertera en SoftwareBitmap till ett annat pixelformat
Klassen SoftwareBitmap innehåller den statiska metoden Konvertera som gör att du enkelt kan skapa en ny SoftwareBitmap som använder pixelformatet och alfaläget som du anger från en befintlig SoftwareBitmap. Observera att den nyligen skapade bitmappen har en separat kopia av bilddata. Ändringar i den nya bitmappen påverkar inte källbitmappen.
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;
}
Omkoda en bildfil
Du kan omkoda en bildfil direkt från en BitmapDecoder till en BitmapEncoder. Skapa en IRandomAccessStream från filen som ska omkodas. Skapa en ny BitmapDecoder från indataströmmen. Skapa en ny InMemoryRandomAccessStream för kodaren att skriva till och anropa BitmapEncoder.CreateForTranscodingAsync, skicka in minnesintern ström och avkodarobjektet. Kodningsalternativ stöds inte vid omkodning. i stället bör du använda CreateAsync. Alla egenskaper i indatabildfilen som du inte specifikt anger på kodaren skrivs till utdatafilen oförändrad. Anropa FlushAsync för att få kodaren att koda till den minnesinterna strömmen. Slutligen söker du upp filströmmen och den minnesinterna strömmen till början och anropar CopyAsync för att skriva ut den minnesinterna strömmen till filströmmen.
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();
}
Relaterade ämnen
Windows developer