Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье объясняется, как загрузить и сохранить файлы изображений с помощью BitmapDecoder и BitmapEncoder и как использовать объект SoftwareBitmap для представления растровых изображений.
Класс SoftwareBitmap — это универсальный API, который можно создать из нескольких источников, включая файлы изображений, объекты WriteableBitmap , поверхности Direct3D и код. 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;
Создание SoftwareBitmap из файла изображения с помощью BitmapDecoder
Чтобы создать 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();
}
Вызовите метод OpenAsync объекта StorageFile , чтобы получить поток случайного доступа, содержащий данные изображения. Вызовите статический метод 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;
}
Сохранение SoftwareBitmap в файл с помощью BitmapEncoder
Чтобы сохранить 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();
}
Вызовите метод OpenAsync объекта StorageFile , чтобы получить поток случайного доступа, в который будет записан образ. Вызовите статический метод BitmapEncoder.CreateAsync, чтобы получить экземпляр класса BitmapEncoder для указанного потока. Первый параметр CreateAsync — это GUID, представляющий кодек, который должен использоваться для кодирования изображения. Класс BitmapEncoder предоставляет свойство, содержащее идентификатор для каждого кодека, поддерживаемого кодировщиком, например JpegEncoderId.
Используйте метод 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();
}
}
Дополнительные параметры кодирования можно указать при создании BitmapEncoder, создав новый объект BitmapPropertySet и заполнив его одним или несколькими объектами BitmapTypedValue, представляющими параметры кодировщика. Список поддерживаемых параметров кодировщика см. в справочнике по параметрам 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();
}
Использование SoftwareBitmap с элементом управления изображением XAML
Чтобы отобразить изображение на странице XAML с помощью элемента управления "Изображение ", сначала определите элемент управления "Изображение " на странице XAML.
<Image x:Name="imageControl"
Grid.Row="2"
Stretch="Uniform"/>
В настоящее время элемент управления Image поддерживает только изображения с кодировкой BGRA8 и с предмультиплицированным альфа-каналом или без альфа-канала. Прежде чем пытаться отобразить изображение, протестируйте, чтобы убедиться, что он имеет правильный формат, а если нет, используйте статический метод Convert SoftwareBitmap для преобразования изображения в поддерживаемый формат.
Создайте объект SoftwareBitmapSource . Задайте содержимое объекта-источника, вызвав SetBitmapAsync и передав объект SoftwareBitmap. Затем можно задать свойство Source элемента управления Image для только что созданного 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 в качестве ImageSource для ImageBrush.
Создание SoftwareBitmap из объекта WriteableBitmap
Вы можете создать SoftwareBitmap из существующего объекта WriteableBitmap, вызвав SoftwareBitmap.CreateCopyFromBuffer и указав свойство PixelBuffer объекта WriteableBitmap, чтобы задать данные пикселей. Второй аргумент позволяет указать формат пикселей для только что созданного SoftwareBitmap. Свойства PixelWidth и PixelHeight объекта WriteableBitmap можно использовать для указания измерений нового изображения.
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;
}
Создать SoftwareBitmap из поверхности Direct3D
Чтобы создать объект SoftwareBitmap из поверхности Direct3D, необходимо включить пространство имен 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